Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/titobouzout/angelia.io

WebSockets Server and Client for node.js and the browser
https://github.com/titobouzout/angelia.io

angelia socket sockets websocket-client websocket-server websockets

Last synced: 10 days ago
JSON representation

WebSockets Server and Client for node.js and the browser

Awesome Lists containing this project

README

        

# angelia.io

WebSockets Server and Client API for Node.js and the browser, with
rooms support.

The goal of this project is to provide a developer friendly API that
just works™.

## Installation

`npm install angelia.io`

## Example

```js
// server.js (node.js)

import Server from 'angelia.io/server'

class FancyChat {
typing(socket, data, callback) {
console.log('Im', data ? ' typing' : ' not typing')
}
theMessage(socket, data, callback) {
console.log('the message is', data, socket)
socket.emit('gotIt', 'thanks')
callback('yes Im sure')
}
}

Server.on(FancyChat)

class myConnection {
connect(socket, request) {
console.log('socket connected', socket)
}
disconnect(socket, code, message) {
console.log('socket disconnected', code, message, socket)
}
}
Server.on(myConnection)

Server.listen()

// index.js (browser)

import Client from 'angelia.io/client'

const socket = new Client('ws://localhost:3001')

socket.emit('typing', true)

setTimeout(() => {
socket.emit('typing', false)
socket.emit('theMessage', 'hi there!', data => {
console.log('yep', data)
})
}, 5000)

socket.on('gotIt', message => {
console.log('Server got it', message)
})
```

## Server Documentation (Node.js)

### `Server.listen` Options

| name | kind | default | description |
| -------------------- | ------- | --------- | ------------------------------------------------------------------------------ |
| `hostname` | String | undefined | the hostname if any |
| `port` | Number | 3001 | the port to use for this server |
| `maxMessageSize` | Number | 5 | max size in mb of a message received |
| `maxPostSize` | Number | 50 | max size in mb of a POST message |
| `skipUTF8Validation` | Boolean | false | allows to skip utf8 validation |
| `timeout` | Number | 60000 | time in milliseconds after a socket is considered gone, minimum value is 10000 |

### `Server` Object

The `server` object can be accessed from everywhere

#### List of `Server` Object Properties

| signature | kind | description |
| ------------------------------------- | -------- | ---------------------------------------------------------------------------------------------- |
| `since` | Number | timestamp of initialization |
| `now` | Number | timestamp that updates every half a second |
| `port` | Number | port used by this server |
| `hostname` | String | the hostname if any |
| `maxMessageSize` | Number | maximum message size in mb |
| `maxPostSize` | Number | maximum POST size in mb |
| `timeout` | Number | after how long the socket is considered gone, in ms |
| `connections` | Number | count of sockets connected |
| `served` | Number | count of sockets ever connected |
| `bytesReceived` | Number | sum of bytes the server has ever received |
| `bytesSent` | Number | sum of bytes sent by the server |
| `messagesGarbage` | Number | count of messages without a listener |
| `messagesReceived` | Number | count of messages ever received |
| `messagesSent` | Number | count of messages ever sent |
| `messagesSentCacheHit` | Number | count of messages ever sent that were cached |
| `serverErrors` | Number | count of server errors |
| `socketErrors` | Number | count of socket errors |
| `events` | Object | ref to events, ex: server.events.typing() to dispatch typing to anyone listening to it |
| `on(Class)` | Function | attaches all methods of a `Class` as listeners |
| `emit(key, [value])` | Function | emits to all connected sockets |
| `once(key, [value])` | Function | emits to the sockets and replace if exists a pending message with the same `key` |
| `broadcast(sender, key, [value])` | Function | emits to all connected sockets except sender |
| `broadcastOnce(sender, key, [value])` | Function | emits to the sockets except sender and replace if exists a pending message with the same `key` |
| `sockets` | Set | a Set() with all the current connected sockets |

### `Socket` Object

The `socket` object is given to you by a listener

#### List of `Socket` Object Properties

