General
ActionHero ships with a chat framework which may be used by all persistent connections (socket and websocket). There are methods to create and manage chat rooms and control the users in those rooms. Chat does not have to be for peer-to-peer communication, and is a metaphor used for many things, including game state in MMOs.
Clients themselves interact with rooms via verbs. Verbs are short-form commands that will attempt to modify the connection's state, either joining or leaving a room. Clients can be in many rooms at once.
Relevant chat verbs are:
roomAddroomLeaveroomViewsay
The special verb for persistent connections say makes use of api.chatRoom.broadcast to tell a message to all other users in the room, IE: say myRoom Hello World from a socket client or client.say("myRoom", 'Hello World") for a websocket.
Chat on multiple actionHero nodes relies on redis for both chat (pub/sub) and a key store defined by api.config.redis. Note that if you elect to use fakeredis, you will be using an in-memory redis server rather than a real redis process, which does not work to share data across nodes. The redis store and the key store don't need to be the same instance of redis, but they do need to be the same for all ActionHero servers you are running in parallel. This is how ActionHero scales the chat features.
There is no limit to the number of rooms which can be created, but keep in mind that each room stores information in redis, and there load created for each connection.
Methods
These methods are to be used within your server (perhaps an action or initializer). They are not exposed directly to clients, but they can be within an action.
{'api.chatRoom.broadcast(connection, room, message, callback)'}
- tell a message to all members in a room.
- connection can either be a real connection (A message coming from a client), or a mockConnection. A mockConnection at the very least has the form
{room: "someOtherRoom"}. mockConnections without an id will be assigned the id of 0 - The
contextof messages sent withapi.chatRoom.broadcastalways beuserto differentiate these responses from aresponseto a request
api.chatRoom.list(callback)
- callback will return (error, [rooms])
api.chatRoom.add(room, callback)
- callback will return 1 if you created the room, 0 if it already existed
api.chatRoom.destroy(room, callback)
- callback is empty
api.chatRoom.exists(room, callback)
- callback returns (error, found); found is a boolean
api.chatRoom.roomStatus(room, callback)
- callback returns (error, details); details is a hash containing room information
- details of the form:
{
room: "myRoom",
membersCount: 2,
members: {
aaa: {id: "aaa", joinedAt: 123456789 },
bbb: {id: "bbb", joinedAt: 123456789 },
}
}api.chatRoom.addMember(connectionId, room, callback)
- callback is of the form (error, wasAdded)
- you can add connections from this or any other server in the cluster
api.chatRoom.removeMember(connectionId, room, callback)
- callback is of the form (error, wasRemoved)
- you can remove connections from this or any other server in the cluster
api.chatRoom.generateMemberDetails( connection )
- defines what is stored from the connection object in the member data
- default is
id: connection.id - other data that is stored by default is
host: api.idandjoinedAt: new Date().getTime() - override the entire method to store custom data that is on the connection
api.chatRoom.sanitizeMemberDetails( memberData )
- Defines what is pulled out of the member data when returning roomStatus
- Defaults to
joinedAt : memberData.joinedAt - After method call, always filled with
id, based on theconnection.idused to store the data - Override the entire method to use custom data as defined in
api.chatRoom.generateMemberDetails
api.chatRoom.generateMessagePayload( message )
- Defiens how messages from clients are sanitized
- Override the entire method to use custom data as defined in
api.chatRoom.generateMessagePayload
Middleware
There are 4 types of middleware you can install for the chat system: say, onSayReceive, join, and leave. You can learn more about chat middleware in the middleware section of this site
Specific Clients
Every connection object also has a connection.sendMessage(message) method which you can call directly from the server.
Client Use
The details of communicating within a chat room are up to each individual server (see websocket or socket), but the same principals apply:
- Client will join a room (
client.roomAdd(room)). - Once in the room, clients can send messages (which are strings) to everyone else in the room via
say, ie:{client.say('room', Hello World')} - Once a client is in a room, they will revive messages from other members of the room as events. For example, catching say events from the websocket client looks like
{client.on('say', function(message){ console.log(message); })}. You can inspectmessage.roomif you are in more than one room.- The payload of a message will contain the room, sender, and the message body:
{{message: "Hello World", room: "SecretRoom", from: "7d419af9-accf-40ac-8d78-9281591dd59e", context: "user", sentAt: 1399437579346}}
- The payload of a message will contain the room, sender, and the message body:
If you want to create an authenticated room, there are 2 steps:
- First, create an action which modifies some property eitehr on the connection object it self, or stores permissions to a database.
- Then, create a
joinCallback-style middleware which cheks these values.