Services

Push messages

Make every connected game run a method, now or at a set time.

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 data is one line of JSON with the typed arguments.
  • mgds.connected is 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).
  • : ping every 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 attributes the 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.