Erweiterungen
This commit is contained in:
@@ -1,269 +0,0 @@
|
|||||||
# MQTT System Changelog
|
|
||||||
|
|
||||||
## Version 2.0.0 - 2025-10-22
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
#### 1. MQTT-Broker-Port geändert
|
|
||||||
- **Alt**: Port `1883`
|
|
||||||
- **Neu**: Port `42099`
|
|
||||||
- **Broker**: `mqtt-2.assecutor.de:42099`
|
|
||||||
- **Grund**: Neuer dedizierter Port für die Produktionsumgebung
|
|
||||||
|
|
||||||
#### 2. Konfigurationssystem umgestellt
|
|
||||||
Die alte `app.mqtt.*` Konfiguration wurde durch das neue Plugin-System ersetzt.
|
|
||||||
|
|
||||||
**Entfernte Konfiguration:**
|
|
||||||
```properties
|
|
||||||
app.mqtt.enabled=true
|
|
||||||
app.mqtt.broker-uri=mqtt://mqtt-2.assecutor.de
|
|
||||||
app.mqtt.client-id=server-${random.uuid}
|
|
||||||
app.mqtt.clean-start=false
|
|
||||||
app.mqtt.session-expiry-interval=86400
|
|
||||||
app.mqtt.keep-alive=30
|
|
||||||
app.mqtt.max-inflight=50
|
|
||||||
app.mqtt.automatic-reconnect=true
|
|
||||||
app.mqtt.default-qos=2
|
|
||||||
app.mqtt.default-retained=false
|
|
||||||
```
|
|
||||||
|
|
||||||
**Neue Konfiguration:**
|
|
||||||
```properties
|
|
||||||
# Messaging Plugin Configuration
|
|
||||||
app.messaging.plugin.type=mqtt
|
|
||||||
app.messaging.plugin.mqtt.broker.host=mqtt-2.assecutor.de
|
|
||||||
app.messaging.plugin.mqtt.broker.port=42099
|
|
||||||
app.messaging.plugin.mqtt.username=app
|
|
||||||
app.messaging.plugin.mqtt.password=apppwd
|
|
||||||
app.messaging.plugin.mqtt.client.id=votianlt-server
|
|
||||||
```
|
|
||||||
|
|
||||||
### Neue Features
|
|
||||||
|
|
||||||
#### 1. Plugin-basiertes Messaging-System
|
|
||||||
- Abstraktionsschicht für verschiedene Messaging-Protokolle
|
|
||||||
- Einfacher Wechsel zwischen MQTT, WebSocket, gRPC möglich
|
|
||||||
- Einheitliche API für alle Messaging-Backends
|
|
||||||
|
|
||||||
**Hauptkomponenten:**
|
|
||||||
- `MessagingPlugin` Interface
|
|
||||||
- `MqttMessagingPlugin` Implementierung
|
|
||||||
- `PluginManager` für Plugin-Verwaltung
|
|
||||||
- `PluginMessagingConfig` für Konfiguration
|
|
||||||
|
|
||||||
#### 2. Message Envelope System
|
|
||||||
Alle Nachrichten werden jetzt in Envelopes verpackt:
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class MessageEnvelope {
|
|
||||||
private String messageId; // UUID
|
|
||||||
private Instant timestamp; // Zeitstempel
|
|
||||||
private String topic; // MQTT-Topic
|
|
||||||
private Object payload; // Eigentliche Nachricht
|
|
||||||
private boolean requiresAck; // ACK erforderlich?
|
|
||||||
private int retryCount; // Anzahl Wiederholungen
|
|
||||||
private Instant expiresAt; // Ablaufzeitpunkt
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3. Acknowledgment-System
|
|
||||||
- Automatische ACK-Verwaltung
|
|
||||||
- Retry-Mechanismus bei fehlenden ACKs
|
|
||||||
- Konfigurierbare Timeouts und Wiederholungen
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class AcknowledgmentMessage {
|
|
||||||
private String messageId;
|
|
||||||
private Instant timestamp;
|
|
||||||
private String status; // SUCCESS oder FAILED
|
|
||||||
private String errorMessage;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4. Verbesserte Fehlerbehandlung
|
|
||||||
- Erhöhter Connection-Timeout: 30s → 60s
|
|
||||||
- Detaillierte Fehlerdiagnose:
|
|
||||||
- `TimeoutException`: Broker nicht erreichbar
|
|
||||||
- `UnknownHostException`: DNS-Fehler
|
|
||||||
- `ConnectException`: Port blockiert
|
|
||||||
- Automatische Wiederverbindung mit exponentieller Backoff
|
|
||||||
|
|
||||||
#### 5. Konfigurierbare Timeouts
|
|
||||||
Neue Konfigurationsoptionen:
|
|
||||||
```properties
|
|
||||||
app.messaging.plugin.mqtt.connection.timeout.seconds=60
|
|
||||||
app.messaging.plugin.mqtt.keep.alive.seconds=60
|
|
||||||
```
|
|
||||||
|
|
||||||
### Entfernte Komponenten
|
|
||||||
|
|
||||||
#### Gelöschte Klassen:
|
|
||||||
1. `MqttProperties.java` - Ersetzt durch Plugin-Konfiguration
|
|
||||||
2. `MqttConfig.java` - Nicht mehr benötigt
|
|
||||||
|
|
||||||
#### Grund für Entfernung:
|
|
||||||
Diese Klassen wurden durch das neue Plugin-System obsolet und waren nicht mehr in Verwendung.
|
|
||||||
|
|
||||||
### Geänderte Komponenten
|
|
||||||
|
|
||||||
#### 1. MqttMessagingPlugin
|
|
||||||
**Datei**: `src/main/java/de/assecutor/votianlt/messaging/plugin/mqtt/MqttMessagingPlugin.java`
|
|
||||||
|
|
||||||
**Änderungen:**
|
|
||||||
- Connection-Timeout von 30s auf 60s erhöht
|
|
||||||
- Konfigurierbare Timeout-Parameter hinzugefügt
|
|
||||||
- Verbesserte Fehlerbehandlung mit spezifischen Exception-Checks
|
|
||||||
- Detailliertes Logging für Verbindungsprobleme
|
|
||||||
|
|
||||||
```java
|
|
||||||
// Neu: Konfigurierbare Timeouts
|
|
||||||
private static final String CONFIG_CONNECTION_TIMEOUT = "connection.timeout.seconds";
|
|
||||||
private static final String CONFIG_KEEP_ALIVE = "keep.alive.seconds";
|
|
||||||
|
|
||||||
// Verbesserte Fehlerbehandlung
|
|
||||||
if (throwable instanceof java.util.concurrent.TimeoutException) {
|
|
||||||
log.error("[MqttPlugin] Connection timeout - broker may be unreachable");
|
|
||||||
} else if (throwable.getCause() instanceof java.net.UnknownHostException) {
|
|
||||||
log.error("[MqttPlugin] Unknown host - DNS resolution failed");
|
|
||||||
} else if (throwable.getCause() instanceof java.net.ConnectException) {
|
|
||||||
log.error("[MqttPlugin] Connection refused - broker may be down");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. PluginMessagingConfig
|
|
||||||
**Datei**: `src/main/java/de/assecutor/votianlt/messaging/config/PluginMessagingConfig.java`
|
|
||||||
|
|
||||||
**Änderungen:**
|
|
||||||
- Verwendet neue Konfigurationsparameter
|
|
||||||
- Initialisiert Plugin mit korrektem Port (42099)
|
|
||||||
- Setzt Authentifizierung (username/password)
|
|
||||||
|
|
||||||
#### 3. application.properties
|
|
||||||
**Datei**: `src/main/resources/application.properties`
|
|
||||||
|
|
||||||
**Änderungen:**
|
|
||||||
- Alte `app.mqtt.*` Konfiguration entfernt (Zeilen 57-71)
|
|
||||||
- Neue `app.messaging.plugin.mqtt.*` Konfiguration verwendet
|
|
||||||
- Port auf 42099 aktualisiert
|
|
||||||
|
|
||||||
### Architektur-Änderungen
|
|
||||||
|
|
||||||
#### Neue Architektur-Schichten:
|
|
||||||
|
|
||||||
```
|
|
||||||
Application Layer (Services, Controllers)
|
|
||||||
↓
|
|
||||||
MessageDeliveryService (Envelope-Wrapping, Queue-Management)
|
|
||||||
↓
|
|
||||||
PluginManager (Plugin-Verwaltung)
|
|
||||||
↓
|
|
||||||
MessagingPlugin Interface (Protokoll-Abstraktion)
|
|
||||||
↓
|
|
||||||
MqttMessagingPlugin (MQTT-spezifische Implementierung)
|
|
||||||
↓
|
|
||||||
HiveMQ MQTT Client
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Vorteile der neuen Architektur:
|
|
||||||
1. **Protokoll-Unabhängigkeit**: Einfacher Wechsel zwischen Messaging-Backends
|
|
||||||
2. **Testbarkeit**: Mock-Plugins für Tests
|
|
||||||
3. **Wartbarkeit**: Klare Trennung der Verantwortlichkeiten
|
|
||||||
4. **Erweiterbarkeit**: Neue Protokolle einfach hinzufügbar
|
|
||||||
|
|
||||||
### Migration Guide
|
|
||||||
|
|
||||||
#### Server-Migration (bereits durchgeführt):
|
|
||||||
1. ✅ Port auf 42099 geändert
|
|
||||||
2. ✅ Alte Konfiguration entfernt
|
|
||||||
3. ✅ Neue Plugin-Konfiguration aktiviert
|
|
||||||
4. ✅ Timeout erhöht
|
|
||||||
5. ✅ Fehlerbehandlung verbessert
|
|
||||||
|
|
||||||
#### Client-Migration (erforderlich):
|
|
||||||
Siehe `MQTT_MIGRATION_GUIDE.md` für detaillierte Anweisungen.
|
|
||||||
|
|
||||||
**Wichtigste Schritte:**
|
|
||||||
1. Port auf 42099 ändern
|
|
||||||
2. Authentifizierung hinzufügen (username: `app`, password: `apppwd`)
|
|
||||||
3. Message-Envelope-Format implementieren
|
|
||||||
4. ACK-Handling implementieren
|
|
||||||
5. Timeout auf 60s erhöhen
|
|
||||||
|
|
||||||
### Kompatibilität
|
|
||||||
|
|
||||||
#### Abwärtskompatibilität:
|
|
||||||
- ✅ Topic-Struktur unverändert
|
|
||||||
- ✅ Legacy-Nachrichten werden noch unterstützt
|
|
||||||
- ⚠️ Neue Clients sollten Envelope-Format verwenden
|
|
||||||
|
|
||||||
#### Vorwärtskompatibilität:
|
|
||||||
- ✅ Neue Features sind optional
|
|
||||||
- ✅ Schrittweise Migration möglich
|
|
||||||
- ✅ Alte und neue Clients können parallel laufen
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
|
|
||||||
#### Getestete Szenarien:
|
|
||||||
1. ✅ Verbindung zum neuen Broker (mqtt-2.assecutor.de:42099)
|
|
||||||
2. ✅ Authentifizierung mit username/password
|
|
||||||
3. ✅ Subscription zu allen Topics
|
|
||||||
4. ✅ Message-Envelope-Verarbeitung
|
|
||||||
5. ✅ ACK-Handling
|
|
||||||
6. ✅ Automatische Wiederverbindung
|
|
||||||
7. ✅ Timeout-Handling
|
|
||||||
|
|
||||||
#### Test-Logs:
|
|
||||||
```
|
|
||||||
11:29:26.251 [RxComputationThreadPool-1] INFO MqttMessagingPlugin - Connected successfully
|
|
||||||
11:29:26.414 [RxComputationThreadPool-3] INFO MqttMessagingPlugin - Successfully subscribed to: /ack/server/+
|
|
||||||
11:29:26.414 [RxComputationThreadPool-4] INFO MqttMessagingPlugin - Successfully subscribed to: /server/+/task_completed
|
|
||||||
11:29:26.414 [RxComputationThreadPool-5] INFO MqttMessagingPlugin - Successfully subscribed to: /server/+/jobs/assigned
|
|
||||||
11:29:26.415 [RxComputationThreadPool-6] INFO MqttMessagingPlugin - Successfully subscribed to: /server/+/message
|
|
||||||
11:29:26.417 [RxComputationThreadPool-7] INFO MqttMessagingPlugin - Successfully subscribed to: /server/+/login
|
|
||||||
```
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
|
|
||||||
#### Verbindungsaufbau:
|
|
||||||
- **Vorher**: ~30s bis Timeout bei Fehlern
|
|
||||||
- **Nachher**: ~60s bis Timeout, aber schnellere Fehlerdiagnose
|
|
||||||
|
|
||||||
#### Nachrichtendurchsatz:
|
|
||||||
- Keine Änderung (QoS 2, exactly once)
|
|
||||||
- Envelope-Overhead: ~200 Bytes pro Nachricht
|
|
||||||
|
|
||||||
### Bekannte Probleme
|
|
||||||
|
|
||||||
#### Keine bekannten Probleme
|
|
||||||
Alle Tests erfolgreich durchgeführt.
|
|
||||||
|
|
||||||
### Nächste Schritte
|
|
||||||
|
|
||||||
1. **Client-Migration**: Mobile Apps auf neuen Port und Envelope-Format umstellen
|
|
||||||
2. **Monitoring**: Metriken für Message-Delivery-Service hinzufügen
|
|
||||||
3. **Dokumentation**: API-Dokumentation für Envelope-Format erweitern
|
|
||||||
4. **Testing**: Integration-Tests für verschiedene Fehlerszenarien
|
|
||||||
|
|
||||||
### Rollback-Plan
|
|
||||||
|
|
||||||
Falls Probleme auftreten:
|
|
||||||
|
|
||||||
1. **Port zurücksetzen**:
|
|
||||||
```properties
|
|
||||||
app.messaging.plugin.mqtt.broker.port=1883
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Alte Konfiguration wiederherstellen**:
|
|
||||||
- `MqttProperties.java` aus Git-Historie wiederherstellen
|
|
||||||
- `MqttConfig.java` aus Git-Historie wiederherstellen
|
|
||||||
- Alte `app.mqtt.*` Konfiguration in `application.properties` einfügen
|
|
||||||
|
|
||||||
3. **Server neu starten**
|
|
||||||
|
|
||||||
### Kontakt
|
|
||||||
|
|
||||||
Bei Fragen oder Problemen:
|
|
||||||
- Siehe `MQTT_MIGRATION_GUIDE.md` für Client-Migration
|
|
||||||
- Siehe `MESSAGING_LAYER.md` für Architektur-Details
|
|
||||||
- Siehe `CLAUDE.md` für allgemeine System-Dokumentation
|
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
This is free and unencumbered software released into the public domain.
|
|
||||||
|
|
||||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
|
|
||||||
|
|
||||||
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
For more information, please refer to http://unlicense.org
|
|
||||||
@@ -1,318 +0,0 @@
|
|||||||
# Message Delivery Layer - Implementierungsdokumentation
|
|
||||||
|
|
||||||
## Übersicht
|
|
||||||
|
|
||||||
Der **Message Delivery Layer** ist eine neue Abstraktionsschicht zwischen der Anwendungslogik und dem MQTT-Transport. Er bietet:
|
|
||||||
|
|
||||||
- ✅ **Zuverlässige Nachrichtenzustellung** mit Bestätigungsmechanismus
|
|
||||||
- ✅ **Automatische Wiederholungsversuche** bei fehlgeschlagenen Zustellungen
|
|
||||||
- ✅ **Protokoll-Abstraktion** für einfachen Austausch von MQTT gegen andere Transporte
|
|
||||||
- ✅ **Vollständiges Audit-Log** aller Nachrichten
|
|
||||||
- ✅ **Queue-basiertes Design** für Skalierbarkeit
|
|
||||||
|
|
||||||
## Architektur
|
|
||||||
|
|
||||||
```
|
|
||||||
Application Layer (MessageController, Services)
|
|
||||||
↓
|
|
||||||
MessageDeliveryService (Envelope-Wrapping, Queue-Management)
|
|
||||||
↓
|
|
||||||
MessagingTransport Interface (Protokoll-Abstraktion)
|
|
||||||
↓
|
|
||||||
MqttTransportAdapter (MQTT-spezifische Implementierung)
|
|
||||||
↓
|
|
||||||
MqttV5ClientManager (HiveMQ Client)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Komponenten
|
|
||||||
|
|
||||||
### 1. Datenmodelle (`messaging/model/`)
|
|
||||||
|
|
||||||
#### MessageEnvelope
|
|
||||||
Wrapper für alle Nachrichten mit Metadaten:
|
|
||||||
- `messageId`: Eindeutige UUID
|
|
||||||
- `timestamp`: Erstellungszeitpunkt
|
|
||||||
- `topic`: Ziel-Topic
|
|
||||||
- `payload`: Ursprüngliche Nachricht
|
|
||||||
- `requiresAck`: Bestätigung erforderlich?
|
|
||||||
- `retryCount`: Anzahl Wiederholungsversuche
|
|
||||||
- `expiresAt`: Ablaufzeitpunkt
|
|
||||||
|
|
||||||
#### PendingDelivery
|
|
||||||
Tracking-Objekt für ausstehende Zustellungen:
|
|
||||||
- `messageId`: Referenz zur Envelope
|
|
||||||
- `status`: PENDING, SENT, ACKNOWLEDGED, FAILED, EXPIRED
|
|
||||||
- `retryCount`: Aktuelle Wiederholungsversuche
|
|
||||||
- `nextRetryAt`: Zeitpunkt des nächsten Versuchs
|
|
||||||
- `envelopeData`: Serialisierte Envelope-Daten
|
|
||||||
|
|
||||||
#### AcknowledgmentMessage
|
|
||||||
Bestätigungsnachricht vom Client:
|
|
||||||
- `messageId`: ID der bestätigten Nachricht
|
|
||||||
- `status`: RECEIVED, PROCESSED, FAILED
|
|
||||||
- `clientId`: Absender der Bestätigung
|
|
||||||
- `errorMessage`: Optional bei Fehler
|
|
||||||
|
|
||||||
### 2. Transport Layer (`messaging/transport/`)
|
|
||||||
|
|
||||||
#### MessagingTransport Interface
|
|
||||||
Protokoll-agnostische Schnittstelle:
|
|
||||||
```java
|
|
||||||
CompletableFuture<Void> send(String topic, byte[] payload, TransportOptions options);
|
|
||||||
void subscribe(String topicPattern, MessageHandler handler);
|
|
||||||
boolean isConnected();
|
|
||||||
String getTransportType();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### MqttTransportAdapter
|
|
||||||
MQTT-Implementierung des Transport-Interfaces:
|
|
||||||
- Adaptiert HiveMQ MQTT Client
|
|
||||||
- Unterstützt MQTT-Wildcards (+ und #)
|
|
||||||
- QoS-Mapping (0, 1, 2)
|
|
||||||
|
|
||||||
### 3. Delivery Service (`messaging/delivery/`)
|
|
||||||
|
|
||||||
#### MessageDeliveryService
|
|
||||||
Zentrale Orchestrierung:
|
|
||||||
- `sendMessage()`: Nachricht mit Tracking senden
|
|
||||||
- `handleIncomingMessage()`: Eingehende Envelope verarbeiten
|
|
||||||
- `handleAcknowledgment()`: Bestätigung verarbeiten
|
|
||||||
- `retryPendingDeliveries()`: Wiederholungsversuche durchführen
|
|
||||||
- `cleanupOldDeliveries()`: Alte Einträge aufräumen
|
|
||||||
|
|
||||||
#### AcknowledgmentHandler
|
|
||||||
Routing eingehender Nachrichten zur Anwendungslogik:
|
|
||||||
- Unwrapping der Envelope
|
|
||||||
- Routing basierend auf Topic-Pattern
|
|
||||||
- Delegation an MessageController
|
|
||||||
|
|
||||||
#### RetryScheduler
|
|
||||||
Geplante Tasks:
|
|
||||||
- Retry-Task: Alle 30 Sekunden (konfigurierbar)
|
|
||||||
- Cleanup-Task: Stündlich (konfigurierbar)
|
|
||||||
|
|
||||||
### 4. Repositories
|
|
||||||
|
|
||||||
#### MessageEnvelopeRepository
|
|
||||||
Speicherung aller Envelope-Objekte in MongoDB Collection `message_envelopes`
|
|
||||||
|
|
||||||
#### PendingDeliveryRepository
|
|
||||||
Tracking ausstehender Zustellungen in MongoDB Collection `pending_deliveries`
|
|
||||||
|
|
||||||
## Nachrichtenfluss
|
|
||||||
|
|
||||||
### Outbound (Server → Client)
|
|
||||||
|
|
||||||
1. **Anwendung** ruft `MessageDeliveryService.sendMessage()` auf
|
|
||||||
2. **MessageEnvelope** wird erstellt mit eindeutiger `messageId`
|
|
||||||
3. **PendingDelivery** wird in Datenbank gespeichert (Status: PENDING)
|
|
||||||
4. **Envelope** wird als JSON serialisiert
|
|
||||||
5. **Transport** sendet Nachricht via MQTT
|
|
||||||
6. **Status** wird auf SENT aktualisiert, `nextRetryAt` gesetzt
|
|
||||||
7. **Client** empfängt Nachricht und sendet ACK
|
|
||||||
8. **AcknowledgmentHandler** verarbeitet ACK
|
|
||||||
9. **PendingDelivery** wird auf ACKNOWLEDGED gesetzt
|
|
||||||
|
|
||||||
### Inbound (Client → Server)
|
|
||||||
|
|
||||||
1. **MQTT** empfängt Nachricht auf Topic
|
|
||||||
2. **MqttTransportAdapter** leitet an MessageDeliveryService weiter
|
|
||||||
3. **MessageEnvelope** wird aus JSON deserialisiert
|
|
||||||
4. **ACK** wird automatisch an Client gesendet (falls `requiresAck=true`)
|
|
||||||
5. **AcknowledgmentHandler** routet Payload zur Anwendung
|
|
||||||
6. **MessageController** verarbeitet Business-Logik
|
|
||||||
|
|
||||||
## Retry-Mechanismus
|
|
||||||
|
|
||||||
### Exponential Backoff
|
|
||||||
```
|
|
||||||
Versuch 1: 5 Sekunden
|
|
||||||
Versuch 2: 10 Sekunden (5s × 2.0)
|
|
||||||
Versuch 3: 20 Sekunden (10s × 2.0)
|
|
||||||
Versuch 4: 40 Sekunden (20s × 2.0)
|
|
||||||
Maximum: 5 Minuten
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ablauf
|
|
||||||
1. **RetryScheduler** läuft alle 30 Sekunden
|
|
||||||
2. Findet alle `PendingDelivery` mit Status SENT und `nextRetryAt` in Vergangenheit
|
|
||||||
3. Prüft auf Ablauf (`expiresAt`) und Max-Retries
|
|
||||||
4. Sendet Nachricht erneut via Transport
|
|
||||||
5. Aktualisiert `retryCount` und `nextRetryAt`
|
|
||||||
|
|
||||||
## Konfiguration
|
|
||||||
|
|
||||||
### application.properties
|
|
||||||
```properties
|
|
||||||
# Message Delivery Layer Configuration
|
|
||||||
app.messaging.delivery.max-retries=3
|
|
||||||
app.messaging.delivery.retry-initial-delay=5s
|
|
||||||
app.messaging.delivery.retry-max-delay=5m
|
|
||||||
app.messaging.delivery.retry-backoff-multiplier=2.0
|
|
||||||
app.messaging.delivery.ack-timeout=30s
|
|
||||||
app.messaging.delivery.message-expiry=24h
|
|
||||||
app.messaging.delivery.cleanup-interval-minutes=60
|
|
||||||
app.messaging.delivery.retry-interval-seconds=30
|
|
||||||
app.messaging.delivery.acknowledged-retention-days=7
|
|
||||||
```
|
|
||||||
|
|
||||||
## MQTT Topics
|
|
||||||
|
|
||||||
### Outbound (Server → Client)
|
|
||||||
```
|
|
||||||
/client/{clientId}/message # Chat-Nachrichten (wrapped)
|
|
||||||
/client/{clientId}/jobs # Job-Zuweisungen (wrapped)
|
|
||||||
/client/{clientId}/auth # Login-Antworten (wrapped)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Inbound (Client → Server)
|
|
||||||
```
|
|
||||||
/server/{clientId}/task_completed # Task-Abschlüsse (wrapped)
|
|
||||||
/server/{clientId}/message # Chat-Nachrichten (wrapped)
|
|
||||||
/server/{clientId}/jobs/assigned # Job-Anfragen (wrapped)
|
|
||||||
/server/login # Login-Anfragen (wrapped)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Acknowledgments
|
|
||||||
```
|
|
||||||
/ack/server/{messageId} # Client → Server ACK
|
|
||||||
/ack/client/{clientId}/{messageId} # Server → Client ACK
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migration bestehender Clients
|
|
||||||
|
|
||||||
### Phase 1: Server-seitig (✅ Abgeschlossen)
|
|
||||||
- Message Delivery Layer implementiert
|
|
||||||
- MqttPublisher nutzt jetzt MessageDeliveryService
|
|
||||||
- Backward-kompatibel: Legacy-Nachrichten werden weiterhin verarbeitet
|
|
||||||
|
|
||||||
### Phase 2: Client-seitig (TODO)
|
|
||||||
Flutter-App muss angepasst werden:
|
|
||||||
|
|
||||||
1. **Envelope-Handling**
|
|
||||||
```dart
|
|
||||||
class MessageEnvelope {
|
|
||||||
String messageId;
|
|
||||||
DateTime timestamp;
|
|
||||||
String topic;
|
|
||||||
Map<String, dynamic> payload;
|
|
||||||
bool requiresAck;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Empfang**
|
|
||||||
```dart
|
|
||||||
void handleIncomingMessage(String topic, String json) {
|
|
||||||
final envelope = MessageEnvelope.fromJson(json);
|
|
||||||
|
|
||||||
// ACK senden
|
|
||||||
if (envelope.requiresAck) {
|
|
||||||
sendAcknowledgment(envelope.messageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Payload verarbeiten
|
|
||||||
processPayload(envelope.payload);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **ACK senden**
|
|
||||||
```dart
|
|
||||||
void sendAcknowledgment(String messageId) {
|
|
||||||
final ack = {
|
|
||||||
'messageId': messageId,
|
|
||||||
'status': 'RECEIVED',
|
|
||||||
'timestamp': DateTime.now().toIso8601String(),
|
|
||||||
'clientId': myClientId
|
|
||||||
};
|
|
||||||
|
|
||||||
mqtt.publish('/ack/server/$messageId', jsonEncode(ack));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Senden**
|
|
||||||
```dart
|
|
||||||
void sendMessage(String topic, Map<String, dynamic> payload) {
|
|
||||||
final envelope = MessageEnvelope(
|
|
||||||
messageId: Uuid().v4(),
|
|
||||||
timestamp: DateTime.now(),
|
|
||||||
topic: topic,
|
|
||||||
payload: payload,
|
|
||||||
requiresAck: true
|
|
||||||
);
|
|
||||||
|
|
||||||
mqtt.publish(topic, jsonEncode(envelope.toJson()));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Monitoring & Debugging
|
|
||||||
|
|
||||||
### Logging
|
|
||||||
Alle Komponenten loggen mit Präfix:
|
|
||||||
- `[MessageDelivery]`: MessageDeliveryService
|
|
||||||
- `[MqttTransport]`: MqttTransportAdapter
|
|
||||||
- `[AckHandler]`: AcknowledgmentHandler
|
|
||||||
- `[RetryScheduler]`: RetryScheduler
|
|
||||||
- `[MessagingConfig]`: MessagingConfig
|
|
||||||
|
|
||||||
### Datenbank-Queries
|
|
||||||
|
|
||||||
**Ausstehende Zustellungen:**
|
|
||||||
```javascript
|
|
||||||
db.pending_deliveries.find({ status: "SENT" })
|
|
||||||
```
|
|
||||||
|
|
||||||
**Fehlgeschlagene Zustellungen:**
|
|
||||||
```javascript
|
|
||||||
db.pending_deliveries.find({ status: "FAILED" })
|
|
||||||
```
|
|
||||||
|
|
||||||
**Retry-Statistiken:**
|
|
||||||
```javascript
|
|
||||||
db.pending_deliveries.aggregate([
|
|
||||||
{ $group: { _id: "$status", count: { $sum: 1 } } }
|
|
||||||
])
|
|
||||||
```
|
|
||||||
|
|
||||||
**Nachrichten eines Clients:**
|
|
||||||
```javascript
|
|
||||||
db.pending_deliveries.find({ client_id: "client123" })
|
|
||||||
```
|
|
||||||
|
|
||||||
## Vorteile
|
|
||||||
|
|
||||||
### Zuverlässigkeit
|
|
||||||
- Garantierte Zustellung durch Retry-Mechanismus
|
|
||||||
- Persistierung in MongoDB verhindert Datenverlust
|
|
||||||
- Acknowledgment-Tracking für Nachvollziehbarkeit
|
|
||||||
|
|
||||||
### Skalierbarkeit
|
|
||||||
- Queue-basiertes Design
|
|
||||||
- Asynchrone Verarbeitung mit CompletableFuture
|
|
||||||
- Scheduled Tasks für Hintergrundverarbeitung
|
|
||||||
|
|
||||||
### Wartbarkeit
|
|
||||||
- Klare Trennung der Verantwortlichkeiten
|
|
||||||
- Protokoll-Abstraktion ermöglicht einfachen Austausch
|
|
||||||
- Umfangreiches Logging für Debugging
|
|
||||||
|
|
||||||
### Flexibilität
|
|
||||||
- Konfigurierbare Retry-Parameter
|
|
||||||
- Verschiedene DeliveryOptions (standard, fireAndForget, critical)
|
|
||||||
- Erweiterbar für andere Transporte (WebSocket, gRPC, etc.)
|
|
||||||
|
|
||||||
## Nächste Schritte
|
|
||||||
|
|
||||||
1. ✅ Server-seitige Implementierung abgeschlossen
|
|
||||||
2. ⏳ Flutter-App anpassen (Envelope-Handling)
|
|
||||||
3. ⏳ Integration-Tests schreiben
|
|
||||||
4. ⏳ Monitoring-Dashboard erstellen
|
|
||||||
5. ⏳ Performance-Optimierung
|
|
||||||
6. ⏳ Dokumentation für Client-Entwickler
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
Bei Fragen oder Problemen:
|
|
||||||
- Logs prüfen: `logs/votianlt.log`
|
|
||||||
- MongoDB Collections: `message_envelopes`, `pending_deliveries`
|
|
||||||
- Konfiguration: `application.properties`
|
|
||||||
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
# MQTT Migration Summary - Dokumentationsübersicht
|
|
||||||
|
|
||||||
## 📚 Erstellte Dokumentation
|
|
||||||
|
|
||||||
Alle Änderungen am MQTT-System wurden umfassend dokumentiert, um die Client-Migration zu erleichtern.
|
|
||||||
|
|
||||||
### 1. MQTT_MIGRATION_GUIDE.md
|
|
||||||
**Zielgruppe**: Client-Entwickler (Flutter/Dart)
|
|
||||||
**Inhalt**:
|
|
||||||
- Übersicht aller Server-Änderungen
|
|
||||||
- Detaillierte Client-Anpassungen mit Code-Beispielen
|
|
||||||
- Message-Envelope-Format
|
|
||||||
- Acknowledgment-Handling
|
|
||||||
- Migration Checklist
|
|
||||||
- Abwärtskompatibilität
|
|
||||||
- Vorteile des neuen Systems
|
|
||||||
|
|
||||||
**Wichtigste Punkte**:
|
|
||||||
- ⚠️ Port-Änderung: 1883 → 42099
|
|
||||||
- ⚠️ Authentifizierung erforderlich: app/apppwd
|
|
||||||
- ⚠️ Timeout erhöht: 30s → 60s
|
|
||||||
- ✅ Message-Envelope-Format implementieren
|
|
||||||
- ✅ ACK-Handling implementieren
|
|
||||||
|
|
||||||
### 2. MQTT_QUICK_REFERENCE.md
|
|
||||||
**Zielgruppe**: Client-Entwickler (Flutter/Dart)
|
|
||||||
**Inhalt**:
|
|
||||||
- Kritische Änderungen auf einen Blick
|
|
||||||
- Fertige Code-Snippets für Flutter/Dart
|
|
||||||
- Verbindungsaufbau
|
|
||||||
- Message-Envelope-Klasse
|
|
||||||
- Nachricht senden/empfangen
|
|
||||||
- ACK-Handling
|
|
||||||
- Debugging-Tipps
|
|
||||||
- Häufige Fehler und Lösungen
|
|
||||||
|
|
||||||
**Verwendung**:
|
|
||||||
Schnelle Referenz während der Implementierung - alle wichtigen Code-Beispiele sofort verfügbar.
|
|
||||||
|
|
||||||
### 3. CHANGELOG_MQTT.md
|
|
||||||
**Zielgruppe**: Alle Entwickler, DevOps
|
|
||||||
**Inhalt**:
|
|
||||||
- Breaking Changes
|
|
||||||
- Neue Features
|
|
||||||
- Entfernte Komponenten
|
|
||||||
- Geänderte Komponenten
|
|
||||||
- Architektur-Änderungen
|
|
||||||
- Migration Guide
|
|
||||||
- Kompatibilität
|
|
||||||
- Testing
|
|
||||||
- Performance
|
|
||||||
- Rollback-Plan
|
|
||||||
|
|
||||||
**Verwendung**:
|
|
||||||
Vollständige Historie aller Änderungen für Audit und Troubleshooting.
|
|
||||||
|
|
||||||
### 4. MQTT_README.md (aktualisiert)
|
|
||||||
**Zielgruppe**: Alle Entwickler
|
|
||||||
**Inhalt**:
|
|
||||||
- ⚠️ Neue Broker-Konfiguration prominent hervorgehoben
|
|
||||||
- Aktualisierte Connection-Parameter
|
|
||||||
- Hinweise auf Migration-Dokumentation
|
|
||||||
- Bestehende API-Dokumentation bleibt erhalten
|
|
||||||
|
|
||||||
**Änderungen**:
|
|
||||||
- Broker-URL und Port aktualisiert
|
|
||||||
- Authentifizierung dokumentiert
|
|
||||||
- Verweise auf neue Dokumentation hinzugefügt
|
|
||||||
|
|
||||||
### 5. MESSAGING_LAYER.md (bereits vorhanden)
|
|
||||||
**Zielgruppe**: Backend-Entwickler
|
|
||||||
**Inhalt**:
|
|
||||||
- Detaillierte Architektur des Messaging-Systems
|
|
||||||
- Plugin-basiertes Design
|
|
||||||
- Message-Delivery-Service
|
|
||||||
- Komponenten-Beschreibungen
|
|
||||||
|
|
||||||
**Status**: Bereits vorhanden, keine Änderungen erforderlich.
|
|
||||||
|
|
||||||
## 🔄 Server-Änderungen (bereits durchgeführt)
|
|
||||||
|
|
||||||
### Konfiguration
|
|
||||||
**Datei**: `src/main/resources/application.properties`
|
|
||||||
|
|
||||||
**Entfernt** (Zeilen 57-71):
|
|
||||||
```properties
|
|
||||||
# MQTT v5 settings (alt)
|
|
||||||
app.mqtt.enabled=true
|
|
||||||
app.mqtt.broker-uri=mqtt://mqtt-2.assecutor.de
|
|
||||||
app.mqtt.client-id=server-${random.uuid}
|
|
||||||
# ... weitere alte Einstellungen
|
|
||||||
```
|
|
||||||
|
|
||||||
**Aktiv**:
|
|
||||||
```properties
|
|
||||||
# Messaging Plugin Configuration
|
|
||||||
app.messaging.plugin.type=mqtt
|
|
||||||
app.messaging.plugin.mqtt.broker.host=mqtt-2.assecutor.de
|
|
||||||
app.messaging.plugin.mqtt.broker.port=42099
|
|
||||||
app.messaging.plugin.mqtt.username=app
|
|
||||||
app.messaging.plugin.mqtt.password=apppwd
|
|
||||||
app.messaging.plugin.mqtt.client.id=votianlt-server
|
|
||||||
```
|
|
||||||
|
|
||||||
### Code-Änderungen
|
|
||||||
|
|
||||||
#### 1. MqttMessagingPlugin.java
|
|
||||||
**Datei**: `src/main/java/de/assecutor/votianlt/messaging/plugin/mqtt/MqttMessagingPlugin.java`
|
|
||||||
|
|
||||||
**Änderungen**:
|
|
||||||
- Connection-Timeout: 30s → 60s (konfigurierbar)
|
|
||||||
- Keep-Alive: konfigurierbar (Standard: 60s)
|
|
||||||
- Verbesserte Fehlerbehandlung:
|
|
||||||
- TimeoutException → "Broker nicht erreichbar"
|
|
||||||
- UnknownHostException → "DNS-Fehler"
|
|
||||||
- ConnectException → "Port blockiert"
|
|
||||||
- Detailliertes Logging
|
|
||||||
|
|
||||||
#### 2. Gelöschte Klassen
|
|
||||||
- `src/main/java/de/assecutor/votianlt/config/MqttProperties.java`
|
|
||||||
- `src/main/java/de/assecutor/votianlt/config/MqttConfig.java`
|
|
||||||
|
|
||||||
**Grund**: Ersetzt durch Plugin-Konfiguration, nicht mehr verwendet.
|
|
||||||
|
|
||||||
## ✅ Verifikation
|
|
||||||
|
|
||||||
### Build erfolgreich
|
|
||||||
```bash
|
|
||||||
./mvnw clean compile
|
|
||||||
# [INFO] BUILD SUCCESS
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server läuft
|
|
||||||
```bash
|
|
||||||
./mvnw spring-boot:run
|
|
||||||
# Application running at http://localhost:8080/
|
|
||||||
```
|
|
||||||
|
|
||||||
### MQTT-Verbindung erfolgreich
|
|
||||||
```
|
|
||||||
[MqttPlugin] Connected successfully - connAck: MqttConnAck{reasonCode=SUCCESS}
|
|
||||||
[MqttPlugin] Successfully subscribed to: /ack/server/+
|
|
||||||
[MqttPlugin] Successfully subscribed to: /server/+/task_completed
|
|
||||||
[MqttPlugin] Successfully subscribed to: /server/+/jobs/assigned
|
|
||||||
[MqttPlugin] Successfully subscribed to: /server/+/message
|
|
||||||
[MqttPlugin] Successfully subscribed to: /server/+/login
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📋 Client Migration Checklist
|
|
||||||
|
|
||||||
### Vorbereitung
|
|
||||||
- [ ] `MQTT_MIGRATION_GUIDE.md` lesen
|
|
||||||
- [ ] `MQTT_QUICK_REFERENCE.md` als Referenz bereithalten
|
|
||||||
- [ ] Testumgebung vorbereiten
|
|
||||||
|
|
||||||
### Implementierung
|
|
||||||
- [ ] Port auf 42099 ändern
|
|
||||||
- [ ] Authentifizierung hinzufügen (app/apppwd)
|
|
||||||
- [ ] Connection-Timeout auf 60s erhöhen
|
|
||||||
- [ ] Keep-Alive auf 60s setzen
|
|
||||||
- [ ] MessageEnvelope-Klasse implementieren (siehe Quick Reference)
|
|
||||||
- [ ] AcknowledgmentMessage-Klasse implementieren (siehe Quick Reference)
|
|
||||||
- [ ] Envelope-basiertes Senden implementieren
|
|
||||||
- [ ] Envelope-basiertes Empfangen implementieren
|
|
||||||
- [ ] ACK-Handling implementieren
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- [ ] Verbindung testen (siehe Quick Reference: testConnection())
|
|
||||||
- [ ] Nachricht senden testen
|
|
||||||
- [ ] Nachricht empfangen testen
|
|
||||||
- [ ] ACK-Handling testen
|
|
||||||
- [ ] Fehlerszenarien testen (Timeout, Verbindungsabbruch)
|
|
||||||
|
|
||||||
### Deployment
|
|
||||||
- [ ] Staging-Umgebung testen
|
|
||||||
- [ ] Produktions-Deployment planen
|
|
||||||
- [ ] Rollback-Plan bereithalten
|
|
||||||
|
|
||||||
## 🔗 Dokumentations-Struktur
|
|
||||||
|
|
||||||
```
|
|
||||||
MQTT-Dokumentation/
|
|
||||||
├── MQTT_MIGRATION_GUIDE.md ← Hauptdokumentation für Client-Migration
|
|
||||||
├── MQTT_QUICK_REFERENCE.md ← Code-Beispiele und Schnellreferenz
|
|
||||||
├── CHANGELOG_MQTT.md ← Vollständige Änderungshistorie
|
|
||||||
├── MQTT_README.md ← API-Referenz (aktualisiert)
|
|
||||||
├── MESSAGING_LAYER.md ← Architektur-Dokumentation (vorhanden)
|
|
||||||
└── MIGRATION_SUMMARY.md ← Diese Datei (Übersicht)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎯 Nächste Schritte
|
|
||||||
|
|
||||||
### Für Client-Entwickler:
|
|
||||||
1. **Lesen**: `MQTT_MIGRATION_GUIDE.md` durcharbeiten
|
|
||||||
2. **Referenz**: `MQTT_QUICK_REFERENCE.md` für Code-Beispiele nutzen
|
|
||||||
3. **Implementieren**: Änderungen gemäß Checklist umsetzen
|
|
||||||
4. **Testen**: Verbindung und Nachrichtenaustausch testen
|
|
||||||
5. **Deployen**: Nach erfolgreichem Test in Produktion bringen
|
|
||||||
|
|
||||||
### Für Backend-Entwickler:
|
|
||||||
1. **Monitoring**: Message-Delivery-Metriken überwachen
|
|
||||||
2. **Logs**: Verbindungsprobleme in Logs prüfen
|
|
||||||
3. **Support**: Client-Entwickler bei Migration unterstützen
|
|
||||||
4. **Dokumentation**: Bei Bedarf weitere Beispiele hinzufügen
|
|
||||||
|
|
||||||
### Für DevOps:
|
|
||||||
1. **Firewall**: Port 42099 für Clients freigeben
|
|
||||||
2. **Monitoring**: MQTT-Broker-Status überwachen
|
|
||||||
3. **Backup**: Rollback-Plan bereithalten
|
|
||||||
4. **Logs**: Zentrales Logging für MQTT-Verbindungen einrichten
|
|
||||||
|
|
||||||
## 💡 Wichtige Hinweise
|
|
||||||
|
|
||||||
### Abwärtskompatibilität
|
|
||||||
Der Server unterstützt **vorübergehend** noch Legacy-Nachrichten ohne Envelope-Format. Dies ermöglicht eine schrittweise Migration der Clients.
|
|
||||||
|
|
||||||
**Empfehlung**: Alle Clients sollten so schnell wie möglich auf das neue Envelope-Format umgestellt werden.
|
|
||||||
|
|
||||||
### Vorteile des neuen Systems
|
|
||||||
1. **Zuverlässigkeit**: ACK-basierte Zustellung mit Retries
|
|
||||||
2. **Nachverfolgung**: Jede Nachricht hat eindeutige ID
|
|
||||||
3. **Fehlerbehandlung**: Detaillierte Fehlerinformationen
|
|
||||||
4. **Monitoring**: Vollständige Nachrichtenverfolgung
|
|
||||||
5. **Skalierbarkeit**: Queue-basiertes Design
|
|
||||||
|
|
||||||
### Support
|
|
||||||
Bei Fragen oder Problemen:
|
|
||||||
1. Dokumentation konsultieren (siehe oben)
|
|
||||||
2. Logs auf Client- und Server-Seite prüfen
|
|
||||||
3. Netzwerk-Konnektivität testen (Port 42099)
|
|
||||||
4. MQTT-Client-Tool verwenden (z.B. MQTT Explorer)
|
|
||||||
|
|
||||||
## 📊 Zusammenfassung
|
|
||||||
|
|
||||||
### Was wurde geändert?
|
|
||||||
- ✅ MQTT-Broker-Port: 1883 → 42099
|
|
||||||
- ✅ Authentifizierung hinzugefügt: app/apppwd
|
|
||||||
- ✅ Timeout erhöht: 30s → 60s
|
|
||||||
- ✅ Alte Konfiguration entfernt
|
|
||||||
- ✅ Fehlerbehandlung verbessert
|
|
||||||
|
|
||||||
### Was wurde dokumentiert?
|
|
||||||
- ✅ Migration Guide für Clients
|
|
||||||
- ✅ Quick Reference mit Code-Beispielen
|
|
||||||
- ✅ Vollständiger Changelog
|
|
||||||
- ✅ Aktualisierte API-Dokumentation
|
|
||||||
- ✅ Diese Übersicht
|
|
||||||
|
|
||||||
### Was muss der Client tun?
|
|
||||||
- ⚠️ Port auf 42099 ändern
|
|
||||||
- ⚠️ Authentifizierung hinzufügen
|
|
||||||
- ⚠️ Timeout erhöhen
|
|
||||||
- ✅ Message-Envelope implementieren (optional, aber empfohlen)
|
|
||||||
- ✅ ACK-Handling implementieren (optional, aber empfohlen)
|
|
||||||
|
|
||||||
### Zeitplan
|
|
||||||
- **Sofort**: Port und Authentifizierung ändern (kritisch!)
|
|
||||||
- **Kurzfristig**: Envelope-Format implementieren (empfohlen)
|
|
||||||
- **Mittelfristig**: ACK-Handling implementieren (empfohlen)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Stand**: 2025-10-22
|
|
||||||
**Version**: 2.0.0
|
|
||||||
**Status**: ✅ Server-Migration abgeschlossen, Client-Migration ausstehend
|
|
||||||
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
# MQTT System Dokumentation - Übersicht
|
|
||||||
|
|
||||||
## 🎯 Zweck dieser Dokumentation
|
|
||||||
|
|
||||||
Diese Dokumentation beschreibt die Migration des MQTT-Systems auf Version 2.0 mit Plugin-basierter Architektur und hilft Client-Entwicklern bei der Umstellung ihrer Anwendungen.
|
|
||||||
|
|
||||||
## 📚 Dokumentations-Struktur
|
|
||||||
|
|
||||||
### Für Client-Entwickler (Flutter/Dart)
|
|
||||||
|
|
||||||
#### 1. **MQTT_QUICK_REFERENCE.md** ⭐ START HERE
|
|
||||||
**Empfohlen für**: Schnelle Implementierung
|
|
||||||
**Inhalt**:
|
|
||||||
- ⚠️ Kritische Änderungen auf einen Blick
|
|
||||||
- 📋 Fertige Code-Snippets zum Copy-Paste
|
|
||||||
- 🔧 Verbindungsaufbau
|
|
||||||
- 📨 Nachricht senden/empfangen
|
|
||||||
- ✅ ACK-Handling
|
|
||||||
- 🐛 Debugging-Tipps
|
|
||||||
- ❌ Häufige Fehler und Lösungen
|
|
||||||
|
|
||||||
**Verwendung**: Als Referenz während der Implementierung offen halten.
|
|
||||||
|
|
||||||
#### 2. **MQTT_MIGRATION_GUIDE.md** 📖 DETAILLIERT
|
|
||||||
**Empfohlen für**: Vollständiges Verständnis
|
|
||||||
**Inhalt**:
|
|
||||||
- 📊 Übersicht aller Server-Änderungen
|
|
||||||
- 🔄 Detaillierte Client-Anpassungen
|
|
||||||
- 📦 Message-Envelope-Format
|
|
||||||
- ✅ Acknowledgment-System
|
|
||||||
- ☑️ Migration Checklist
|
|
||||||
- 🔙 Abwärtskompatibilität
|
|
||||||
- 💡 Vorteile des neuen Systems
|
|
||||||
- 🧪 Testing-Strategien
|
|
||||||
|
|
||||||
**Verwendung**: Vor der Implementierung komplett durchlesen.
|
|
||||||
|
|
||||||
### Für alle Entwickler
|
|
||||||
|
|
||||||
#### 3. **MIGRATION_SUMMARY.md** 📋 ÜBERSICHT
|
|
||||||
**Empfohlen für**: Schneller Überblick
|
|
||||||
**Inhalt**:
|
|
||||||
- 📚 Übersicht aller Dokumentationen
|
|
||||||
- 🔄 Zusammenfassung der Server-Änderungen
|
|
||||||
- ✅ Verifikation der Änderungen
|
|
||||||
- 📋 Client Migration Checklist
|
|
||||||
- 🔗 Dokumentations-Struktur
|
|
||||||
- 🎯 Nächste Schritte
|
|
||||||
|
|
||||||
**Verwendung**: Als Einstiegspunkt und Orientierung.
|
|
||||||
|
|
||||||
#### 4. **CHANGELOG_MQTT.md** 📝 HISTORIE
|
|
||||||
**Empfohlen für**: Audit und Troubleshooting
|
|
||||||
**Inhalt**:
|
|
||||||
- 💥 Breaking Changes
|
|
||||||
- ✨ Neue Features
|
|
||||||
- 🗑️ Entfernte Komponenten
|
|
||||||
- 🔧 Geänderte Komponenten
|
|
||||||
- 🏗️ Architektur-Änderungen
|
|
||||||
- 🧪 Testing-Ergebnisse
|
|
||||||
- 📊 Performance-Metriken
|
|
||||||
- 🔄 Rollback-Plan
|
|
||||||
|
|
||||||
**Verwendung**: Für detaillierte Änderungshistorie und Rollback-Planung.
|
|
||||||
|
|
||||||
#### 5. **MQTT_README.md** 📖 API-REFERENZ
|
|
||||||
**Empfohlen für**: API-Dokumentation
|
|
||||||
**Inhalt**:
|
|
||||||
- 🔌 Broker-Konfiguration (aktualisiert!)
|
|
||||||
- 📡 Topic-Struktur
|
|
||||||
- 📨 Message-Formate
|
|
||||||
- 🔐 Authentifizierung
|
|
||||||
- ⚙️ Connection-Parameter
|
|
||||||
|
|
||||||
**Verwendung**: Als API-Referenz für Topic-Struktur und Message-Formate.
|
|
||||||
|
|
||||||
### Für Backend-Entwickler
|
|
||||||
|
|
||||||
#### 6. **MESSAGING_LAYER.md** 🏗️ ARCHITEKTUR
|
|
||||||
**Empfohlen für**: Backend-Entwicklung
|
|
||||||
**Inhalt**:
|
|
||||||
- 🏗️ Architektur-Übersicht
|
|
||||||
- 🔌 Plugin-System
|
|
||||||
- 📦 Message-Delivery-Service
|
|
||||||
- 🔄 Nachrichtenfluss
|
|
||||||
- 🧩 Komponenten-Beschreibungen
|
|
||||||
- 🔧 Konfiguration
|
|
||||||
- 🐛 Fehlerbehandlung
|
|
||||||
|
|
||||||
**Verwendung**: Für Backend-Entwicklung und Architektur-Verständnis.
|
|
||||||
|
|
||||||
## 🚀 Quick Start für Client-Entwickler
|
|
||||||
|
|
||||||
### Schritt 1: Kritische Änderungen verstehen
|
|
||||||
```bash
|
|
||||||
# Lesen Sie zuerst die kritischen Änderungen
|
|
||||||
cat MQTT_QUICK_REFERENCE.md | head -50
|
|
||||||
```
|
|
||||||
|
|
||||||
**Wichtigste Änderungen**:
|
|
||||||
- ⚠️ **Port**: 1883 → **42099**
|
|
||||||
- ⚠️ **Auth**: Username: `app`, Password: `apppwd`
|
|
||||||
- ⚠️ **Timeout**: 30s → **60s**
|
|
||||||
|
|
||||||
### Schritt 2: Code-Beispiele kopieren
|
|
||||||
```bash
|
|
||||||
# Öffnen Sie die Quick Reference
|
|
||||||
open MQTT_QUICK_REFERENCE.md
|
|
||||||
```
|
|
||||||
|
|
||||||
Kopieren Sie die Code-Snippets für:
|
|
||||||
1. Verbindungsaufbau
|
|
||||||
2. MessageEnvelope-Klasse
|
|
||||||
3. Nachricht senden
|
|
||||||
4. Nachricht empfangen
|
|
||||||
5. ACK-Handling
|
|
||||||
|
|
||||||
### Schritt 3: Implementieren und Testen
|
|
||||||
```dart
|
|
||||||
// 1. Verbindung testen
|
|
||||||
await testConnection();
|
|
||||||
|
|
||||||
// 2. Nachricht senden testen
|
|
||||||
await sendMessage(client, clientId, 'test', {'hello': 'world'});
|
|
||||||
|
|
||||||
// 3. Nachricht empfangen testen
|
|
||||||
setupMessageListener(client, clientId);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schritt 4: Migration Checklist abarbeiten
|
|
||||||
```bash
|
|
||||||
# Öffnen Sie die Migration Checklist
|
|
||||||
open MIGRATION_SUMMARY.md
|
|
||||||
```
|
|
||||||
|
|
||||||
Arbeiten Sie die Checklist Punkt für Punkt ab.
|
|
||||||
|
|
||||||
## 📊 Änderungen auf einen Blick
|
|
||||||
|
|
||||||
### Server-Änderungen (✅ Abgeschlossen)
|
|
||||||
|
|
||||||
| Komponente | Alt | Neu | Status |
|
|
||||||
|------------|-----|-----|--------|
|
|
||||||
| **Port** | 1883 | 42099 | ✅ |
|
|
||||||
| **Auth** | Keine | app/apppwd | ✅ |
|
|
||||||
| **Timeout** | 30s | 60s | ✅ |
|
|
||||||
| **Konfiguration** | app.mqtt.* | app.messaging.plugin.mqtt.* | ✅ |
|
|
||||||
| **Fehlerbehandlung** | Basic | Detailliert | ✅ |
|
|
||||||
|
|
||||||
### Client-Änderungen (⚠️ Erforderlich)
|
|
||||||
|
|
||||||
| Aufgabe | Priorität | Dokumentation |
|
|
||||||
|---------|-----------|---------------|
|
|
||||||
| Port auf 42099 ändern | 🔴 KRITISCH | Quick Reference |
|
|
||||||
| Authentifizierung hinzufügen | 🔴 KRITISCH | Quick Reference |
|
|
||||||
| Timeout auf 60s erhöhen | 🟡 WICHTIG | Quick Reference |
|
|
||||||
| MessageEnvelope implementieren | 🟢 EMPFOHLEN | Migration Guide |
|
|
||||||
| ACK-Handling implementieren | 🟢 EMPFOHLEN | Migration Guide |
|
|
||||||
|
|
||||||
## 🎯 Empfohlener Workflow
|
|
||||||
|
|
||||||
### Für Client-Entwickler
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph LR
|
|
||||||
A[Start] --> B[Quick Reference lesen]
|
|
||||||
B --> C[Kritische Änderungen umsetzen]
|
|
||||||
C --> D[Code-Snippets kopieren]
|
|
||||||
D --> E[Implementieren]
|
|
||||||
E --> F[Testen]
|
|
||||||
F --> G{Tests OK?}
|
|
||||||
G -->|Nein| H[Migration Guide konsultieren]
|
|
||||||
H --> E
|
|
||||||
G -->|Ja| I[Deployment]
|
|
||||||
I --> J[Ende]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Für Backend-Entwickler
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph LR
|
|
||||||
A[Start] --> B[Changelog lesen]
|
|
||||||
B --> C[Messaging Layer verstehen]
|
|
||||||
C --> D[Monitoring einrichten]
|
|
||||||
D --> E[Client-Support]
|
|
||||||
E --> F[Ende]
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔍 Troubleshooting-Guide
|
|
||||||
|
|
||||||
### Problem: Wo finde ich...?
|
|
||||||
|
|
||||||
| Frage | Antwort | Dokument |
|
|
||||||
|-------|---------|----------|
|
|
||||||
| Wie verbinde ich mich? | Code-Snippet | MQTT_QUICK_REFERENCE.md |
|
|
||||||
| Warum funktioniert die Verbindung nicht? | Debugging-Tipps | MQTT_QUICK_REFERENCE.md |
|
|
||||||
| Was ist ein MessageEnvelope? | Detaillierte Erklärung | MQTT_MIGRATION_GUIDE.md |
|
|
||||||
| Welche Änderungen gab es? | Vollständige Liste | CHANGELOG_MQTT.md |
|
|
||||||
| Wie ist die Architektur? | Architektur-Diagramm | MESSAGING_LAYER.md |
|
|
||||||
| Was sind die Topics? | Topic-Struktur | MQTT_README.md |
|
|
||||||
|
|
||||||
### Problem: Verbindung schlägt fehl
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Quick Reference öffnen
|
|
||||||
open MQTT_QUICK_REFERENCE.md
|
|
||||||
|
|
||||||
# 2. Abschnitt "Debugging" suchen
|
|
||||||
# 3. "Verbindung testen" Code ausführen
|
|
||||||
# 4. "Häufige Fehler" konsultieren
|
|
||||||
```
|
|
||||||
|
|
||||||
### Problem: Nachrichten kommen nicht an
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Migration Guide öffnen
|
|
||||||
open MQTT_MIGRATION_GUIDE.md
|
|
||||||
|
|
||||||
# 2. Abschnitt "Nachrichten empfangen" suchen
|
|
||||||
# 3. Code-Beispiel mit eigenem Code vergleichen
|
|
||||||
# 4. Topic-Struktur in MQTT_README.md prüfen
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📞 Support
|
|
||||||
|
|
||||||
### Dokumentation nicht hilfreich?
|
|
||||||
|
|
||||||
1. **Logs prüfen**: Client- und Server-Logs analysieren
|
|
||||||
2. **Netzwerk testen**: Port 42099 Erreichbarkeit prüfen
|
|
||||||
3. **MQTT-Tool verwenden**: MQTT Explorer zum Debuggen nutzen
|
|
||||||
4. **Changelog konsultieren**: Alle Änderungen nochmal durchgehen
|
|
||||||
|
|
||||||
### Weitere Ressourcen
|
|
||||||
|
|
||||||
- **HiveMQ Dokumentation**: https://www.hivemq.com/docs/
|
|
||||||
- **MQTT v5 Spezifikation**: https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html
|
|
||||||
- **Flutter MQTT Client**: https://pub.dev/packages/mqtt_client
|
|
||||||
|
|
||||||
## 📈 Status
|
|
||||||
|
|
||||||
| Komponente | Status | Datum |
|
|
||||||
|------------|--------|-------|
|
|
||||||
| Server-Migration | ✅ Abgeschlossen | 2025-10-22 |
|
|
||||||
| Dokumentation | ✅ Abgeschlossen | 2025-10-22 |
|
|
||||||
| Client-Migration | ⏳ Ausstehend | TBD |
|
|
||||||
| Testing | ⏳ Ausstehend | TBD |
|
|
||||||
| Deployment | ⏳ Ausstehend | TBD |
|
|
||||||
|
|
||||||
## 🎓 Lernpfad
|
|
||||||
|
|
||||||
### Anfänger (Nur Verbindung herstellen)
|
|
||||||
1. MQTT_QUICK_REFERENCE.md → Abschnitt "Verbindung herstellen"
|
|
||||||
2. Code kopieren und anpassen
|
|
||||||
3. Testen
|
|
||||||
|
|
||||||
### Fortgeschritten (Vollständige Integration)
|
|
||||||
1. MIGRATION_SUMMARY.md → Überblick verschaffen
|
|
||||||
2. MQTT_MIGRATION_GUIDE.md → Komplett durchlesen
|
|
||||||
3. MQTT_QUICK_REFERENCE.md → Als Referenz nutzen
|
|
||||||
4. Implementieren und testen
|
|
||||||
|
|
||||||
### Experte (Architektur verstehen)
|
|
||||||
1. CHANGELOG_MQTT.md → Alle Änderungen verstehen
|
|
||||||
2. MESSAGING_LAYER.md → Architektur studieren
|
|
||||||
3. MQTT_README.md → API-Details lernen
|
|
||||||
4. Eigene Erweiterungen entwickeln
|
|
||||||
|
|
||||||
## 📝 Feedback
|
|
||||||
|
|
||||||
Diese Dokumentation wurde erstellt, um die Client-Migration so einfach wie möglich zu machen. Bei Fragen, Unklarheiten oder Verbesserungsvorschlägen:
|
|
||||||
|
|
||||||
1. Dokumentation aktualisieren
|
|
||||||
2. Beispiele hinzufügen
|
|
||||||
3. Diagramme erweitern
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Version**: 2.0.0
|
|
||||||
**Stand**: 2025-10-22
|
|
||||||
**Autor**: System-Migration
|
|
||||||
**Status**: ✅ Vollständig
|
|
||||||
|
|
||||||
@@ -1,398 +0,0 @@
|
|||||||
# MQTT Migration Guide - Client Implementation
|
|
||||||
|
|
||||||
## Übersicht
|
|
||||||
|
|
||||||
Dieses Dokument beschreibt die Änderungen am MQTT-Messaging-System und wie mobile Clients (Flutter/Dart) auf den neuen Messaging-Layer umgestellt werden müssen.
|
|
||||||
|
|
||||||
## Änderungen am Server
|
|
||||||
|
|
||||||
### 1. Neue MQTT-Broker-Konfiguration
|
|
||||||
|
|
||||||
**Wichtig: Der MQTT-Broker-Port hat sich geändert!**
|
|
||||||
|
|
||||||
```
|
|
||||||
Alter Port: 1883
|
|
||||||
Neuer Port: 42099
|
|
||||||
Broker: mqtt-2.assecutor.de:42099
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Server-Konfiguration
|
|
||||||
|
|
||||||
Die Server-Konfiguration wurde von der alten `app.mqtt.*` Konfiguration auf das neue Plugin-System umgestellt:
|
|
||||||
|
|
||||||
**Alte Konfiguration (nicht mehr verwendet):**
|
|
||||||
```properties
|
|
||||||
app.mqtt.enabled=true
|
|
||||||
app.mqtt.broker-uri=mqtt://mqtt-2.assecutor.de
|
|
||||||
app.mqtt.client-id=server-${random.uuid}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Neue Konfiguration:**
|
|
||||||
```properties
|
|
||||||
# Messaging Plugin Configuration
|
|
||||||
app.messaging.plugin.type=mqtt
|
|
||||||
app.messaging.plugin.mqtt.broker.host=mqtt-2.assecutor.de
|
|
||||||
app.messaging.plugin.mqtt.broker.port=42099
|
|
||||||
app.messaging.plugin.mqtt.username=app
|
|
||||||
app.messaging.plugin.mqtt.password=apppwd
|
|
||||||
app.messaging.plugin.mqtt.client.id=votianlt-server
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Verbesserte Fehlerbehandlung
|
|
||||||
|
|
||||||
Der Server hat jetzt:
|
|
||||||
- Erhöhten Connection-Timeout (60 Sekunden statt 30)
|
|
||||||
- Detaillierte Fehlerdiagnose für Verbindungsprobleme
|
|
||||||
- Automatische Wiederverbindung mit exponentieller Backoff-Strategie
|
|
||||||
|
|
||||||
## Client-Anpassungen erforderlich
|
|
||||||
|
|
||||||
### 1. MQTT-Broker-Verbindung aktualisieren
|
|
||||||
|
|
||||||
**Flutter/Dart Beispiel:**
|
|
||||||
|
|
||||||
```dart
|
|
||||||
import 'package:mqtt_client/mqtt_client.dart';
|
|
||||||
import 'package:mqtt_client/mqtt_server_client.dart';
|
|
||||||
|
|
||||||
class MqttService {
|
|
||||||
// WICHTIG: Neuer Port!
|
|
||||||
static const String BROKER_HOST = 'mqtt-2.assecutor.de';
|
|
||||||
static const int BROKER_PORT = 42099; // Geändert von 1883
|
|
||||||
|
|
||||||
static const String USERNAME = 'app';
|
|
||||||
static const String PASSWORD = 'apppwd';
|
|
||||||
|
|
||||||
late MqttServerClient client;
|
|
||||||
|
|
||||||
Future<void> connect(String clientId) async {
|
|
||||||
client = MqttServerClient.withPort(
|
|
||||||
BROKER_HOST,
|
|
||||||
clientId,
|
|
||||||
BROKER_PORT, // Neuer Port
|
|
||||||
);
|
|
||||||
|
|
||||||
client.logging(on: true);
|
|
||||||
client.keepAlivePeriod = 60;
|
|
||||||
client.connectTimeoutPeriod = 60000; // 60 Sekunden
|
|
||||||
client.autoReconnect = true;
|
|
||||||
|
|
||||||
// Authentifizierung
|
|
||||||
client.setProtocolV311();
|
|
||||||
|
|
||||||
final connMessage = MqttConnectMessage()
|
|
||||||
.withClientIdentifier(clientId)
|
|
||||||
.authenticateAs(USERNAME, PASSWORD)
|
|
||||||
.withWillQos(MqttQos.atLeastOnce)
|
|
||||||
.startClean()
|
|
||||||
.keepAliveFor(60);
|
|
||||||
|
|
||||||
client.connectionMessage = connMessage;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await client.connect();
|
|
||||||
print('MQTT Connected successfully');
|
|
||||||
} catch (e) {
|
|
||||||
print('MQTT Connection failed: $e');
|
|
||||||
client.disconnect();
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Topic-Struktur (unverändert)
|
|
||||||
|
|
||||||
Die Topic-Struktur bleibt gleich:
|
|
||||||
|
|
||||||
**Client → Server:**
|
|
||||||
```
|
|
||||||
/server/{clientId}/{messageType}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Server → Client:**
|
|
||||||
```
|
|
||||||
/client/{clientId}/{messageType}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Acknowledgments:**
|
|
||||||
```
|
|
||||||
Client → Server: /ack/server/{messageId}
|
|
||||||
Server → Client: /ack/client/{clientId}/{messageId}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Message Envelope Format
|
|
||||||
|
|
||||||
Der Server verwendet jetzt ein Message-Envelope-Format für alle Nachrichten:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"messageId": "uuid-v4",
|
|
||||||
"timestamp": "2025-10-22T10:30:00Z",
|
|
||||||
"topic": "/client/app-user-123/jobs/assigned",
|
|
||||||
"payload": {
|
|
||||||
// Ihre eigentliche Nachricht
|
|
||||||
},
|
|
||||||
"requiresAck": true,
|
|
||||||
"retryCount": 0,
|
|
||||||
"expiresAt": "2025-10-23T10:30:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Client-Implementierung:**
|
|
||||||
|
|
||||||
```dart
|
|
||||||
class MessageEnvelope {
|
|
||||||
final String messageId;
|
|
||||||
final DateTime timestamp;
|
|
||||||
final String topic;
|
|
||||||
final Map<String, dynamic> payload;
|
|
||||||
final bool requiresAck;
|
|
||||||
final int retryCount;
|
|
||||||
final DateTime? expiresAt;
|
|
||||||
|
|
||||||
MessageEnvelope({
|
|
||||||
required this.messageId,
|
|
||||||
required this.timestamp,
|
|
||||||
required this.topic,
|
|
||||||
required this.payload,
|
|
||||||
this.requiresAck = true,
|
|
||||||
this.retryCount = 0,
|
|
||||||
this.expiresAt,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory MessageEnvelope.fromJson(Map<String, dynamic> json) {
|
|
||||||
return MessageEnvelope(
|
|
||||||
messageId: json['messageId'],
|
|
||||||
timestamp: DateTime.parse(json['timestamp']),
|
|
||||||
topic: json['topic'],
|
|
||||||
payload: json['payload'],
|
|
||||||
requiresAck: json['requiresAck'] ?? true,
|
|
||||||
retryCount: json['retryCount'] ?? 0,
|
|
||||||
expiresAt: json['expiresAt'] != null
|
|
||||||
? DateTime.parse(json['expiresAt'])
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return {
|
|
||||||
'messageId': messageId,
|
|
||||||
'timestamp': timestamp.toIso8601String(),
|
|
||||||
'topic': topic,
|
|
||||||
'payload': payload,
|
|
||||||
'requiresAck': requiresAck,
|
|
||||||
'retryCount': retryCount,
|
|
||||||
'expiresAt': expiresAt?.toIso8601String(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Acknowledgment-Handling
|
|
||||||
|
|
||||||
Wenn eine Nachricht mit `requiresAck: true` empfangen wird, muss der Client eine Bestätigung senden:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
class AcknowledgmentMessage {
|
|
||||||
final String messageId;
|
|
||||||
final DateTime timestamp;
|
|
||||||
final String status; // "SUCCESS" oder "FAILED"
|
|
||||||
final String? errorMessage;
|
|
||||||
|
|
||||||
AcknowledgmentMessage({
|
|
||||||
required this.messageId,
|
|
||||||
required this.timestamp,
|
|
||||||
required this.status,
|
|
||||||
this.errorMessage,
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return {
|
|
||||||
'messageId': messageId,
|
|
||||||
'timestamp': timestamp.toIso8601String(),
|
|
||||||
'status': status,
|
|
||||||
if (errorMessage != null) 'errorMessage': errorMessage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verwendung:
|
|
||||||
void sendAcknowledgment(String messageId, bool success, [String? error]) {
|
|
||||||
final ack = AcknowledgmentMessage(
|
|
||||||
messageId: messageId,
|
|
||||||
timestamp: DateTime.now(),
|
|
||||||
status: success ? 'SUCCESS' : 'FAILED',
|
|
||||||
errorMessage: error,
|
|
||||||
);
|
|
||||||
|
|
||||||
final topic = '/ack/server/$messageId';
|
|
||||||
final payload = jsonEncode(ack.toJson());
|
|
||||||
|
|
||||||
final builder = MqttClientPayloadBuilder();
|
|
||||||
builder.addString(payload);
|
|
||||||
|
|
||||||
client.publishMessage(
|
|
||||||
topic,
|
|
||||||
MqttQos.exactlyOnce,
|
|
||||||
builder.payload!,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Nachrichten empfangen und verarbeiten
|
|
||||||
|
|
||||||
```dart
|
|
||||||
void setupMessageHandlers() {
|
|
||||||
client.updates!.listen((List<MqttReceivedMessage<MqttMessage>> messages) {
|
|
||||||
for (var message in messages) {
|
|
||||||
final topic = message.topic;
|
|
||||||
final payload = MqttPublishPayload.bytesToStringAsString(
|
|
||||||
(message.payload as MqttPublishMessage).payload.message,
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final json = jsonDecode(payload);
|
|
||||||
|
|
||||||
// Prüfen, ob es ein Envelope ist
|
|
||||||
if (json.containsKey('messageId') && json.containsKey('payload')) {
|
|
||||||
final envelope = MessageEnvelope.fromJson(json);
|
|
||||||
|
|
||||||
// Nachricht verarbeiten
|
|
||||||
handleMessage(envelope);
|
|
||||||
|
|
||||||
// ACK senden, wenn erforderlich
|
|
||||||
if (envelope.requiresAck) {
|
|
||||||
sendAcknowledgment(envelope.messageId, true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Legacy-Nachricht ohne Envelope
|
|
||||||
handleLegacyMessage(topic, json);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print('Error processing message: $e');
|
|
||||||
// Bei Envelope-Nachrichten: Fehler-ACK senden
|
|
||||||
if (json.containsKey('messageId')) {
|
|
||||||
sendAcknowledgment(json['messageId'], false, e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. Nachrichten senden
|
|
||||||
|
|
||||||
```dart
|
|
||||||
Future<void> sendMessage(
|
|
||||||
String messageType,
|
|
||||||
Map<String, dynamic> payload,
|
|
||||||
{bool requiresAck = true}
|
|
||||||
) async {
|
|
||||||
final envelope = MessageEnvelope(
|
|
||||||
messageId: Uuid().v4(),
|
|
||||||
timestamp: DateTime.now(),
|
|
||||||
topic: '/server/$clientId/$messageType',
|
|
||||||
payload: payload,
|
|
||||||
requiresAck: requiresAck,
|
|
||||||
);
|
|
||||||
|
|
||||||
final topic = envelope.topic;
|
|
||||||
final message = jsonEncode(envelope.toJson());
|
|
||||||
|
|
||||||
final builder = MqttClientPayloadBuilder();
|
|
||||||
builder.addString(message);
|
|
||||||
|
|
||||||
client.publishMessage(
|
|
||||||
topic,
|
|
||||||
MqttQos.exactlyOnce,
|
|
||||||
builder.payload!,
|
|
||||||
);
|
|
||||||
|
|
||||||
print('Message sent: $messageType');
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migration Checklist für Clients
|
|
||||||
|
|
||||||
- [ ] **MQTT-Broker-Port auf 42099 ändern**
|
|
||||||
- [ ] **Connection-Timeout auf mindestens 60 Sekunden erhöhen**
|
|
||||||
- [ ] **Keep-Alive auf 60 Sekunden setzen**
|
|
||||||
- [ ] **Authentifizierung hinzufügen** (username: `app`, password: `apppwd`)
|
|
||||||
- [ ] **MessageEnvelope-Klasse implementieren**
|
|
||||||
- [ ] **AcknowledgmentMessage-Klasse implementieren**
|
|
||||||
- [ ] **Envelope-basierte Nachrichtenverarbeitung implementieren**
|
|
||||||
- [ ] **ACK-Handling für eingehende Nachrichten implementieren**
|
|
||||||
- [ ] **Ausgehende Nachrichten in Envelopes verpacken**
|
|
||||||
- [ ] **Fehlerbehandlung für abgelaufene Nachrichten implementieren**
|
|
||||||
- [ ] **Retry-Logik für fehlgeschlagene Nachrichten implementieren**
|
|
||||||
|
|
||||||
## Abwärtskompatibilität
|
|
||||||
|
|
||||||
Der Server unterstützt derzeit noch Legacy-Nachrichten ohne Envelope-Format, aber es wird empfohlen, so schnell wie möglich auf das neue Format umzustellen.
|
|
||||||
|
|
||||||
**Legacy-Format (wird noch unterstützt):**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"taskId": "123",
|
|
||||||
"status": "completed"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Neues Format (empfohlen):**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"messageId": "uuid",
|
|
||||||
"timestamp": "2025-10-22T10:30:00Z",
|
|
||||||
"topic": "/server/client-123/task_completed",
|
|
||||||
"payload": {
|
|
||||||
"taskId": "123",
|
|
||||||
"status": "completed"
|
|
||||||
},
|
|
||||||
"requiresAck": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Vorteile des neuen Systems
|
|
||||||
|
|
||||||
1. **Zuverlässige Zustellung**: ACK-basiertes System mit automatischen Wiederholungen
|
|
||||||
2. **Nachrichtenverfolgung**: Jede Nachricht hat eine eindeutige ID
|
|
||||||
3. **Ablaufverwaltung**: Nachrichten können ablaufen und werden automatisch bereinigt
|
|
||||||
4. **Bessere Fehlerbehandlung**: Detaillierte Fehlerinformationen
|
|
||||||
5. **Monitoring**: Vollständige Nachrichtenverfolgung im System
|
|
||||||
|
|
||||||
## Testen der Verbindung
|
|
||||||
|
|
||||||
```dart
|
|
||||||
Future<void> testConnection() async {
|
|
||||||
try {
|
|
||||||
final mqttService = MqttService();
|
|
||||||
await mqttService.connect('test-client-${Uuid().v4()}');
|
|
||||||
|
|
||||||
// Test-Nachricht senden
|
|
||||||
await mqttService.sendMessage(
|
|
||||||
'test',
|
|
||||||
{'message': 'Hello from client'},
|
|
||||||
);
|
|
||||||
|
|
||||||
print('Connection test successful!');
|
|
||||||
} catch (e) {
|
|
||||||
print('Connection test failed: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Support und Fragen
|
|
||||||
|
|
||||||
Bei Fragen oder Problemen während der Migration:
|
|
||||||
1. Prüfen Sie die Logs auf beiden Seiten (Client und Server)
|
|
||||||
2. Stellen Sie sicher, dass der Port 42099 erreichbar ist
|
|
||||||
3. Überprüfen Sie die Authentifizierungsdaten
|
|
||||||
4. Testen Sie die Verbindung mit einem MQTT-Client-Tool (z.B. MQTT Explorer)
|
|
||||||
|
|
||||||
## Weitere Dokumentation
|
|
||||||
|
|
||||||
- `MESSAGING_LAYER.md` - Detaillierte Architektur des Messaging-Systems
|
|
||||||
- `MQTT_README.md` - MQTT-API-Dokumentation
|
|
||||||
- `CLAUDE.md` - Allgemeine Systemarchitektur
|
|
||||||
|
|
||||||
@@ -1,367 +0,0 @@
|
|||||||
# MQTT Quick Reference - Client Migration
|
|
||||||
|
|
||||||
## 🚨 Kritische Änderungen
|
|
||||||
|
|
||||||
### Port-Änderung (WICHTIG!)
|
|
||||||
```
|
|
||||||
Alt: mqtt-2.assecutor.de:1883
|
|
||||||
Neu: mqtt-2.assecutor.de:42099
|
|
||||||
```
|
|
||||||
|
|
||||||
### Authentifizierung (NEU!)
|
|
||||||
```
|
|
||||||
Username: app
|
|
||||||
Password: apppwd
|
|
||||||
```
|
|
||||||
|
|
||||||
### Timeout-Erhöhung
|
|
||||||
```
|
|
||||||
Connection Timeout: 60 Sekunden (vorher 30s)
|
|
||||||
Keep-Alive: 60 Sekunden (vorher 30s)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📋 Flutter/Dart Code-Snippets
|
|
||||||
|
|
||||||
### 1. Verbindung herstellen
|
|
||||||
|
|
||||||
```dart
|
|
||||||
import 'package:mqtt_client/mqtt_client.dart';
|
|
||||||
import 'package:mqtt_client/mqtt_server_client.dart';
|
|
||||||
|
|
||||||
Future<MqttServerClient> connectToMqtt(String clientId) async {
|
|
||||||
final client = MqttServerClient.withPort(
|
|
||||||
'mqtt-2.assecutor.de',
|
|
||||||
clientId,
|
|
||||||
42099, // NEUER PORT!
|
|
||||||
);
|
|
||||||
|
|
||||||
client.keepAlivePeriod = 60;
|
|
||||||
client.connectTimeoutPeriod = 60000;
|
|
||||||
client.autoReconnect = true;
|
|
||||||
client.setProtocolV311();
|
|
||||||
|
|
||||||
final connMessage = MqttConnectMessage()
|
|
||||||
.withClientIdentifier(clientId)
|
|
||||||
.authenticateAs('app', 'apppwd') // NEU: Authentifizierung
|
|
||||||
.withWillQos(MqttQos.atLeastOnce)
|
|
||||||
.startClean()
|
|
||||||
.keepAliveFor(60);
|
|
||||||
|
|
||||||
client.connectionMessage = connMessage;
|
|
||||||
|
|
||||||
await client.connect();
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Message Envelope (NEU!)
|
|
||||||
|
|
||||||
```dart
|
|
||||||
class MessageEnvelope {
|
|
||||||
final String messageId;
|
|
||||||
final DateTime timestamp;
|
|
||||||
final String topic;
|
|
||||||
final Map<String, dynamic> payload;
|
|
||||||
final bool requiresAck;
|
|
||||||
final int retryCount;
|
|
||||||
final DateTime? expiresAt;
|
|
||||||
|
|
||||||
MessageEnvelope({
|
|
||||||
required this.messageId,
|
|
||||||
required this.timestamp,
|
|
||||||
required this.topic,
|
|
||||||
required this.payload,
|
|
||||||
this.requiresAck = true,
|
|
||||||
this.retryCount = 0,
|
|
||||||
this.expiresAt,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory MessageEnvelope.fromJson(Map<String, dynamic> json) {
|
|
||||||
return MessageEnvelope(
|
|
||||||
messageId: json['messageId'],
|
|
||||||
timestamp: DateTime.parse(json['timestamp']),
|
|
||||||
topic: json['topic'],
|
|
||||||
payload: json['payload'],
|
|
||||||
requiresAck: json['requiresAck'] ?? true,
|
|
||||||
retryCount: json['retryCount'] ?? 0,
|
|
||||||
expiresAt: json['expiresAt'] != null
|
|
||||||
? DateTime.parse(json['expiresAt'])
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'messageId': messageId,
|
|
||||||
'timestamp': timestamp.toIso8601String(),
|
|
||||||
'topic': topic,
|
|
||||||
'payload': payload,
|
|
||||||
'requiresAck': requiresAck,
|
|
||||||
'retryCount': retryCount,
|
|
||||||
if (expiresAt != null) 'expiresAt': expiresAt!.toIso8601String(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Nachricht senden
|
|
||||||
|
|
||||||
```dart
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
Future<void> sendMessage(
|
|
||||||
MqttServerClient client,
|
|
||||||
String clientId,
|
|
||||||
String messageType,
|
|
||||||
Map<String, dynamic> payload,
|
|
||||||
) async {
|
|
||||||
final envelope = MessageEnvelope(
|
|
||||||
messageId: Uuid().v4(),
|
|
||||||
timestamp: DateTime.now(),
|
|
||||||
topic: '/server/$clientId/$messageType',
|
|
||||||
payload: payload,
|
|
||||||
requiresAck: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
final builder = MqttClientPayloadBuilder();
|
|
||||||
builder.addString(jsonEncode(envelope.toJson()));
|
|
||||||
|
|
||||||
client.publishMessage(
|
|
||||||
envelope.topic,
|
|
||||||
MqttQos.exactlyOnce,
|
|
||||||
builder.payload!,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Beispiel-Verwendung:
|
|
||||||
await sendMessage(
|
|
||||||
client,
|
|
||||||
'app-user-123',
|
|
||||||
'task_completed',
|
|
||||||
{
|
|
||||||
'taskId': '456',
|
|
||||||
'status': 'completed',
|
|
||||||
'completedAt': DateTime.now().toIso8601String(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Nachricht empfangen
|
|
||||||
|
|
||||||
```dart
|
|
||||||
void setupMessageListener(MqttServerClient client, String clientId) {
|
|
||||||
// Subscribe zu allen relevanten Topics
|
|
||||||
client.subscribe('/client/$clientId/#', MqttQos.exactlyOnce);
|
|
||||||
client.subscribe('/ack/client/$clientId/#', MqttQos.exactlyOnce);
|
|
||||||
|
|
||||||
client.updates!.listen((List<MqttReceivedMessage<MqttMessage>> messages) {
|
|
||||||
for (var message in messages) {
|
|
||||||
final topic = message.topic;
|
|
||||||
final payloadString = MqttPublishPayload.bytesToStringAsString(
|
|
||||||
(message.payload as MqttPublishMessage).payload.message,
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final json = jsonDecode(payloadString);
|
|
||||||
|
|
||||||
// Prüfen ob Envelope-Format
|
|
||||||
if (json.containsKey('messageId') && json.containsKey('payload')) {
|
|
||||||
final envelope = MessageEnvelope.fromJson(json);
|
|
||||||
|
|
||||||
// Nachricht verarbeiten
|
|
||||||
handleEnvelopeMessage(envelope);
|
|
||||||
|
|
||||||
// ACK senden wenn erforderlich
|
|
||||||
if (envelope.requiresAck) {
|
|
||||||
sendAck(client, envelope.messageId, true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Legacy-Format
|
|
||||||
handleLegacyMessage(topic, json);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print('Error processing message: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Acknowledgment senden (NEU!)
|
|
||||||
|
|
||||||
```dart
|
|
||||||
class AcknowledgmentMessage {
|
|
||||||
final String messageId;
|
|
||||||
final DateTime timestamp;
|
|
||||||
final String status;
|
|
||||||
final String? errorMessage;
|
|
||||||
|
|
||||||
AcknowledgmentMessage({
|
|
||||||
required this.messageId,
|
|
||||||
required this.timestamp,
|
|
||||||
required this.status,
|
|
||||||
this.errorMessage,
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'messageId': messageId,
|
|
||||||
'timestamp': timestamp.toIso8601String(),
|
|
||||||
'status': status,
|
|
||||||
if (errorMessage != null) 'errorMessage': errorMessage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendAck(
|
|
||||||
MqttServerClient client,
|
|
||||||
String messageId,
|
|
||||||
bool success,
|
|
||||||
[String? errorMessage]
|
|
||||||
) {
|
|
||||||
final ack = AcknowledgmentMessage(
|
|
||||||
messageId: messageId,
|
|
||||||
timestamp: DateTime.now(),
|
|
||||||
status: success ? 'SUCCESS' : 'FAILED',
|
|
||||||
errorMessage: errorMessage,
|
|
||||||
);
|
|
||||||
|
|
||||||
final topic = '/ack/server/$messageId';
|
|
||||||
final builder = MqttClientPayloadBuilder();
|
|
||||||
builder.addString(jsonEncode(ack.toJson()));
|
|
||||||
|
|
||||||
client.publishMessage(
|
|
||||||
topic,
|
|
||||||
MqttQos.exactlyOnce,
|
|
||||||
builder.payload!,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📊 Topic-Struktur (unverändert)
|
|
||||||
|
|
||||||
### Client → Server
|
|
||||||
```
|
|
||||||
/server/{clientId}/task_completed
|
|
||||||
/server/{clientId}/login
|
|
||||||
/server/{clientId}/message
|
|
||||||
/server/{clientId}/jobs/assigned
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server → Client
|
|
||||||
```
|
|
||||||
/client/{clientId}/jobs/assigned
|
|
||||||
/client/{clientId}/message
|
|
||||||
/client/{clientId}/task_update
|
|
||||||
```
|
|
||||||
|
|
||||||
### Acknowledgments
|
|
||||||
```
|
|
||||||
Client → Server: /ack/server/{messageId}
|
|
||||||
Server → Client: /ack/client/{clientId}/{messageId}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔍 Debugging
|
|
||||||
|
|
||||||
### Verbindung testen
|
|
||||||
|
|
||||||
```dart
|
|
||||||
Future<void> testConnection() async {
|
|
||||||
try {
|
|
||||||
final client = await connectToMqtt('test-${Uuid().v4()}');
|
|
||||||
|
|
||||||
if (client.connectionStatus!.state == MqttConnectionState.connected) {
|
|
||||||
print('✅ Connection successful!');
|
|
||||||
|
|
||||||
// Test-Nachricht senden
|
|
||||||
await sendMessage(
|
|
||||||
client,
|
|
||||||
'test-client',
|
|
||||||
'test',
|
|
||||||
{'message': 'Hello from client'},
|
|
||||||
);
|
|
||||||
|
|
||||||
print('✅ Test message sent!');
|
|
||||||
} else {
|
|
||||||
print('❌ Connection failed: ${client.connectionStatus}');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print('❌ Error: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Häufige Fehler
|
|
||||||
|
|
||||||
#### 1. Connection Timeout
|
|
||||||
```
|
|
||||||
Fehler: TimeoutException after 60 seconds
|
|
||||||
Lösung:
|
|
||||||
- Prüfen Sie, ob Port 42099 erreichbar ist
|
|
||||||
- Firewall-Einstellungen überprüfen
|
|
||||||
- Netzwerkverbindung testen
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. Authentication Failed
|
|
||||||
```
|
|
||||||
Fehler: Connection refused
|
|
||||||
Lösung:
|
|
||||||
- Username: 'app'
|
|
||||||
- Password: 'apppwd'
|
|
||||||
- Stellen Sie sicher, dass authenticateAs() aufgerufen wird
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3. Message not received
|
|
||||||
```
|
|
||||||
Fehler: Keine Nachrichten empfangen
|
|
||||||
Lösung:
|
|
||||||
- Subscription überprüfen: client.subscribe('/client/$clientId/#', ...)
|
|
||||||
- Listener registriert: client.updates!.listen(...)
|
|
||||||
- Topic-Format korrekt: /client/{clientId}/{messageType}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📦 Dependencies
|
|
||||||
|
|
||||||
### pubspec.yaml
|
|
||||||
```yaml
|
|
||||||
dependencies:
|
|
||||||
mqtt_client: ^10.2.0
|
|
||||||
uuid: ^4.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
## ✅ Migration Checklist
|
|
||||||
|
|
||||||
- [ ] Port auf 42099 geändert
|
|
||||||
- [ ] Authentifizierung hinzugefügt (app/apppwd)
|
|
||||||
- [ ] Connection-Timeout auf 60s erhöht
|
|
||||||
- [ ] Keep-Alive auf 60s gesetzt
|
|
||||||
- [ ] MessageEnvelope-Klasse implementiert
|
|
||||||
- [ ] AcknowledgmentMessage-Klasse implementiert
|
|
||||||
- [ ] Envelope-basiertes Senden implementiert
|
|
||||||
- [ ] Envelope-basiertes Empfangen implementiert
|
|
||||||
- [ ] ACK-Handling implementiert
|
|
||||||
- [ ] Fehlerbehandlung für ACKs implementiert
|
|
||||||
- [ ] Verbindung getestet
|
|
||||||
- [ ] Nachrichtenversand getestet
|
|
||||||
- [ ] Nachrichtenempfang getestet
|
|
||||||
|
|
||||||
## 🔗 Weitere Dokumentation
|
|
||||||
|
|
||||||
- **Detaillierte Migration**: `MQTT_MIGRATION_GUIDE.md`
|
|
||||||
- **Changelog**: `CHANGELOG_MQTT.md`
|
|
||||||
- **Architektur**: `MESSAGING_LAYER.md`
|
|
||||||
- **API-Referenz**: `MQTT_README.md`
|
|
||||||
|
|
||||||
## 💡 Best Practices
|
|
||||||
|
|
||||||
1. **Eindeutige Client-IDs**: Verwenden Sie stabile, geräte-spezifische IDs
|
|
||||||
2. **Fehlerbehandlung**: Implementieren Sie Retry-Logik für fehlgeschlagene Verbindungen
|
|
||||||
3. **ACK-Timeout**: Warten Sie maximal 30 Sekunden auf ACKs
|
|
||||||
4. **Message-Expiry**: Prüfen Sie `expiresAt` vor der Verarbeitung
|
|
||||||
5. **Logging**: Loggen Sie alle Verbindungsereignisse für Debugging
|
|
||||||
|
|
||||||
## 🆘 Support
|
|
||||||
|
|
||||||
Bei Problemen:
|
|
||||||
1. Logs auf Client- und Server-Seite prüfen
|
|
||||||
2. Netzwerk-Konnektivität testen (Port 42099)
|
|
||||||
3. MQTT-Client-Tool verwenden (z.B. MQTT Explorer)
|
|
||||||
4. Dokumentation konsultieren
|
|
||||||
|
|
||||||
191
MQTT_README.md
191
MQTT_README.md
@@ -1,191 +0,0 @@
|
|||||||
# VOTIANLT MQTT Messaging API
|
|
||||||
|
|
||||||
This document describes how mobile/Flutter apps should communicate with the backend using MQTT. It replaces the previous STOMP/WebSocket communication.
|
|
||||||
|
|
||||||
## ⚠️ WICHTIG: Neue Konfiguration (Stand: 2025-10-22)
|
|
||||||
|
|
||||||
**Broker**: `mqtt-2.assecutor.de:42099` (MQTT v5)
|
|
||||||
**Port**: `42099` (geändert von 1883!)
|
|
||||||
**QoS**: 2 (exactly once)
|
|
||||||
**Retain**: Enabled for critical topics (see below), otherwise not retained
|
|
||||||
**Payloads**: JSON (UTF‑8)
|
|
||||||
|
|
||||||
### Connection Parameters
|
|
||||||
- **MQTT clientId**: choose a stable, unique per-device id (e.g., app-<uuid>)
|
|
||||||
- **Clean session**: false (recommended for guaranteed delivery). The broker will queue QoS>0 messages while the app is offline.
|
|
||||||
- **Authentication**: **REQUIRED** (neu!)
|
|
||||||
- Username: `app`
|
|
||||||
- Password: `apppwd`
|
|
||||||
- **Keep-Alive**: 60 seconds
|
|
||||||
- **Connection Timeout**: 60 seconds
|
|
||||||
|
|
||||||
### Migration Notice
|
|
||||||
📖 **Für die Migration auf das neue System siehe:**
|
|
||||||
- `MQTT_MIGRATION_GUIDE.md` - Detaillierte Migrationsanleitung
|
|
||||||
- `MQTT_QUICK_REFERENCE.md` - Schnellreferenz mit Code-Beispielen
|
|
||||||
- `CHANGELOG_MQTT.md` - Vollständige Liste aller Änderungen
|
|
||||||
|
|
||||||
Topic Naming (v1/*)
|
|
||||||
- v1/app/<deviceId>/auth/login (App -> Server)
|
|
||||||
- v1/users/<username>/notifications (Server -> App)
|
|
||||||
- v1/broadcasts (Server -> App)
|
|
||||||
- v1/app/<deviceId>/jobs/assigned (App -> Server request)
|
|
||||||
- v1/app/<deviceId>/job/status (App -> Server)
|
|
||||||
- v1/app/<deviceId>/device/location (App -> Server)
|
|
||||||
- v1/tasks/<taskId> (Server -> App events for a single task)
|
|
||||||
- v1/task-updates (Server -> App general task events) [optional]
|
|
||||||
|
|
||||||
General pattern
|
|
||||||
- Requests from apps go under v1/app/<deviceId>/...
|
|
||||||
- Server responses and events are published to either a user‑ or task‑scoped topic as listed above.
|
|
||||||
|
|
||||||
1) Authentication (App -> Server)
|
|
||||||
Topic: v1/app/<deviceId>/auth/login
|
|
||||||
Payload request:
|
|
||||||
{
|
|
||||||
"email": "user@example.com",
|
|
||||||
"password": "secret"
|
|
||||||
}
|
|
||||||
|
|
||||||
Response (Server -> App)
|
|
||||||
Topic: v1/users/<username-or-appUserId>/notifications
|
|
||||||
Payload:
|
|
||||||
{
|
|
||||||
"type": "auth",
|
|
||||||
"success": true,
|
|
||||||
"message": "Anmeldung erfolgreich",
|
|
||||||
"appUserId": "<ObjectId>"
|
|
||||||
}
|
|
||||||
|
|
||||||
2) Job status update (App -> Server)
|
|
||||||
Topic: v1/app/<deviceId>/job/status
|
|
||||||
Payload request (example):
|
|
||||||
{
|
|
||||||
"jobId": "<ObjectId>",
|
|
||||||
"status": "ON_ROUTE",
|
|
||||||
"note": "...",
|
|
||||||
"timestamp": "2025-09-13T22:00:00"
|
|
||||||
}
|
|
||||||
|
|
||||||
Server may publish derived updates to:
|
|
||||||
- v1/broadcasts (if global) or
|
|
||||||
- v1/users/<username>/notifications (if per user)
|
|
||||||
|
|
||||||
3) Device location (App -> Server)
|
|
||||||
Topic: v1/app/<deviceId>/device/location
|
|
||||||
Payload:
|
|
||||||
{
|
|
||||||
"lat": 48.12345,
|
|
||||||
"lon": 11.54321,
|
|
||||||
"accuracy": 5.4,
|
|
||||||
"timestamp": "2025-09-13T22:00:00"
|
|
||||||
}
|
|
||||||
|
|
||||||
4) Assigned jobs request (App -> Server)
|
|
||||||
Topic: v1/app/<deviceId>/jobs/assigned
|
|
||||||
Payload request:
|
|
||||||
{
|
|
||||||
"appUserId": "<ObjectId>"
|
|
||||||
}
|
|
||||||
|
|
||||||
Response (Server -> App)
|
|
||||||
Topic: v1/users/<appUserId>/notifications
|
|
||||||
Payload:
|
|
||||||
{
|
|
||||||
"type": "jobs",
|
|
||||||
"jobs": [ { /* JobWithRelatedDataDTO */ } ]
|
|
||||||
}
|
|
||||||
|
|
||||||
5) Task completion events (Server -> App)
|
|
||||||
- When a task is completed (CONFIRMATION, SIGNATURE, BARCODE, TODOLIST, PHOTO), the server publishes an event to the task‑scoped topic.
|
|
||||||
Topic: v1/tasks/<taskId>
|
|
||||||
Payload:
|
|
||||||
{
|
|
||||||
"event": "taskCompleted",
|
|
||||||
"taskId": "<taskId>",
|
|
||||||
"jobId": "<jobId>",
|
|
||||||
"taskType": "PHOTO|CONFIRMATION|...",
|
|
||||||
"completed": true,
|
|
||||||
"completedAt": "2025-09-13T22:05:00",
|
|
||||||
"completedBy": "driver01",
|
|
||||||
"note": "optional"
|
|
||||||
}
|
|
||||||
|
|
||||||
6) Photo uploads (MQTT)
|
|
||||||
- Apps send photos as base64 strings within the MQTT payload when reporting PHOTO task completion.
|
|
||||||
|
|
||||||
Topic (App -> Server): v1/app/<deviceId>/task/photo/completed
|
|
||||||
Payload:
|
|
||||||
{
|
|
||||||
"taskId": "<taskId>",
|
|
||||||
"completedBy": "driver01",
|
|
||||||
"note": "optional",
|
|
||||||
"extraData": {
|
|
||||||
"photos": ["<base64-1>", "<base64-2>"],
|
|
||||||
"count": 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Server behavior:
|
|
||||||
- Saves the photos in the photos collection, marks the task as completed, and publishes an event:
|
|
||||||
Topic (Server -> App): v1/tasks/<taskId>
|
|
||||||
Payload:
|
|
||||||
{
|
|
||||||
"event": "taskCompleted",
|
|
||||||
"taskId": "<taskId>",
|
|
||||||
"jobId": "<jobId>",
|
|
||||||
"taskType": "PHOTO",
|
|
||||||
"completed": true,
|
|
||||||
"completedAt": "...",
|
|
||||||
"completedBy": "driver01",
|
|
||||||
"note": "optional"
|
|
||||||
}
|
|
||||||
|
|
||||||
7) Broadcasts and notifications (Server -> App)
|
|
||||||
- Broadcasts: v1/broadcasts
|
|
||||||
- User notifications: v1/users/<username>/notifications
|
|
||||||
Payload example:
|
|
||||||
{
|
|
||||||
"type": "broadcast|notification",
|
|
||||||
"message": "...",
|
|
||||||
"timestamp": "2025-09-13T22:10:00"
|
|
||||||
}
|
|
||||||
|
|
||||||
## Chat Messaging (App ↔ Server)
|
|
||||||
|
|
||||||
Mobile apps exchange chat messages with the backend through dedicated topics. JSON samples can be
|
|
||||||
found under `src/main/resources/mqtt/chat`.
|
|
||||||
|
|
||||||
### App → Server
|
|
||||||
- **Topic:** `/server/{clientId}/message`
|
|
||||||
- **Payload example:** `src/main/resources/mqtt/chat/incoming-chat-message.json`
|
|
||||||
- **Required fields:** `sender`, `receiver`, `content`
|
|
||||||
- **Optional fields:** `jobId` (Mongo ObjectId), `jobNumber`
|
|
||||||
- Payloads missing required fields or containing invalid `jobId` values are rejected with a warning log.
|
|
||||||
|
|
||||||
### Server → App
|
|
||||||
- **Topic:** `/client/{receiver}/message`
|
|
||||||
- **Payload example:** `src/main/resources/mqtt/chat/outgoing-chat-message.json`
|
|
||||||
- **Notes:** `direction` (INCOMING/OUTGOING) and `messageType` (GENERAL/JOB_RELATED) mirror the
|
|
||||||
persisted message entity. `read` remains `false` until the receiver acknowledges the message via the
|
|
||||||
REST API.
|
|
||||||
|
|
||||||
### Quality of Service
|
|
||||||
- Chat topics inherit the global default QoS 2 (`app.mqtt.default-qos`).
|
|
||||||
- Messages are not retained; offline clients rely on QoS queueing on the broker.
|
|
||||||
|
|
||||||
Quality of Service & Retain
|
|
||||||
- QoS 2 (exactly once) is used by default server side for both inbound subscriptions and outbound publications.
|
|
||||||
- Retained messages are disabled by default to avoid stale updates.
|
|
||||||
|
|
||||||
Error Handling
|
|
||||||
- Server logs errors; apps should implement local retries for transient failures.
|
|
||||||
- For request/response patterns over MQTT, include correlationId in payloads if you need strict pairing.
|
|
||||||
|
|
||||||
Security
|
|
||||||
- If authentication is required at broker level, configure username/password.
|
|
||||||
- Consider using TLS if the broker supports it.
|
|
||||||
|
|
||||||
Migration notes
|
|
||||||
- Previous STOMP destinations like /topic/tasks/{taskId} are now MQTT topics v1/tasks/<taskId>.
|
|
||||||
- Photos for PHOTO tasks must be embedded in the MQTT message (extraData.photos) published to v1/app/<deviceId>/task/photo/completed. The old HTTP endpoints have been removed.
|
|
||||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
|||||||
|
package de.assecutor.votianlt.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Separate configuration for PasswordEncoder to avoid circular dependencies
|
||||||
|
* with VaadinWebSecurity configuration.
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class PasswordEncoderConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder passwordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -97,6 +97,7 @@ public class AcknowledgmentHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle login request
|
* Handle login request
|
||||||
|
* Topic: /server/login
|
||||||
*/
|
*/
|
||||||
private void handleLogin(Map<String, Object> payload) {
|
private void handleLogin(Map<String, Object> payload) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
* Topic Structure (managed internally):
|
* Topic Structure (managed internally):
|
||||||
* - Server -> Client: /client/{clientId}/{messageType}
|
* - Server -> Client: /client/{clientId}/{messageType}
|
||||||
* - Client -> Server: /server/{clientId}/{messageType}
|
* - Client -> Server: /server/{clientId}/{messageType}
|
||||||
* - ACK Server -> Client: /ack/client/{clientId}/{messageId}
|
* - ACK Server -> Client: /client/{clientId}/{messageId}/ack
|
||||||
* - ACK Client -> Server: /ack/server/{messageId}
|
* - ACK Client -> Server: /server/{messageId}/ack
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class MqttMessagingPlugin implements MessagingPlugin {
|
public class MqttMessagingPlugin implements MessagingPlugin {
|
||||||
@@ -33,12 +33,12 @@ public class MqttMessagingPlugin implements MessagingPlugin {
|
|||||||
// Topic templates
|
// Topic templates
|
||||||
private static final String TOPIC_TO_CLIENT = "/client/%s/%s"; // /client/{clientId}/{messageType}
|
private static final String TOPIC_TO_CLIENT = "/client/%s/%s"; // /client/{clientId}/{messageType}
|
||||||
private static final String TOPIC_FROM_CLIENT = "/server/%s/%s"; // /server/{clientId}/{messageType}
|
private static final String TOPIC_FROM_CLIENT = "/server/%s/%s"; // /server/{clientId}/{messageType}
|
||||||
private static final String TOPIC_ACK_TO_CLIENT = "/ack/client/%s/%s"; // /ack/client/{clientId}/{messageId}
|
private static final String TOPIC_ACK_TO_CLIENT = "/client/%s/%s/ack"; // /client/{clientId}/{messageId}/ack
|
||||||
private static final String TOPIC_ACK_FROM_CLIENT = "/ack/server/%s"; // /ack/server/{messageId}
|
private static final String TOPIC_ACK_FROM_CLIENT = "/server/%s/ack"; // /server/{messageId}/ack
|
||||||
|
|
||||||
// Subscription patterns
|
// Subscription patterns
|
||||||
private static final String PATTERN_FROM_CLIENT = "/server/+/%s"; // /server/+/{messageType}
|
private static final String PATTERN_FROM_CLIENT = "/server/+/%s"; // /server/+/{messageType}
|
||||||
private static final String PATTERN_ACK_FROM_CLIENT = "/ack/server/+"; // /ack/server/+
|
private static final String PATTERN_ACK_FROM_CLIENT = "/server/+/ack"; // /server/+/ack
|
||||||
|
|
||||||
private Mqtt5AsyncClient mqttClient;
|
private Mqtt5AsyncClient mqttClient;
|
||||||
private ConnectionStateListener connectionListener;
|
private ConnectionStateListener connectionListener;
|
||||||
@@ -151,9 +151,21 @@ public class MqttMessagingPlugin implements MessagingPlugin {
|
|||||||
try {
|
try {
|
||||||
notifyConnectionState(ConnectionState.DISCONNECTING, null);
|
notifyConnectionState(ConnectionState.DISCONNECTING, null);
|
||||||
|
|
||||||
if (mqttClient != null && connected) {
|
if (mqttClient != null) {
|
||||||
|
// Check actual client connection state, not just our flag
|
||||||
|
var clientState = mqttClient.getState();
|
||||||
|
if (clientState.isConnected()) {
|
||||||
|
try {
|
||||||
mqttClient.disconnect().join();
|
mqttClient.disconnect().join();
|
||||||
log.info("[MqttPlugin] Disconnected successfully");
|
log.info("[MqttPlugin] Disconnected successfully");
|
||||||
|
} catch (Exception disconnectEx) {
|
||||||
|
// Log but don't throw - client may already be disconnected
|
||||||
|
log.warn("[MqttPlugin] Disconnect failed (client may already be disconnected): {}",
|
||||||
|
disconnectEx.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("[MqttPlugin] Client already disconnected (state: {})", clientState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connected = false;
|
connected = false;
|
||||||
@@ -163,7 +175,10 @@ public class MqttMessagingPlugin implements MessagingPlugin {
|
|||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[MqttPlugin] Shutdown failed: {}", e.getMessage(), e);
|
log.error("[MqttPlugin] Shutdown failed: {}", e.getMessage(), e);
|
||||||
throw new PluginException("Failed to shutdown MQTT plugin", e);
|
// Don't throw on shutdown - just log the error
|
||||||
|
connected = false;
|
||||||
|
messageHandlers.clear();
|
||||||
|
ackHandler = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,12 +217,30 @@ public class MqttMessagingPlugin implements MessagingPlugin {
|
|||||||
throw new PluginException("MQTT client is not connected");
|
throw new PluginException("MQTT client is not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
messageHandlers.put(messageType, handler);
|
||||||
|
|
||||||
|
// Special case for login: subscribe to /server/login (without clientId)
|
||||||
|
if ("login".equals(messageType)) {
|
||||||
|
String loginTopic = "/server/login";
|
||||||
|
log.info("[MqttPlugin] Registering handler for message type '{}' with topic: {}", messageType, loginTopic);
|
||||||
|
|
||||||
|
mqttClient.subscribeWith()
|
||||||
|
.topicFilter(loginTopic)
|
||||||
|
.qos(MqttQos.EXACTLY_ONCE)
|
||||||
|
.send()
|
||||||
|
.whenComplete((subAck, throwable) -> {
|
||||||
|
if (throwable != null) {
|
||||||
|
log.error("[MqttPlugin] Subscription to {} failed: {}", loginTopic, throwable.getMessage());
|
||||||
|
messageHandlers.remove(messageType);
|
||||||
|
} else {
|
||||||
|
log.info("[MqttPlugin] Successfully subscribed to: {}", loginTopic);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Standard pattern: /server/+/{messageType}
|
||||||
String topicPattern = String.format(PATTERN_FROM_CLIENT, messageType);
|
String topicPattern = String.format(PATTERN_FROM_CLIENT, messageType);
|
||||||
log.info("[MqttPlugin] Registering handler for message type '{}' with pattern: {}", messageType, topicPattern);
|
log.info("[MqttPlugin] Registering handler for message type '{}' with pattern: {}", messageType, topicPattern);
|
||||||
|
|
||||||
messageHandlers.put(messageType, handler);
|
|
||||||
|
|
||||||
// Subscribe to the topic pattern
|
|
||||||
mqttClient.subscribeWith()
|
mqttClient.subscribeWith()
|
||||||
.topicFilter(topicPattern)
|
.topicFilter(topicPattern)
|
||||||
.qos(MqttQos.EXACTLY_ONCE)
|
.qos(MqttQos.EXACTLY_ONCE)
|
||||||
@@ -221,6 +254,7 @@ public class MqttMessagingPlugin implements MessagingPlugin {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerAckHandler(AckHandler handler) throws PluginException {
|
public void registerAckHandler(AckHandler handler) throws PluginException {
|
||||||
@@ -296,8 +330,8 @@ public class MqttMessagingPlugin implements MessagingPlugin {
|
|||||||
log.debug("[MqttPlugin] Received message on topic: {}", topic);
|
log.debug("[MqttPlugin] Received message on topic: {}", topic);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if it's an ACK message
|
// Check if it's an ACK message (topic ends with /ack)
|
||||||
if (topic.startsWith("/ack/server/")) {
|
if (topic.startsWith("/server/") && topic.endsWith("/ack")) {
|
||||||
handleAckMessage(topic, payload);
|
handleAckMessage(topic, payload);
|
||||||
}
|
}
|
||||||
// Check if it's a client message
|
// Check if it's a client message
|
||||||
@@ -317,7 +351,7 @@ public class MqttMessagingPlugin implements MessagingPlugin {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle ACK message from client.
|
* Handle ACK message from client.
|
||||||
* Topic format: /ack/server/{messageId}
|
* Topic format: /server/{messageId}/ack
|
||||||
*/
|
*/
|
||||||
private void handleAckMessage(String topic, byte[] payload) {
|
private void handleAckMessage(String topic, byte[] payload) {
|
||||||
if (ackHandler == null) {
|
if (ackHandler == null) {
|
||||||
@@ -325,10 +359,10 @@ public class MqttMessagingPlugin implements MessagingPlugin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract messageId from topic
|
// Extract messageId from topic: /server/{messageId}/ack
|
||||||
String[] parts = topic.split("/");
|
String[] parts = topic.split("/");
|
||||||
if (parts.length >= 4) {
|
if (parts.length >= 4) {
|
||||||
String messageId = parts[3];
|
String messageId = parts[2]; // messageId is at index 2
|
||||||
log.debug("[MqttPlugin] Routing ACK for message: {}", messageId);
|
log.debug("[MqttPlugin] Routing ACK for message: {}", messageId);
|
||||||
ackHandler.onAckReceived(messageId, payload);
|
ackHandler.onAckReceived(messageId, payload);
|
||||||
} else {
|
} else {
|
||||||
@@ -338,11 +372,26 @@ public class MqttMessagingPlugin implements MessagingPlugin {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle client message.
|
* Handle client message.
|
||||||
* Topic format: /server/{clientId}/{messageType}
|
* Topic format: /server/{clientId}/{messageType} or /server/{messageType} (for login)
|
||||||
*/
|
*/
|
||||||
private void handleClientMessage(String topic, byte[] payload) {
|
private void handleClientMessage(String topic, byte[] payload) {
|
||||||
// Extract clientId and messageType from topic
|
// Extract clientId and messageType from topic
|
||||||
String[] parts = topic.split("/");
|
String[] parts = topic.split("/");
|
||||||
|
|
||||||
|
// Handle /server/login (without clientId)
|
||||||
|
if (parts.length == 3 && "login".equals(parts[2])) {
|
||||||
|
String messageType = parts[2];
|
||||||
|
ClientMessageHandler handler = messageHandlers.get(messageType);
|
||||||
|
if (handler != null) {
|
||||||
|
log.debug("[MqttPlugin] Routing login message (type: {})", messageType);
|
||||||
|
handler.onMessageReceived(null, payload);
|
||||||
|
} else {
|
||||||
|
log.warn("[MqttPlugin] No handler registered for message type: {}", messageType);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle /server/{clientId}/{messageType}
|
||||||
if (parts.length >= 4) {
|
if (parts.length >= 4) {
|
||||||
String clientId = parts[2];
|
String clientId = parts[2];
|
||||||
String messageType = parts[3];
|
String messageType = parts[3];
|
||||||
|
|||||||
@@ -7,19 +7,12 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SecurityConfig extends VaadinWebSecurity {
|
public class SecurityConfig extends VaadinWebSecurity {
|
||||||
|
|
||||||
@Bean
|
|
||||||
public PasswordEncoder passwordEncoder() {
|
|
||||||
return new BCryptPasswordEncoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
// Konfiguriere zusätzliche öffentliche Endpunkte vor der Basis-Konfiguration
|
// Konfiguriere zusätzliche öffentliche Endpunkte vor der Basis-Konfiguration
|
||||||
|
|||||||
Reference in New Issue
Block a user