Socket.io Room-based Server
This is a small JavaScript boilerplate for quickly enabling multi-room functionality for socket.io servers.
Functionality
Single server can host multiple user-created rooms.
Rooms can:
- Be named.
- Be public/private.
- Be password protected.
- Be limited to a max number of users.
Rooms provide functionality for:
- Messaging.
- Kicking.
- In-room logic, e.g. a game server hosting multiple rooms, each of which are running a game of poker.
Clients, when connecting to the server, are prompted to register a username. Clients can't do anything without registering.
Clients can then join/create a room. A list of public rooms is accessible, and rooms are joined using the room's name. Room names are unique. Private rooms are not listed in the public list. Rooms can also be password protected, clients are prompted for room passwords after a join call is made.
Quick Start
Install the package using npm i @yacoubb/socket.io-rooms
.
Import it into your project: const {clientFactory, toRoomServer, codes} = require('socket.io-rooms')
or import {clientFactory, toRoomServer, codes} from 'socket.io-rooms'
Client
The clientFactory
function accepts an object containing the configuration of the client. This configuration object requires the properties: port : number, appId : string, serverAddress : string, usernameMinLength : number, usernameMaxLength : number
.
The client, returned by the factory function, contains many components used to effectively 'inherit' from the base, roomy client.
New commands can be registered using client.registerCommands({...newCommands})
. The architecture of commands is described in the next section.
Certain callbacks must be registered to use the client. When the server requests a password or extra information when creating rooms, a callback is fired. These can be registered using client.registerPasswordCallback(callback)
and client.registerRoomInfoCallback(callback)
. The callback
parameters simply need to be async functions that return the user's input for a room password or information about the room the user is creating. Details about the return types of these functions are explored in the next section.
Server
The toRoomServer
function transforms an existing socket.io server into a room based one. Similar to clientFactory
, it's first parameter is the same config object. The second parameter is the io
server that you want to roomify.
toRoomServer
in turn returns some helper functions: roomOf(socket), playersOf(room)
, which find the room object that a given socket is connected to and the list of players connected to a room object, respectively.
New server events can be defined in the normal fashion using io.on
and socket.on
. Note that a roomified server makes use of io.use middleware to check if a socket is verified, registered and connected to a room before processing any commands. This means that any additional socket.on
events defined by you assume that the client is already connected to a room.
Architecture
Commands
All client commands are exposed in the commands
property on a client.
Client commands are always asynchronous (if they require a socket.emit
call). Every call to socket.emit
provides as the last parameter an acknowledgement function. The parameters of the ack
function are almost always of the form (success, data
). success
indicates if the command was successful, and data
contains any response - if the command was unsuccessful then data
always contains the error code associated with the command failure. The general pattern for using client commands, then, is: const result = await command(parameters).catch(client.logErrorCode)
.
Error/Event Codes
info
events and error
messages are broadcast using error codes rather than transmitting the entire message itself. Default codes are defined in codes.js
.
Error codes are written in the form ERR_{TYPEOFERROR}
e.g. ERR_NOTINROOM
means the reason that the client's request failed is because it is not in a room. Error codes are sent in error
socket.io events, and in ack
responses when a request fails (success === false
).
Event codes are written in the form EVENT_{TYPEOFEVENT}
e.g. EVENT_PLAYERJOINED
means a player joined the room that the client is in. Event codes are sent in info
socket.io events.
Callback Registering
Two callbacks must be registered to use the client. When the server requests a password to join a room, or extra information when creating rooms, a callback is fired. These can be registered using client.registerPasswordCallback(callback)
and client.registerRoomInfoCallback(callback)
.
The callback
parameters simply need to be async functions that return the user's input for a room password or information about the room the user is creating.
registerPasswordCallback
expects an async function that returns a string - the password of the room that the client is attempting to join.
registerRoomInfoCallback
expects an async function that returns an object with the properties: {roomName : string, maxPlayers: number, password: string, public : boolean}
- the properties of the room that the client is attempting to create.
Socket.io exposure
Client socket.io events (such as info
and error
) are accessed through the standard socket.on
functionality provided by socket.io. The client socket
object is returned from client.js
to allow for this. Client socket.io events include:
-
handshake
- called when the client first connects to the server. Client and server exchange a uniqueappid
(can be any string) to ensure the client and server are connected correctly. -
info
- emitted by the server on certain events. Events are defined by the event code used. These are constants, defined incodes.js
. e.g. when a player leaves a room, the server broadcasts to that room: 'info',EVENT_PLAYERLEFT
, {username of the player that left}. -
message
- emitted when a player in this room sends a message. -
kicked
- emitted when the client is kicked from a room. -
disconnect
- emitted when the client disconnects from the server. -
error
- called when an error occurs.
Details about the parameters of these events can be found in server.js
and client.js
.
Logging
Clients can also set different locations to log messages to using setLogger
. By default, messages and errors are logged to console.log
and console.error
. Messages are colored using ANSI escape codes; you may have to remove these using a library such as strip-ansi.