Socker.js
An easy-to-use websocket library based on Promises with built-in support for heartbeats and storing user data. Built using ws and uuid.
Table of Contents
- Installation
- Examples
-
API Docs
- Class: Socker
-
Class: User
- new User(socket, request)
- Event: .onChange(key[, callback])
- Event: .onReceive([callback])
- Event: .onClose([callback])
- Event: .onError([callback])
- Method: .send(data[, options[, callback]])
- Method: .ping([callback])
- Method: .isAlive()
- Method: .get(key)
- Method: .set(key, value[, readOnly])
- Method: .stop([code, [reason]])
- Method: .forceStop()
- stopListener()
- Versions
- License
Installation
npm i @sloanfinger/socker-js
Examples
Getting Started:
Start by requiring the Socker class:
const { Socker } = require('@sloanfinger/socker-js');
Next, you can create a new Socker, using these options.
const { Socker } = require('@sloanfinger/socker-js');
const socker = new Socker({port: 8080});
Then, you can listen for when users connect.
const { Socker } = require('@sloanfinger/socker-js');
const socker = new Socker({port: 8080});
socker.onConnect((user) => {
});
The user
class is passed to the .onConnect()
callback/Promise, allowing you to listen for user events, store data, and send messages to the user.
const { Socker } = require('@sloanfinger/socker-js');
const socker = new Socker({port: 8080});
socker.onConnect((user) => {
user.send('Hello! What is your name?');
user.onReceive((name, stopListener) => {
stopListener();
user.set('name', name);
user.send(`Hi, ${name}! Nice to meet you!`);
});
});
Using Async/Await
If you want to create long chains/conversations between the server and the user, it's much easier to use Async/Await instead of callbacks.
const { Socker } = require('@sloanfinger/socker-js');
const socker = new Socker({port: 8080});
socker.onConnect(async (user) => { // Now we're working asynchronously!
await user.send('Hello! What is your name?');
let name = await user.onReceive();d
await user.send(`Hi, ${name}! How old are you?`);
let age = await user.onReceive();
await user.send(`Do you have a job? If so, what do you do?`);
let job = await user.onReceive();
await user.send(`That's cool! Do you enjoy it?`);
// To be continued...
});
Storing Data
Data can be attached to users in the form of key-value pairs.
const { Socker } = require('@sloanfinger/socker-js');
const socker = new Socker({port: 8080});
socker.onConnect((user) => {
user.send('Hi! What is your name?');
user.onReceive((name, stopListener) => {
stopListener();
user.set('name', name);
user.send(`Hello, ${ user.get('name') }!`);
});
});
Selecting Users
You can use the .getUsers()
method on the Socker class to select users based on data they have stored or their ID.
const { Socker } = require('@sloanfinger/socker-js');
const socker = new Socker({port: 8080});
socker.onConnect((user) => {
user.send('Hi! How old are you?');
user.onReceive((age, stopListener) => {
stopListener();
user.set('age', age);
user.send(`There are ${ socker.getUsers('age >= 18').length } users who are age 18 or older.`);
});
});
The .getUsers()
method returns an array of user IDs. However, all of the events and methods that you would find attached to a regular user
are available on said array.
const { Socker } = require('@sloanfinger/socker-js');
const socker = new Socker({port: 8080});
socker.onConnect((user) => {
user.send('Hi! How old are you?'); // Asks user for age
user.onReceive((age, stopListener) => { // Listens for response
stopListener(); // Stops listening after event fires
user.set('age', age); // Sets age to user input
if (age >= 18) {
user.send('Joined 18+ chat. Enter a message:');
user.onReceive((message) => {
// Send all 18+ users the message
socker.getUsers('age >= 18').send('> ' + message);
});
}
});
});
To get a single user based on their id, you can use .getUser()
.
const { Socker } = require('@sloanfinger/socker-js');
const socker = new Socker({port: 8080});
socker.onConnect((user) => {
// These are functionally the same
user.send('Hi!');
socker.getUser(user.getId()).send('Hi!');
});
The .getUsers()
method allows for any JavaScript comparison operators to be used. This is currently acheived by using eval()
, meaning you should never use user input in the .getUsers()
method.
API Docs
Class: Socker
This class is used to create/interact with the WebSocket user.
new Socker(options)
-
options
{Object} -
host
{String} The path to bind the server to -
port
{Number} The port to bind the server to -
server
{http.Server|https.Server} A Node.js HTTP(S) Server -
noServer
{Boolean} Enable no server mode -
path
{String} Only accept connections from matching path -
maxPayload
{Number} The maximum size of a message in bytes -
heartbeat
{Number} How often to check for unresponsive connections
Creates a new websocket server. You must specify either port
, server
, or noServer
, otherwise and error will be thrown. Specifying port
will automatically create a new HTTP server. Specifying either server
or noServer
allows you to use an external HTTP(S) server. For more info, see here.
The heartbeat
option changes the interval at which the server will check for unresponsive connections. After each interval, the server will ping each user. If the user does not respond (which should happen automatically) before the next interval is reached, then the connection will be stopped.
Socker is based on the ws npm package. For a comprehensive list/explanation on the above parameters (and a few more) for new Socker()
, you can view the parameters for new Websocket.Server()
on ws's API Docs.
Event: .onHeaders([callback])
-
callback
: {Function} Runs the given function when the event is emitted with the parametersheaders
,request
,stopListener
, andsocker
This event is emitted before any of the response headers are written as a part of the handshake, allowing you inspect or modify the headers before they are sent. Returns a promise that will resolve the first time the event is emitted. Callbacks will be executed every time the event is emitted, unless stopListener()
is called.
Event: .onConnect([callback])
-
callback
: {Function} Runs the given function when the event is emitted with the parametersuser
stopListener
, andsocker
This event is emitted when the handshake is complete. Returns a promise that will resolve the first time the event is emitted. Callbacks will be executed every time the event is emitted, unless stopListener()
is called.
Event: .onClose([callback])
-
callback
: {Function} Runs the given function when the event is emitted with the parametersstopListener
andsocker
This event is emitted when the server closes. Returns a promise that will resolve the first time the event is emitted. Callbacks will be executed every time the event is emitted, unless stopListener()
is called.
Event: .onError([callback])
-
callback
: {Function} Runs the given function when the event is emitted with the parameterserror
,stopListener
, andsocker
This event is emitted when the server encounters an error. Returns a promise that will resolve the first time the event is emitted. Callbacks will be executed every time the event is emitted, unless stopListener()
is called.
Method: .stop([callback])
-
callback
: {Function} Runs the given function when the method is complete
This method will close the websocket server, if created internally, and force stop all users. Returns a promise that will resolve when the method is complete.
Method: .getUser(id)
-
id
: {String} The id of the user to get
Returns the instance of the user
with the given id.
Method: .getUsers(filter|ids)
-
filter
: {String} A javascript comparison usinguser data
and a given value -
ids
: {Array} An array of the ids of the users to get
Returns an instance of the User
class which can be used to interact with all selected users.
The .getUsers()
method allows for any JavaScript comparison operators to be used. This is currently acheived by using eval()
, meaning you should never use user input in the .getUsers()
method.
Class: User
This class is used to interact with the WebSocket server's user.
new User(socket, request)
-
socket
: {ws.WebSocket} The socket automatically generated byws
-
request
: {http.IncomingMessage} The HTTP GET request sent by the user
Creates a new user. This is automatically passed to the callback or Promise.resolve()
of the .onConnect()
event of the Socker
class.
Event: .onChange(key[, callback])
-
key
: {String} The name of the data value stored with the user -
callback
: {Function} Runs the given function when the event is emitted with the parametersstopListener
anduser
This event is emitted when the any of the stored user data changes. Returns a promise that will resolve the first time the event is emitted. Callbacks will be executed every time the event is emitted, unless stopListener()
is called.
Event: .onReceive([callback])
-
callback
: {Function} Runs the given function when the event is emitted with the parametersdata
,stopListener
, anduser
This event is emitted when the any of the stored user data changes. Returns a promise that will resolve the first time the event is emitted. Callbacks will be executed every time the event is emitted, unless stopListener()
is called.
Event: .onClose([callback])
-
callback
: {Function} Runs the given function when the event is emitted with the parameterscode
,reason
,stopListener
, anduser
This event is emitted when the user's connection closes. Returns a promise that will resolve the first time the event is emitted. Callbacks will be executed every time the event is emitted, unless stopListener()
is called.
Event: .onError([callback])
-
callback
: {Function} Runs the given function when the event is emitted with the parameterserror
,stopListener
, anduser
This event is emitted when the user encounters an error. Returns a promise that will resolve the first time the event is emitted. Callbacks will be executed every time the event is emitted, unless stopListener()
is called.
Method: .send(data[, options[, callback]])
-
data
: {Any} The data to send -
options
: {Object} Options based onws
's websocket.send() -
callback
: {Function} Runs the given function when the method is complete
This method will send the specified data to the user. Returns a promise that will resolve when the method is complete.
Method: .ping([callback])
-
callback
: {Function} Runs the given function when the method is complete
This method will ping the user. Returns a promise that will resolve when the method is complete.
Method: .isAlive()
Returns whether the user has responded to the most recent ping.
Method: .getId()
Returns the id of the user.
Method: .get(key)
-
key
: {String} The key with which the user data is stored
Returns the data stored in the user with the given key
. See: Method: .set(key, value[, readOnly])
Method: .set(key, value[, readOnly])
-
key
: {String} The key with which the user data is stored -
value
: {Any} The value to store with the key in the user -
readOnly
: {Boolean} Specifies whether the data can be overriten
This method will store the value according to the key in the user. If the key already exists, the old value will be overwritten by the new value unless readOnly
was set to true
. The data is cached in a javascript object within the user, is not stored anywhere on the file system, and will be lost upon stopping either the user or the server.
Method: .stop([code[, reason]])
-
code
: {Number} A numeric value indicating why the connection is being stopped -
reason
: {String} A human-readable string explaning why the connection is being stopped
This method will start a closing handshake.
Method: .forceStop()
This method will forcibly close the connection without a handshake.
stopListener()
This function is passed as an argument to the callback function of an event listener. When this function is called, the event listener will no longer fire.
Versions
Changelog
- Add documentation
Future Plans
- Client-side support for the Socker User class
- Allow for user data storage to be easily integrated with popular Node.js Database solutions (Sqlite3, MongoDB, etc.)
- Allow for websocket servers to be easily integrated with Express.js
- Become dependency-free