Hub-Daten - Entwickler
Ziel der Struktur
Die Datenstruktur in ce.hub.data trennt fachlichen Zustand, EEP-Zugriff und Veröffentlichung bewusst voneinander.
Für dynamische CeTypes ist die gewünschte Rollenverteilung:
Domain: Zustand, Getter/Setter, Dirty-TrackingRegistry: zentrale Map der bekannten Objekte nach IDDiscovery: erkennt neue und entfernte ObjekteUpdater: entscheidet, welche Felder aktualisiert werden, und ruftpullX()auf Domain-ObjektenPublisher: sendet Add/Change/Remove-Events und wertet Sync-Optionen ausDtoFactory: baut serialisierbare DTOs
Einfachere Singleton-CeTypes wie Zeit, Wetter oder Version nutzen meist nur den kleineren Ausschnitt Registry + Updater + Publisher, folgen aber denselben Zuständigkeitsgrenzen:
- Der
Updatertrifft die Einscheidungen, dass Daten geladen werden sollen; EEP-Lesezugriffe erfolgen mit denpullX()-Methoden der Datenklassen - Sync-Logik liegt im
Publisher
Daten-Fassaden und EEP-Zugriff
Die aktiven Datenklassen in ce.hub.data sind Fassaden vor dem EEP-Zustand. Sie halten die zuletzt bekannten Werte im Lua-Objekt, reduzieren direkte EEP*Get*- und EEP*Set*-Aufrufe und markieren geänderte Felder für die Veröffentlichung.
Die Grundregeln sind:
*Discoveryfindet neue oder entfernte Objekte.initFromAnl3(tableOfAnl3)liest bereits geparste Anlagendaten aus der einmal geladenen.anl3-Struktur und befüllt Objekte nur überseed*-Methoden. Ist eine Domain in der.anl3-Erkennung enthalten, werden nur die dort gefundenen Objekte behalten. Ohne.anl3-Erkennung nutzt die Discovery die bisherigen Suchmechanismen und günstige Existenzprüfungen wieSignal.exists(id),Switch.exists(id),Structure.exists(name),Train.exists(name)oderRollingStock.exists(name).*Updaterentscheiden nur, welche Werte gerade aktualisiert werden sollen. Sie rufenpullX()auf den Datenobjekten auf und enthalten auf dem aktiven Pfad keine direktenEEP*Get*-Aufrufe.- Jede Objekt-Domain besitzt eine Registry mit Lookup über die Pflicht-ID. Train und RollingStock teilen sich intern den gekoppelten
TrainRollingStockStore; die KompatibilitätsmoduleTrainRegistryundRollingStockRegistrybleiben trotzdem die öffentlichen Einstiege. *DtoFactoryund*Publisherhalten die bestehenden DTO-Verträge stabil. Sie lesen Werte cache-only überpeekX()oder äquivalente cache-only Hilfsfunktionen und lösen keine EEP-Lesezugriffe aus.- Direkte
EEP*Set*-Aufrufe gehören in die passendesetX(...)-Methode der Datenklasse. DirekteEEP*Get*-Aufrufe gehören in die passendepullX(...)-Methode der Datenklasse. Ausnahme sind Discovery-Existenzprüfungen und wenige globale Singleton-Fassaden wie Scenario, FrameData, Weather oder Time. - Alte Collector-Module sollen nicht mehr erweitert oder neu verwendet werden. Wenn sie nur noch von Tests referenziert werden, sind sie Altlasten und können entfernt oder in die Fassade überführt werden.
Für Felder einer Datenklasse gilt dieses Namensschema:
peekX() -- Schaut nur im Cache nach und ruft keine EEP-Funktion auf
getX() -- read-through: nutzt Cache, ruft pullX() nur bei fehlendem Wert
replaceX(...) -- überschreibt Cache, kein EEPSet-Aufruf, dirty nur bei Änderung
seedX(...) -- Discovery-Seed, kein EEPSet, dirty nur bei Änderung
pullX() -- EEPGet -> replaceX -> dirty nur bei Änderung -> Rückgabewerte ohne ok-Flag
setX(...) -- idempotentes EEPSet -> replaceX nur bei akzeptiertem Set
Die Rückgabeform orientiert sich an der EEP-API ohne Erfolgsindikator. Beispiel: EEPStructureGetPosition(name) liefert ok, x, y, z; Structure:getPosition() und Structure:pullPosition() liefern bei Erfolg x, y, z und bei Fehlschlag nil, nil, nil.
setX() und seedX() müssen idempotent bleiben: gleiche Werte verursachen keinen EEP-Aufruf und markieren kein Feld erneut als dirty.
DTO-Konvention: CeTypes und Listen
Alle Daten werden in eine dreistufige Map-Struktur einsortiert:
ceType : string
└─ dtoId : string | number
└─ dto : table
ceTypeist die stabile Typkennung des Datenbereichs, z. B."ce.hub.Train"oder"ce.hub.Signal".dtoIdist ein eindeutiger Schlüssel innerhalb des CeTypes, z. B. der Zugname oder die Signal-ID.dtoist eine flache serialisierbare Tabelle ohne Funktionen.
Ablauf: Wie kommt ein DTO auf den Bus?
CeHubModule.init()startet Initial-Discovery und Initial-Updates.CeHubModule.run()führt die laufende Discovery und die laufenden Updates aus.- Ein
*Publisherbewertet die Sync-Optionen des CeTypes. - Eine
*DtoFactoryserialisiert Domain-Objekte oder Patches in DTOs. - Der Publisher veröffentlicht Änderungen über
DataChangeBus.fire*().
Die historischen *StatePublisher.lua-Dateien sind auf dem aktiven Pfad nur noch dünne Adapter, die Publisher.syncState(...) mit den zugehörigen Optionen aufrufen.
Optionen und Verantwortlichkeiten
Die Sync- und Fetch-Optionen werden auf drei Ebenen angewendet:
- Feld-Ebene:
collect = falseDerUpdaterliest dieses Feld nicht und dieDtoFactorynimmt es nicht in DTOs auf. - CeType-Ebene:
mode = all | none | selectedDasCeHubModuleund diePublisherentscheiden damit, ob ein CeType vollständig, gar nicht oder nur für selektierte Objekte synchronisiert wird. - Publisher-Ebene:
enabled = true | falseDer jeweiligePublisherkann komplett deaktiviert werden.
Discovery und gekoppelte CeTypes
Nicht jeder CeType scannt die Welt unabhängig. Ein wichtiges Beispiel ist der Zugpfad:
TrainDiscoveryerkennt Tracks, Züge und RollingStock-Existenz gemeinsam.TrainUpdateraktualisiert die bekannten Zugobjekte.RollingStockUpdateraktualisiert die bekannten RollingStock-Objekte.TrackPublisher,TrainPublisherundRollingStockPublisherveröffentlichen anschließend ihre Änderungen getrennt.
Damit bleibt die Discovery-Logik zentral, während Registry, Updater und Publisher weiter je CeType getrennt bleiben.
Vollständige DTO-Strukturen
Alle aktiven CeTypes und ihre DTO-Felder sind in DTO.md dokumentiert.
Informationen für Anwender: README.md