Constellation is a daemon whose purpose is to unite all stateful functions of mixer.com.

One of its main features is liveloading.

Liveloading

Liveloading is an event system on Mixer. When models update, users follow channels, or anything else happens that clients might want to be aware of an event is sent. Users must subscribe to Events to recieve them.

Pro tip: you can view liveloading in-action by viewing your websocket log on mixer.com.

Clients

A number of clients already support Constellation. Try them out for a jump start into Constellation.

Session

Users authenticate to Constellation by sending their existing cookies or authentication details in socket headers. No external API are endpoints needed.

Users remain connected to Constellation throughout their session. During the session, they may subscribe to events happening on the site and get notifications when those events occur.

Protocol

Constellation is based on JSON-RPC with additional support for an event system. Initially a user connects to constellation.mixer.com with a standard WebSocket connection. Aside from standard websocket headers, the following headers may also be passed:

  • cookie: may contain the Mixer session cookie. Its presence will cause Constellation to attempt to authenticate the user.
  • authorization: may contain an OAuth Bearer token to authenticate with for 3rd party apps, rather than using a cookie. This will indicate to Constellation that the user is a bot.
  • x-sec-websocket-protocol: if set to cnstl-gzip, Constellation may choose to send websocket frames down as binary, gzipped JSON rather than plain text. Passing this is generally handled by websocket clients themselves, and are usually configured by specifying a preferred subprotocol.

    The client may detect gzipped frames by the fact that they are binary messages and begin with the magic bytes 0x1f and 0x8b as the first and second payload byte, respectively.

  • x-is-bot: this must be set to true if the client is an automated bot rather than a human user and you are not using an authorization header. Failure to set this may cause the account to be banned.

Packets

There are three packet types: method, reply, and event. These are sent over the websocket as JSON encoded messages. Messages to the client may be gzipped if x-supports-gzip was passed in the headers, messages sent to Constellation are always allowed to be gzipped.

Method

Method packets are sent from the client in a way very similar to JSON-RPC. This is the only packet the client may send to the server. A method may look like the following:

{"type": "method", "method": "divide", "params": {"numerator": 16, "denominator": 4}, "id": 123}
  • type is always set to "method"
  • method should be the name of the method to call
  • params should be an object, not an array, of named arguments to pass into the method.
  • id may be any uint32. It’s included in the reply packet and used to correlate replies from the socket. You should ensure that each request has a unique id within your session.

Reply

Reply packets are sent in response to method packets. Replies are always sent in response to methods unless the socket closes before they may be sent. Some reply packets may look like the following:

{"type": "reply", "result": 4, "error": null, "id": 123}
{"type": "reply", "result": null, "error": {"code": 1000, "message": "Cannot divide by zero"}, "id": 124}
  • type is always set to "reply"
  • id is set to the id passed in the corresponding method packet
  • result is the unstructured result of the method, or null
  • error is an error which occurred, or null. If present it will always contain a "code" and an associated "message"

    Note that if fatal errors occur as a result of a method call, a websocket close frame will be sent instead of a reply. The close frame’s code and associated message will be the same as that which otherwise would have been sent in reply.error.

Event

Event packets are sent when an action occurs which a client as asked to be notified about. Event packets look like the following:

{"type": "event", "event": "math_result", "data": 4}
  • type is always set to "event"
  • event is the string name of the event
  • data is unstructured information associated with the event. Usually this is the same as found within the liveloading/sails event of the same type.

Error Codes

Constellation uses the 4xxx error code range reserved for use by applications in addition to the standard 1xxx codes. The following codes are in use:

  • 1011 - Sent in a close or method reply if an unknown internal error occurs.
  • 1012 - Sent in a close frame when we deploy or restart Constellation; clients should attempt to reconnect.
  • 4006 - Error parsing payload as JSON
  • 4007 - Error decompressing a supposedly-gzipped payload
  • 4008 - Unknown packet type
  • 4009 - Unknown method name call
  • 4010 - Error parsing method arguments (not the right type or structure)
  • 4011 - The user session has expired; if using a cookie, they should log in again, or get a bearer auth token if using an authorization header.
  • 4106 - Unknown event used in a livesubscribe call
  • 4107 - You do not have access to subscribe to that livesubscribe event
  • 4108 - You are already subscribed to that livesubscribe event (during livesubscribe)
  • 4109 - You are not subscribed to that livesubscribe event (in response to a liveunsubscribe method)

Methods

livesubscribe

A livesubscribe method allows users to subscribe to liveloading events.

{"type": "method", "method": "livesubscribe", "params": {"events": ["user:1:update", "channel:1:followed"]}, "id": 42}
  • events is an array of events to subscribe to. Note that either all events are successfully subscribed to, or a failure occurs and no events are subscribed to. Either do or do not, there is no try.

A livesubscribe reply looks like one of the following:

  • A successful reply:
  • {"type": "reply", "result": null, "error": null, "id": 42}
  • A reply with an invalid event:
  • {"type": "reply", "result": null, "error": {"code": 4106, "message": "Unknown event \"my silly event\" "}, "id": 42}
  • A reply for an event you do not have permission to see:
  • {"type": "reply", "result": null, "error": {"code": 4107, "message": "You do not have permission to subscribe to \"user:1:secrets\""}, "id": 42}
  • A reply for an event you are already subscribed to:
  • {"type": "reply", "result": null, "error": {"code": 4108, "message": "Attempt to duplicate subscription to \"user:1:update\""}, "id": 42}