| signature | kind | description |
| --------------------------- | -------- | ----------------------------------------------------------------------------- |
| `server` | Object | reference to the server |
| `ip` | String | ip of the socket |
| `userAgent` | String | user agent of the socket |
| `params` | Object | the params sent via the client constructor |
| `since` | Number | timestamp of first seen |
| `seen` | Number | timestamp of last received message |
| `ping` | Number | delay with the socket in milliseconds (full round trip) |
| `timedout` | Boolean | whether we lost connection with this socket |
| `bytesSent` | Number | sum of bytes sent to this socket |
| `bytesReceived` | Number | sum of bytes received from this socket |
| `messagesSent` | Number | count of messages sent to this socket |
| `messagesReceived` | Number | count of messages received from this socket |
| `rooms` | Set | a set with the rooms where this socket is in |
| `emit(key, [value])` | Function | emits to client |
| `once(key, [value])` | Function | replace if exists a pending message with the same `key` from emit queue |
| `disconnect([noReconnect])` | Function | disconnects the socket from the server, pass `true` to prevent re-connections |

### Server Listeners

Listen to an event by creating a class with any name, and give to
methods the name of the things you want to listen to. Then add the
class to the listeners as `Server.on(MyClass)` and you are done.

On user defined listeners, the listener receives three things as sent
by the client: `socket`, `data` and a `callback`; Example:
`class FancyChat { typing(socket, data, callback?) { console.log(socket, data) }}`.

#### List of Predefined `Server` Events

There's a bunch of handy predefined events dispatched

| signature | description |
| ----------------------------------- | ----------------------------------------------------------------------------------------- |
| `listen()` | when the server is about to listen |
| `connect(socket, request)` | when a socket connects |
| `disconnect(socket, code, message)` | when a socket gets disconnected |
| `ping(socket)` | when we got an update of the ping for a socket |
| `timeout(socket, delay)` | when we are about to disconnect a timedout socket, gives the delay in milliseconds |
| `garbage(socket, data)` | if the client sends a message that the server has no listener this will be dispatched |
| `incoming(socket, messages)` | for debugging: ref to array of incoming messages received before dispatching to listeners |
| `outgoing(socket, messages)` | for debugging: ref to array of outgoing messages before sending to socket |

## Client API (Browser)

### `Client` Options

Arguments for the constructor

```js
const socket = new Client({
url: 'ws://localhost:3001',
params: function () {
return { fast: 'data', test: 'a space' }
},
noConnect: true,
})
socket.connect()
```

You may also do like this if you don't need any option

```js
const socket = new Client('ws://localhost:3001')
```

### `Client` API

The client API is similar to regular event handling

| signature | kind | description |
| ------------------------------ | -------- | ------------------------------------------------------------------ |
| `connected` | Boolean | `true` when the socket is connected else `false` |
| `connect()` | Function | connects to the server, it auto-connects on disconnection |
| `disconnect([noReconnect])` | Function | disconnects from the server, pass `true` to prevent re-connections |
| `on(key, callback)` | Function | listens for an event, returns an `off` function to stop listening |
| `emit(key, [value, callback])` | Function | emits data to the server |

#### List of Predefined `Client` Events

As in `socket.on('connect', () => console.log('connect happened!'))`

| signature | description |
| ------------ | -------------------------------------------------------------------------------------------------------- |
| `connect` | **this happens only once** when we connect to the server, any future connection is a `reconnect` |
| `reconnect` | if we were connected at least once, then any re-connection will dispatch this event instead of `connect` |
| `disconnect` | when we disconnect from the server |

## Rooms

### Via a `Rooms` list

1. Create a room class that extends `Room`
2. Create a room list that will allow joining sockets
3. Join a socket in a room, a socket may join multiple rooms. Rooms
are created when the `id` of the room doesn't exists, and deleted
when there are no sockets in the room and the room doesn't have the
flag `persistent`
4. A socket will leave automatically all rooms on disconnection
5. `socket.rooms` is a set with all the rooms the socket joined
6. `id` is assigned to the room on creation

