ttfm-socket
v1.7.6
Published
Welcome to the Hangout FM Socket Client! This package provides a TypeScript client to communicate with rooms on Hangout FM.
Downloads
539
Readme
Hangout FM Socket Client
Welcome to the Hangout FM Socket Client! This package provides a TypeScript client to communicate with rooms on Hangout FM.
Installation
npm install ttfm-socketJoining a Room
To join a room, you'll need to retrieve the UUID for that room using this endpoint. Then create an instance of the SocketClient and run the joinRoom method:
import { SocketClient } from "ttfm-socket";
const client = new SocketClient("https://socket.prod.tt.fm");
const token = "{your Hangout FM JWT}";
const { state } = await client.joinRoom(token, {
roomUuid: "{room uuid}",
password: "{optional room password}",
});Assuming you are allowed to join the room (e.g. it's not full, the password is correct, etc.), joinRoom will resolve with an object containing state, an object representing the current room state. In this response, allUserData will be an empty object, to be filled in later (see updatedUserData). If your join request is rejected for any reason, joinRoom will throw an error.
Events
When the SocketClient receives a message broadcast from the server, it emits a corresponding event, which can be listened to.
serverMessage
This is emitted on all messages broadcast from the server. The value emitted here is the full message object, which contains both our custom message as well as other values such as messageId and sentAt.
statefulMessage
This is emitted when the SocketClient receives a server message that contains statePatch. The value emitted here is only our custom message without any of the extra values. The type of the message is narrowed so that the listener knows that statePatch will exist.
statelessMessage
This is emitted when the SocketClient receives a server message that contains params instead of statePatch. The value emitted here is only our custom message without any of the extra values. The type of the message is narrowed so that the listener knows that params will exist.
error
This is when the Primus connection has an error, or when the server returns an error after trying to run an Action. The value emitted here is a string error message, or potentially undefined if there is no error message available.
Connection States
There are four possible events here: connected, disconnected, reconnecting, and timeout. These are emitted when the connection state changes. There is no value emitted with these, so the listener will have 0 arguments.
Listening for Messages
Once a room has been joined, you should attach listeners to the SocketClient to handle incoming messages. To compute the state updates, we recommend the fast-json-patch package.
import { applyPatch } from "fast-json-patch";
client.on("statefulMessage", (message) => {
const newState = applyPatch(
prevState,
message.statePatch,
true,
false,
).newDocument;
// Save the new state
});
client.on("statelessMessage", (message) => {
// Respond to the message based on its name and params
});Listeners can also be added for specific messages:
client.on(ServerMessageName.kickedFromRoom, () => {
// Clear local state and destroy the client
});Actions
When a client wants to make some sort of update to the room, it can do so with the action method in the SocketClient class. Documentation for these actions can be found here. For example, to take the stage in a room a client would run the addDj action:
client.action<AddDjAction>(ActionName.addDj, { song: { ... } })In this case, song is optional but should match the type MinimalCrateSongResDTO.
Messages
After a client or the server successfully runs an action in a room, the server will broadcast a message to every client connected to that room, including the one that ran the Action. As a convention, the names of these messages take the past-tense form of the name of the Action that spawned them. For example, the addDj Action correlates to the addedDj server message.
Stateful Messages
Most of the messages sent by the server come after some sort of room state update. For these, the message will take this shape:
{
name: StatefulServerMessageNameType;
statePatch: Operation[];
}statePatch is a JSON-encoded series of operations for the client to perform in order to update its local state to stay in sync with the server. This adheres the JSON Patch format.
These are all of the stateful messages:
updatedUserData
Sent to the server after a client successfully joins a room, only to that single client. This will contain a statePatch that fills in the allUserData piece of the client state, which is not included in the initial state sent in response to the joinRoom action.
userJoined
Sent by the server to all clients when a user joins the room. This comes after a client successfully runs the joinRoom Action and is added to the Actionhero chatRoom.
userLeft
Sent by the server to all clients when a user leaves the room. When a client sends the Actionhero roomLeave message, or when its connection is closed, we enqueue a 20-second delayed Task. If the user has no active connections after that delay, the server will broadcast this userLeft message.
addedDj
Sent by the server to all clients when a user has been successfully added to the DJ lineup. This comes after a client runs the addDj Action.
removedDj
Sent by the server to all clients when a user has been successfully removed from the DJ lineup. This comes after a client or server runs the removeDj Action.
playedSong
Sent by the server to all clients when nowPlaying changes. This can be triggered by add/removing DJs, skips, kicks, bans, and the current song ending. This same message is sent when there is no next song to play, in which case nowPlaying will be null. The only Action that broadcasts this message is playSong.
updatedNextSong
Sent by the server to all clients when a DJ updates their next song via the updateNextSong Action. This might be followed by the playedSong message, but only if a DJ sends a non-null song and there isn't already something playing.
votedOnSong
Sent by the server to all clients when a user updates their song votes via the voteOnSong Action. This currently handles likes/dislikes and stars. The client state will have per-user voting information, as well as a computed vibeMeter value and an allVotes object that contains arrays of user UUIDs for each type of vote.
lookedUpSong
Sent by the server to all clients after a successful song lookup. This happens if a client sends a song placeholder with the addDj or updateNextSong Actions. It's unlikely the clients will need to do anything in response to this message, but it exists to keep the client state in sync with the server state to avoid errors on subsequent patches.
Stateless Messages
If a message does not accompany a room state update, the shape is slightly different:
{
name: StatelessServerMessageNameType;
params?: StatelessServerMessageParams;
}These are all of the stateless messasges:
playedOneTimeAnimation
Sent by the server to all clients when a user sends a one-time animation. For this message, params takes the following shape:
{
userUuid: string;
animation: OneTimeAnimationType;
emoji?: string;
}emoji here is only defined if animation is OneTimeAnimation.emoji, and will only ever be a string with a single emoji character in it.
kickedFromRoom
Sent by the server only to the connection(s) for one specific user in a room. This indicates that the user was just kicked (or banned). Immediately following this message, the server will close the connection. This message has no params.
roomReset
Sent by the server after someone hits the /resetRoom endpoint for that room. This means that the room's state will be cleared and the server will close all connections that are currenly in the room. In response to this, the clients will need to open a new connection and rejoin the room via the joinRoom Action. This message has no params.
Examples
Support
If you have any questions or feedback about this package, please reach out to us on Discord or at [email protected].
