Skip to content

Commit

Permalink
client: add todos & docs regarding state handling needing improvement 📝
Browse files Browse the repository at this point in the history
  • Loading branch information
derhuerst committed Sep 17, 2024
1 parent 5fa19fe commit 0ace9f3
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 2 deletions.
18 changes: 16 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ const SECOND = 1000
const MINUTE = 60 * SECOND
const HOUR = 60 * MINUTE

const DFI_DEFAULT_SUBSCRIPTION_TTL = 1 * HOUR,
const AUS_DEFAULT_SUBSCRIPTION_TTL = 1 * HOUR,

const waitFor = async (ms, abortSignal) => {
await new Promise((resolve) => {
const timer = setTimeout(resolve, ms)
Expand Down Expand Up @@ -149,6 +152,7 @@ const createClient = (cfg, opt = {}) => {
// > 5.1.1 Überblick
// > Eine AboID ist innerhalb eines jeden Dienstes eindeutig.
const getNextAboId = () => String(10000 + Math.round(Math.random() * 9999))
// todo: "Wird eine AboAnfrage mit einer AboID gestellt und es existiert bereits ein Abonnement unter dieser Bezeichnung, so wird das bestehende Abonnement überschrieben." – warn about this? does it apply across services?
// todo: persist AboIDs across client restarts, reinstate fetch timers after restarts?
// service -> AboID -> subscriptionAbortController
const subscriptions = Object.fromEntries(
Expand Down Expand Up @@ -192,6 +196,10 @@ const createClient = (cfg, opt = {}) => {
// todo: provide AktiveAbos if `clientStatusAnfrage.$.MitAbos` has value `true`
// > 5.1.8.3 ClientStatusAnfrage
// > Beispiel 3: Antwort des Clients: Dienst verfügbar, Client initialisiert gerade und will keine Auskunft zu den aktiven Abonnements geben:
// > 5.1.8.3 ClientStatusAnfrage
// > […]
// > Stellt der Server einen Unterschied zwischen seiner Abonnementliste und der Liste vom Client, kann der Server entweder stillschweigend den Unterschied beseitigen indem er die nicht aus der Clientsicht aktiven Abonnements löscht und die aus der Clientsicht aktiven Abonnements registriert und anfängt für diese Daten bereitzustellen oder er setzt den StartDienstZst in seiner StatusAntwort auf die aktuelle Zeit und erzwingt somit die Neuinitiali- sierung des Clients. Der zweite Weg wird empfohlen.
// > Ist die Struktur AktiveAbos leer, hat der Client keine aktiven Abonnements. Falls der Server doch welche kennt, sollen diese stillschweigend deaktiviert werden.
],
})
})
Expand Down Expand Up @@ -226,6 +234,8 @@ const createClient = (cfg, opt = {}) => {
// todo: otherwise warn-log unexpected tag?
}
}
// todo: send StatusAnfrage periodically, to detect server hiccups
// > Verliert der Server seine Abonnement-Daten, so ist dies zunächst vom Client aus nicht fest- stellbar. DatenBereitAnfragen bleiben zwar aus, aber dies kann nicht vom normalen Betrieb unterschieden und somit der Absturz des Servers nicht festgestellt werden. Um diesen Fall zu erkennen, sind zusätzliche, zyklische Anfragen vom Typ StatusAnfrage (5.1.8.1) zum Server zu senden. Innerhalb der StatusAntwort (5.1.8.2) gibt der Server den Zeitstempel des Dienststarts an. Fand der Dienststart nach der Einrichtung der Abonnements statt, so muss vom Verlust der Abonnements ausgegangen werden. Es ist nun zu verfahren wie beim Client-Datenverlust: Löschen und Neueinrichtung aller Abonnements.

// ----------------------------------

Expand All @@ -248,6 +258,8 @@ const createClient = (cfg, opt = {}) => {
for await (const [tag, el] of tags) {
if (tag === BESTAETIGUNG) {
assertBestaetigungOk(el)
// todo: warn if DatenGueltigBis < aboParams.VerfallZst?
// > (optional) Ende des Datenhorizontes des Datenproduzenten. Entfällt, wenn Anfrage vollständig im Datenhorizont liegt.
return el
}
// todo: otherwise warn-log unexpected tag?
Expand All @@ -261,6 +273,8 @@ const createClient = (cfg, opt = {}) => {
`invalid/unknown tag of root sub element for service "${service}"`
)
const aboSubTag = ABO_ANFRAGE_ROOT_SUB_TAGS_BY_SERVICE.get(service)
// todo: handle BigInt?
ok(Number.isInteger(expiresAt), 'expiresAt must be a UNIX timestamp')

const aboId = getNextAboId()
const logCtx = {
Expand Down Expand Up @@ -546,7 +560,7 @@ const createClient = (cfg, opt = {}) => {
hysterese,
fetchInterval,
} = {
expiresAt: Date.now() + HOUR,
expiresAt: Date.now() + DFI_DEFAULT_SUBSCRIPTION_TTL,
linienId: null,
richtungsId: null,
vorschauzeit: 10, // minutes
Expand Down Expand Up @@ -625,7 +639,7 @@ const createClient = (cfg, opt = {}) => {
hysterese,
fetchInterval,
} = {
expiresAt: Date.now() + HOUR,
expiresAt: Date.now() + AUS_DEFAULT_SUBSCRIPTION_TTL,
// linienId: null,
// richtungsId: null,
vorschauzeit: 10, // minutes
Expand Down
6 changes: 6 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ npm install OpenDataVBB/vdv-453-client

## Usage

> [!IMPORTANT]
> While `vdv-453-client` is used in a production system at VBB, it hasn't been tested with other VDV-453/-454 systems.
### Leitstellenkennung

With the organisation providing the VDV 453 API, you will have to agree upon your client's *Leitstellenkennung*, which – a bit like an HTTP User-Agent – allows the server to identify your client:
Expand Down Expand Up @@ -138,6 +141,9 @@ data.on('aus:IstFahrt', (istFahrt) => {
})
```

> [!WARNING]
> Currently, `vdv-453-client` has some shortcomings in the handling of subscriptions; For example, it does not persist the information about its subscriptions, and it does not respond to the server with its active subscriptions (`AktiveAbos`) when asked. Refer to the [tracking Issue #3](https://github.com/OpenDataVBB/vdv-453-client/issues/3) for more details.

## Related

Expand Down

0 comments on commit 0ace9f3

Please sign in to comment.