liveunsubscribe

A liveunsubscribe method can be used to stop listening to previously-subscribed-to events:

{"type": "method", "method": "liveunsubscribe", "params": {"events": ["user:1:update", "channel:1:followed"]}, "id": 42}
  • events is an array of events to unsubscribe from. Note that if you are not subscribed to one or more of the events, no error is returned.

A liveunsubcribe reply looks like the following:

{"type": "reply", "result": null, "error": null, "id": 42}

ping

A ping method should be used in environments where websocket implementations do not natively support pings.

{"id":1,"type":"method","method":"ping","params":null}

A ping reply is a blank reply packet with a matching id.

{"id":1,"type":"reply","result":{},"error":null}

Events

hello

A hello event is sent down to the client when they first connect.

{"type": "event", "event": "hello", "data": {"authenticated": true}}
  • authenticated is true if the session is authenticated as a user.

live

A live event looks like the following. Do note the socket event names are not liveloading events. Events you ask for over liveloading are always "live" events which contain the liveloading information. This separation is added so that other kinds of events can be distinguished from liveloading events.

{"type": "event", "event": "live", "data": {"channel": "user:1:update", "payload": {"sparks": 10000}}

Live Event Types

The following live events are available to subscribe to.

Event Description
⁠⁠⁠⁠announcement:announce

Sent when there is a site-wide announcement. The message property of the body contains the announcement text. Other fields affect how the announcement is displayed on mixer.com

channel:{id}:followed

Sent when a user follows or unfollows a channel. The body will contain an attribute following - boolean set to true true if the user just followed the channel, false if they unfollowed, and user - the User who just followed the channel.

channel:{id}:hosted

Sent when another user hosts the channel with the provided id. The body will contain the hosterId, a number, and hoster, the full Channel model who started hosting this channel. Note that this event is not subject to the spam prevention that the chat message is.

channel:{id}:unhosted

Sent when another user finishes hosting the channel with the provided id. The body will contain the hosterId, a number, and hoster, the full Channel model who finished hosting this channel. Note that this event is not subject to the spam prevention that the chat message is.

channel:{id}:status

Subscribes to the online status of a channel. You'll get events sent down named chat:{id}:StartStreaming and chat:{id}:StopStreaming.

channel:{id}:subscribed

Sent when a user subscribes to the channel. The body will contain the User object who just subscribed to the channel.

channel:{id}:resubscribed

Sent when an automatic resubscription to a channel happens. The body will contain the User object of the channel the user just resubscribed to. Additionally there are since and until properties. These are the dates for when the user first subscribed (from the start of recurring billing period) and when the subscription expires. Finally there's a totalMonths property, which is an integer indicating how many months the user has been subscribed since the beginning of time.

channel:{id}:resubShared

Sent when a user who has recently resubscribed to the channel chooses to 'share' their resubscription, by clicking the 'Share' button within the site chat. This event is preferred to the channel:{id}:resubscribed event if your integration reacts with some form of celebration, but you should be aware that this event will not fire at all for a resubscription if the user does not choose to share it. The body is identical to that of the channel:{id}:resubscribed event.

channel:{id}:update

You'll get an event sent down that matches the slug, containing changes on the Channel model. The event may not necessarily include the entire channel resource. For example, when a channel goes online, an event with the key online going to true is sent.

interactive:{id}:connect

Sent when an interactive app connects to this channel

interactive:{id}:disconnected

Sent when an interactive app disconnects from this channel

team:{id}:deleted

Sent when a Team is deleted. The body will contain the team's old record.

team:{id}:memberAccepted

Sent when an invitee accepts their team invitation. The body will contain the accepting user's record.

team:{id}:memberInvited

Sent when a member is invited to a team. The body will contain the invited user's record.

team:{id}:memberRemoved

Sent when a team member leaves or invitee rejects their invite. The body will contain the member's User record.

team:{id}:ownerChanged

Sent when a team's ownership changes. The body will contain the new owner's User record.

user:{id}:achievement

Sent when a user achievement earning is updated. The body is simply an AchievementEarning record as returned in the achievement user listing endpoint.

user:{id}:followed

Sent when a user follows or unfollows a channel. The body will contain an attribute following - boolean set to true true if the user just followed the channel, false if they unfollowed, and user - the User who just followed the channel.

user:{id}:notify

Sent when a new user Notification is created. Notifications of the same type will always follow the same structure.

user:{id}:subscribed

Sent when the user subscribes to a channel. The body will contain the channel ID that they just subscribed to.

user:{id}:resubscribed

Sent when an automatic resubscription to a channel happens. The body will contain the Channel id of the channel the user just resubscribed to. Additionally there are since and until properties. These are the dates for when the user first subscribed (from the start of recurring billing period) and when the subscription expires. Finally there's a totalMonths property, which is an integer indicating how many months the user has been subscribed since the beginning of time.

user:{id}:teamAccepted

Sent when a user accepts their invite to a team. The body will contain the Team record related to the event.

user:{id}:teamInvited

Sent when a user is invited to a team. The body will contain the Team record related to the event.

user:{id}:teamRemoved

Sent when a user leaves a team or rejects its invite. The body will contain the Team record related to the event.

user:{id}:update

You'll get an event sent down that matches the slug, containing changes on the User model. The event may not necessarily include the entire user resource.

Need more help?

If you're still not sure, or would like some help, hit us up on Gitter!