```js
import { Room, Rooms } from 'angelia.io/server'

class GameRoom extends Room {
persistent = false

onCreate(socket) {
console.log('creating room', this.id, socket)
}
onDelete(socket) {
console.log('deleting room', this.id, socket)
}

onJoin(socket) {
console.log('socket joined room', this.id, socket)
socket.game = this
this.emit('user joined', 'data here')
}
onLeave(socket) {
console.log('socket left room', this.id, socket)
socket.game = undefined
this.emit('user left', 'data here')
}
}

// games is a room list
const games = new Rooms(GameRoom)

class Connection {
connect(socket) {
games.join(socket, 'room id here')
socket.game.id === 'room id here'
console.log(socket.rooms)
games.leave(socket, 'room id here')

games.join(socket, 'a different room')
socket.game.id === 'a different room'
games.leave(socket, 'a different room')
}
}

Server.on(Connection)
Server.listen()
```

#### `Rooms` Class

Iterating returns the rooms

| signature | kind | description |
| ------------------------------------- | -------- | --------------------------------------------- |
| `get(id)` | method | gets room with such an `id` |
| `join(socket, [id])` | method | adds socket to room `id` |
| `leave(socket, [id])` | method | removes socket from room `id` |
| `connections` | number | number of sockets in this room list |
| `sockets` | Iterator | sockets in this room list |
| `emit(key, [value])` | method | emits to all sockets in this room list |
| `once(key, [value])` | method | emits once to all sockets in this room list |
| `broadcast(socket, key, [value])` | method | emits to other sockets in this room list |
| `broadcastOnce(socket, key, [value])` | method | emits once to other sockets in this room list |
| `map(fn)` | method | returns mapped array |
| `filter(fn)` | method | returns mapped filtered array |

### Via a `Room`

1. Create a room instance that extends `Room`
2. Join a socket in a room, a socket may join multiple rooms.
3. A socket will leave automatically all rooms on disconnection
4. `socket.rooms` is a set with all the rooms the socket joined
5. Keep in mind that `onCreate` and `onDelete` are not dispatched when
the room is manged by yourself. The construtor could be used for
simulating `onCreate` and `onDelete` only you will know when to
dispose such a variable.

```js
import { Room } from 'angelia.io/server'

class Lobby extends Room {
persistent = true
id = 'lobby'
onJoin(socket) {
console.log('socket joined room', this.id, socket)
}
}

// lobby is just 1 room
const lobby = new Lobby()

class Connection {
connect(socket) {
lobby.join(socket)

lobby.leave(socket)
}
}

Server.on(Connection)
Server.listen()
```

#### `Room` Class

Iterating returns the sockets

| signature | kind | description |
| ------------------------------------- | ------- | ------------------------------------------------ |
| `onCreate(socket)` | method | dispatched when the room is created |
| `onDelete(socket)` | method | dispatched when the room is deleted |
| `onJoin(socket)` | method | dispatched when a socket joins the room |
| `onLeave(socket)` | method | dispatched when a socket leaves the room |
| `persistent` | boolean | to not delete rooms when there are no sockets in |
| `connections` | number | number of sockets in the room |
| `sockets` | Set | sockets in the room |
| `emit(key, [value])` | method | emits to all sockets in the room |
| `once(key, [value])` | method | emits once to all sockets in the room |
| `broadcast(socket, key, [value])` | method | emits to other sockets in the room |
| `broadcastOnce(socket, key, [value])` | method | emits once to other sockets in the room |
| `id` | any | the room id |
| `join(socket)` | method | adds a socket to the room |
| `leave(socket)` | method | remves a socket from the room |

### `sockets` Object in `Room` and `Rooms`

Like `Set` but with two aditional methods

| signature | kind | description |
| ------------ | ------ | ----------------------------- |
| `map(fn)` | method | returns mapped array |
| `filter(fn)` | method | returns mapped filtered array |

## Authors

- Tito Bouzout https://github.com/titoBouzout
- Anthony K. https://github.com/boredofnames

## URLs

- https://github.com/titoBouzout/angelia.io
- https://www.npmjs.com/package/angelia.io