Schnellstart
Leitfaden für Publisher und Subscriber im ARD Eventhub.
Dieser Leitfaden hilft dir beim Start in den ARD Eventhub.
Egal, ob du Publisher oder Subscriber bist: Du benötigst ein Benutzerkonto, um mit der API zu interagieren. Fordere ein Konto über deinen Ansprechpartner beim SWR Audio Lab oder ARD Online an.
Nachdem das Konto eingerichtet wurde, lies das Kapitel Authentifizierung, um mehr über Login und den Token-Austausch zu erfahren.
Publisher
Wenn du als Hörfunkanstalt Events in den ARD Eventhub publizieren möchtest, befolge diese einfachen Schritte:
- Richte dein Konto ein, lese und verstehe den Authentifizierungsprozess
- Verwende den POST-Endpoint
/events/{eventName}, um Events zu senden - Hinweis: Auch wenn GET
/topicsdeine Sender noch nicht auflistet, werden die Topics beim ersten veröffentlichten Event automatisch erstellt (die Antwort enthält z.B.):
{
"statuses": {
"published": 0,
"blocked": 0,
"failed": 1,
},
"event": {
"name": "de.ard.eventhub.v1.radio.track.next",
// ...
"services": [
{
"type": "PermanentLivestream",
"externalId": "crid://swr.de/282310/demo7",
"publisherId": "urn:ard:publisher:75dbb3dace15f610",
"topic": {
"id": "urn:ard:permanent-livestream:234690e18c2c7863",
"name": "de.ard.eventhub.dev.urn%3Aard%3Apermanent-livestream%3A234690e18c2c7863",
"status": "TOPIC_CREATED",
"messageId": null,
},
},
],
// ...
},
}
Es wird empfohlen, zunächst das test-System des Eventhub zu nutzen, um alles zu prüfen, bevor du in die Produktion (prod) wechselst. Die Hostnamen findest du im Dokument zu den Stages.
Sicherheits-Hinweis: Jedes Benutzerkonto darf nur zu publisherIds seiner eigenen Institution publizieren. Sofern man einen Fehler zurückbekommt kann die ID falsch sein oder das Benutzerkonto wurde durch einen Admin falsch konfiguriert.
Umgang mit Events aus externen Quellen
Wenn du Eventhub benutzt, um Events aus einer anderen Anstalt zu empfangen (z.B. Nächtliche bundesweite Sendungen) und diese für deinen Sender weiterveröffentlichst, ist es wichtig, die empfangenen Events erneut an den Eventhub zu publizieren.
Das ist essentiell, da deine Abonnenten alle Events deines Senders erhalten müssen – inklusive der von anderen Sendern erneut gesendeten Events. Sie wissen möglicherweise nicht, dass du das Programm von einer anderen Station weiterverbreitest und nutzen lediglich ein Abonnement für deinen Sender, um alle Events zu empfangen.
Für Dienste wie ARD Sounds ist dies wichtig, andernfalls verfügt dein Sender möglicherweise über unvollständige Live-Metadaten, wenn du andere Sender erneut ausstrahlst.
In diesem Fall ist es wichtig, sicherzustellen, dass deine interne Filterung korrekt funktioniert, wenn du Events von anderen Sendern empfängst, und diese nur zu veröffentlichen, wenn der Sender tatsächlich auf Sendung ist. Andernfalls könnte es zu einer Schleife kommen.
Beispiel-Workflow
Ein möglicher Ablauf in deinem System für jedes neue Event könnte so aussehen:
- Prüfe ob dein
token, den du von einem früheren Aufruf hast, noch gültig ist - Falls du keinen Gültigen mehr hast, prüfe ob du noch einen
refreshTokenvon einem früheren Aufruf hast- Falls ja, tausche ihn für einen gültigen
tokenein - Falls nein, logge dich über die API erneut an
- Falls ja, tausche ihn für einen gültigen
- POST das Event im vorgegebenen Format. Das folgende Beispiel kann dir dabei helfen, den Aufbau eines Events zu verstehen:
{
"type": "music",
"start": "2021-03-17T10:04:35+01:00",
"length": 215.2,
"title": "Save your tears",
"artist": "The Weeknd",
"contributors": [
{
"name": "The Weeknd",
"role": "artist",
"normDb": {
"type": "Person",
"id": "12345"
}
}
],
"services": [
{
"type": "PermanentLivestream",
"externalId": "crid://swr.de/282310",
"publisherId": "282310"
}
],
"playlistItemId": "radiomax:SWR3-BAD-MAX:12569153",
"externalId": "M0589810001",
"isrc": null,
"upc": null,
"mpn": null,
"media": [
{
"type": "cover",
"url": "http://my-server/covers/M0589810.001",
"templateUrl": null,
"description": "SWR Cover zu Save your tears von The Weeknd",
"attribution": ""
}
],
"hfdbIds": ["swrhfdb1.KONF.12345"]
}
Subscriber
Wenn du Events anderer Sender empfangen möchtest, trage dich als Subscriber ein und erhalte Echtzeit-POSTs (Webhooks) für alle veröffentlichten Events. Diese können z.B. deine Web- oder App-Angebote während der Wiederholungen in den nächtlichen Sendungen verbessern.
Beachte, dass der Typ der hier veröffentlichten Events in Zukunft erweitert werden kann, filtere deshalb entsprechend. Das Datenformat bleibt abwärtskompatibel, es können jedoch bei Bedarf neue Bereiche zu diesem Dienst hinzugefügt werden.
Bei nächtlichen Sendungen solltest du eine permanente Subscription 24/7 betreiben. Der Filter basierend auf dem Programmplan sollte auf deiner Seite durchgeführt werden. Pub/Sub sollte nicht zum wiederholten Erstellen/Löschen von Subscriptions genutzt werden.
Stelle sicher, dass dein Endpoint aus dem Internet erreichbar ist und ein gültiges SSL-Zertifikat installiert ist. Ist der Endpoint zeitweise nicht erreichbar, sammelt die Subscription vergangene Events und versucht die Zustellung erneut. Siehe dazu auch src/utils/pubsub/create-subscription.ts und cloud.google.com/pubsub/docs/push.
Aktuell ist ein Pull-Workflow für Subscriptions nicht vorgesehen.
Starte mit diesen Schritten:
- Richte dein Konto ein und verstehe den Authentifizierungsprozess
- Verwende GET
/topics, um verfügbare Channels (Topics) zu sehen - Wenn ein Channel nicht sichtbar ist, wurde noch nicht darauf publiziert. Topics entstehen erst beim ersten Senden eines Events.
- Erstelle mit POST
/subscriptionseine Subscription- ACHTE darauf keine localhost oder internen Adressen als URL anzugeben.
- Lese die Google-Dokumentation “Receiving messages using Push” für das Nachrichtenformat
- Verwende GET
/subcriptions, um Subscriptions zu prüfen
Sicherheits-Hinweis: Ein registrierter Benutzer ist einer Institution (Landesrundfunkanstalt) zugeordnet. Benutzer können alle Subscriptions innerhalb ihrer Institution verwalten — lösche keine Produktions-Einträge deiner Kollegen. Mit diesem Workflow hat man weiterhin Zugriff auf alle Abonnements, auch wenn eine Person deinen Sender verlässt, oder dein Konto deaktiviert wird.
Sicherheit
Um sicherzustellen, dass ein Event tatsächlich vom Eventhub stammt, verwende das mitgelieferte JWT-Token und den Service Account.
Die Antwort beim Erstellen einer Subscription enthält u.a. das verwendete Service Account-Feld:
{
// ...
"serviceAccount": "something@something-else.iam.gserviceaccount.com",
// ...
}
Bitte beachte, dass der Service Account derzeit in der Regel dieselbe Antwort enthält. Bei zukünftigen Abonnements kann es jedoch sein, dass ein anderes Konto verwendet wird. Konfiguriere deinen Dienst so, dass für jedes Abonnement das entsprechende Konto überprüft wird.
Beispiel-Receiver
Ein vereinfachtes Beispiel (Node.js mit Express): Die Google Cloud Sektion “Authentication and authorization by the push endpoint” enthält weiterführende Informationen über diesen Prozess.
// load node packages
import { OAuth2Client } from 'google-auth-library'
const authClient = new OAuth2Client()
// set received serviceAccount
const serviceAccountEmail = 'somethin@something-else.iam.gserviceaccount.com'
export default async (req, res) => {
try {
// read token from header
const bearer = req.header('Authorization')
const [_match, idToken] = bearer.match(/Bearer (.*)/) ?? []
if (!idToken) throw Error('No ID token could be found.')
// verify token, throws error if invalid
const verification = await authClient.verifyIdToken({
idToken,
})
// check token email vs. subscription email
if (verification?.payload?.email === serviceAccountEmail) {
// get message and metadata from pubsub body
const { attributes, messageId } = req.body.message
const { subscription } = req.body
let data = Buffer.from(req.body.message.data, 'base64').toString()
data = JSON.parse(data)
// request successful, you can now use the received data
console.log({ attributes, messageId, subscription, data })
// close connection
return res.sendStatus(201)
} else {
// user provided valid token but failed email verification
return res.sendStatus(204)
}
} catch (error) {
// request failed or invalid token
return res.sendStatus(204)
}
}