Make every connected game run a method, the moment you press the button or at a time you set: start maintenance, show a banner, hand out a gift. You define triggers on the dashboard - a name your game has a method for, and the parameters it takes - and send them to everyone, to chosen players, or to a channel, narrowed by a condition if you like.
The stream
A game holds one request open and is handed each message as it is sent. It is Server-Sent Events: plain HTTPS, one text line per field, readable by any HTTP client in any language.
GET /push/stream?environment=production&channels=eu,guild-42&attributes={"platform":"windows"}
Accept: text/event-stream
Authorization: Bearer mgds_... optional: a signed-in player also gets what is sent to them
Last-Event-ID: 41 optional: the last message id it saw, when reconnecting
| Query | |
|---|---|
environment |
The remote config environment; the default one when left out |
channels |
Up to 20 channels it listens on, comma separated: letters, digits, _ - . : |
attributes |
A JSON object, URL-encoded, up to 4096 characters: what conditions are checked against, as for remote config |
lastEventId |
The same as the Last-Event-ID header, for a client that cannot set headers |
Without a token anybody with the project id may connect, and gets what is sent to everyone. A
token that does not work is refused with 401, rather than streaming as nobody: refresh it. When
the site holds as many streams as it can, it answers 503 with Retry-After.
What comes down it:
retry: 3000
event: mgds.connected
data: {"connection":"6f1c...","playerId":null,"environment":"production","channels":["eu"]}
id: 42
event: MaintenanceWarning
data: {"id":42,"trigger":"MaintenanceWarning","arguments":{"message":"Back in 20 minutes","minutes":20},"sentAt":"...","expiresAt":"...","delivery":"sticky"}
: ping
event: mgds.recalled
data: {"id":42,"trigger":"MaintenanceWarning"}
event: mgds.reconnect
data: {"reason":"the token expires; refresh it and connect again"}
- A message's event name is its trigger; its
datais one line of JSON with the typedarguments. mgds.connectedis first, with the connection id for acknowledging.mgds.recalled: a message that went out was recalled. Undo it if the game can (hide the banner).: pingevery 20 seconds while it is quiet. Ignore it; it keeps proxies from closing the line.mgds.reconnect: the stream ends on purpose - when a signed-in player's token expires, and at the latest after an hour. Connect again, with the last id.
Names starting mgds. are MGDS's own; a trigger can never have one.
Catching up, sticky and live
Reconnect with the last id you saw (the Last-Event-ID header, which every SSE client sends by
itself) and you are handed every message for you after it that still stands, before anything new.
A dropped connection, a server restart or a deploy loses nothing.
Every message is one of two kinds, chosen when it is sent:
- Sticky: a game that connects while it lasts gets it too, even without a last id. "Maintenance at 20:00" reaches a game started at 19:55.
- Live: only the games connected when it goes out, and those catching up with a last id. "Double XP starts now" is not news an hour later.
A signed-in player is not handed the same sticky message twice, on any device. A game nobody is
signed in to gets the sticky ones again each time it connects without a last id: keep the last id
and send it. Delivery is at least once; a message's id never repeats, so skip one you have seen.
A message stops being handed out when it expires (an hour after it goes out, unless the sender says otherwise, at most 30 days) or is recalled.
Who gets it
- Everyone connected to the environment. Untick "signed-out games too" for signed-in players only.
- Chosen players, by player id, up to 1000. Only their own signed-in games get it.
- A channel: every game that listed it in
channels. A guild, a match, a region. To join one, reconnect with the new list. - A condition, on top of any of those: the same language as remote config rules, on the
attributesthe game connected with.platform == "windows" && app.version < "1.2".
Acknowledging
When the game has run a message, it can say so. The dashboard counts it.
POST /push/messages/{id}/ack { "connection": "6f1c..." } -> 204
Or, for a signed-in player, with their token and no body - for a message any of their games was handed.
A player's history
GET /me/push?limit=50&before={id} Authorization: Bearer mgds_...
-> { "results": [ { "id", "trigger", "arguments", "sentAt", "expiresAt", "delivery", "receivedAt", "acknowledgedAt", "recalledAt" } ] }
Every message the player's games were handed, newest first: for an inbox, or after a reinstall.
On the dashboard
Push messages lists the triggers (Add trigger, the pen to change or delete one), a Send button on
each with the arguments, who gets it, when and for how long, and every message sent: its status
(scheduled, live, expired, recalled, cancelled), how many games were connected when it went
out, how many got it since, and how many said they ran it. A scheduled message can be cancelled, and
a live one recalled.