peero-server
Advanced tools
Comparing version 1.0.1 to 2.0.0
268
index.js
@@ -1,159 +0,209 @@ | ||
require('dotenv').config() | ||
const EventEmitter = require('events') | ||
const uuid = require('uuid/v4') | ||
const logger = require('./lib/logger') | ||
const server = require('./lib/server')({ port: process.env.WS_PORT }) | ||
const server = require('./lib/server') | ||
const log = logger({ | ||
dir: `${__dirname}/logs` | ||
}) | ||
class PeeroServer extends EventEmitter { | ||
constructor (opts = {}) { | ||
super() | ||
const sockets = {} | ||
const defaults = { | ||
port: 8080, | ||
log: null | ||
} | ||
function onMessage (message) { | ||
try { | ||
var data = JSON.parse(message) | ||
} catch (err) { | ||
return log.error('Could not parse message to JSON.') | ||
} | ||
this.options = Object.assign(defaults, opts) | ||
if (data.type === 'register') { | ||
registerClient.call(this) | ||
announcePeer.call(this) | ||
return sendPeers.call(this) | ||
this.initConstants() | ||
this.initLogger() | ||
this.initSocket() | ||
this.logger.info(`Server running on port: ${this.options.port}`) | ||
} | ||
if (data.type === 'signal') { | ||
return sendSignal.call(this, data.data) | ||
initLogger () { | ||
this.logger = logger(this.options) | ||
} | ||
} | ||
function sendMessage (peerId, message) { | ||
var socket = sockets[peerId] | ||
if (!socket) { | ||
return false | ||
initSocket () { | ||
this.sockets = {} | ||
this.socket = server(this.options) | ||
this.socket.on('connection', (socket) => { | ||
this.onConnection(socket) | ||
}) | ||
} | ||
if (socket.readyState !== 1) { | ||
return false | ||
initConstants () { | ||
this.CONNECTING = 0 | ||
this.CONNECTED = 1 | ||
this.CLOSING = 2 | ||
this.CLOSED = 3 | ||
} | ||
return socket.send(message, onSendError) | ||
} | ||
onConnection (socket) { | ||
const peerId = uuid() | ||
function onSendError (err) { | ||
if (!err) { | ||
return null | ||
} | ||
socket.peerId = peerId | ||
socket.on('message', (message) => { | ||
return this.onMessage(socket, message) | ||
}) | ||
if (this.readyState > 1) { | ||
removeSocket(this.peerId) | ||
this.sockets[peerId] = socket | ||
this.emit('connection', socket) | ||
} | ||
return log.error('Could not send message.') | ||
} | ||
onMessage (socket, message) { | ||
let data = null | ||
function removeSocket (peerId) { | ||
delete sockets[peerId] | ||
} | ||
try { | ||
data = JSON.parse(message) | ||
} catch (err) { | ||
return this.logger.error('Could not parse message to JSON.') | ||
} | ||
function registerClient () { | ||
var message = JSON.stringify({ | ||
type: 'register', | ||
data: { peerId: this.peerId } | ||
}) | ||
if (data.type === 'register') { | ||
this.registerClient(socket) | ||
this.announcePeer(socket) | ||
this.sendPeers(socket) | ||
} else if (data.type === 'signal') { | ||
this.sendSignal(socket, data.data) | ||
} | ||
} | ||
return sendMessage(this.peerId, message) | ||
} | ||
sendSignal (socket, data) { | ||
if (data.signal.type === 'offer') { | ||
this.sendOffer(socket, data.signal) | ||
} | ||
function announcePeer () { | ||
Object.keys(sockets).forEach(peerId => { | ||
if (this.peerId === peerId) { | ||
return null | ||
if (data.signal.type === 'answer') { | ||
this.sendAnswer(socket, data.peerId, data.signal) | ||
} | ||
} | ||
var message = JSON.stringify({ | ||
type: 'announce', | ||
data: { peerId: this.peerId } | ||
sendOffer (socket, signal) { | ||
Object.keys(this.sockets).forEach((peerId) => { | ||
if (socket.peerId === peerId) { | ||
return null | ||
} | ||
const message = JSON.stringify({ | ||
type: 'offer', | ||
data: { | ||
signal, | ||
peerId: socket.peerId | ||
} | ||
}) | ||
return this.sendMessage(peerId, message) | ||
}) | ||
return sendMessage(peerId, message) | ||
}) | ||
} | ||
return this.emit('offer', socket, signal) | ||
} | ||
function sendPeers () { | ||
var peers = [] | ||
sendAnswer (socket, peerId, signal) { | ||
const message = JSON.stringify({ | ||
type: 'answer', | ||
data: { | ||
signal, | ||
peerId: socket.peerId | ||
} | ||
}) | ||
Object.keys(sockets).forEach(peerId => { | ||
if (this.peerId === peerId) { | ||
return null | ||
this.sendMessage(peerId, message) | ||
this.emit('answer', socket, peerId, signal) | ||
} | ||
sendMessage (peerId, message) { | ||
const that = this | ||
const socket = this.sockets[peerId] | ||
if (!socket) { | ||
return false | ||
} | ||
if (sockets[peerId].readyState > 1) { | ||
return removeSocket(peerId) | ||
if (socket.readyState !== this.CONNECTED) { | ||
return false | ||
} | ||
peers.push(peerId) | ||
}) | ||
return socket.send(message, (err) => { | ||
if (!err) { | ||
return this.emit('message', peerId, message) | ||
} | ||
var message = JSON.stringify({ | ||
type: 'peers', | ||
data: { peers } | ||
}) | ||
return that.onSendError(socket, err) | ||
}) | ||
} | ||
return sendMessage(this.peerId, message) | ||
} | ||
function sendOffer (signal) { | ||
Object.keys(sockets).forEach(peerId => { | ||
if (this.peerId === peerId) { | ||
return null | ||
onSendError (socket, err) { | ||
if (socket.readyState > this.CONNECTED) { | ||
this.removeSocket(socket.peerId) | ||
} | ||
var message = JSON.stringify({ | ||
type: 'offer', | ||
this.logger.error('Could not send message.') | ||
this.emit('error', err, socket) | ||
} | ||
registerClient (socket) { | ||
const message = JSON.stringify({ | ||
type: 'register', | ||
data: { | ||
signal, | ||
peerId: this.peerId | ||
peerId: socket.peerId | ||
} | ||
}) | ||
return sendMessage(peerId, message) | ||
}) | ||
} | ||
this.sendMessage(socket.peerId, message) | ||
this.emit('register', socket) | ||
} | ||
function sendAnswer (peerId, signal) { | ||
var message = JSON.stringify({ | ||
type: 'answer', | ||
data: { | ||
signal, | ||
peerId: this.peerId | ||
} | ||
}) | ||
announcePeer (socket) { | ||
Object.keys(this.sockets).forEach((peerId) => { | ||
if (socket.peerId === peerId) { | ||
return null | ||
} | ||
return sendMessage(peerId, message) | ||
} | ||
const message = JSON.stringify({ | ||
type: 'announce', | ||
data: { | ||
peerId: socket.peerId | ||
} | ||
}) | ||
function sendSignal (data) { | ||
if (data.signal.type === 'offer') { | ||
return sendOffer.call(this, data.signal) | ||
} | ||
return this.sendMessage(peerId, message) | ||
}) | ||
if (data.signal.type === 'answer') { | ||
return sendAnswer.call(this, data.peerId, data.signal) | ||
this.emit('announce', socket) | ||
} | ||
} | ||
function onConnection (socket) { | ||
var peerId = uuid() | ||
sendPeers (socket) { | ||
const peers = [] | ||
socket.peerId = peerId | ||
socket.on('message', onMessage) | ||
Object.keys(this.sockets).forEach((peerId) => { | ||
if (socket.peerId === peerId) { | ||
return null | ||
} | ||
sockets[peerId] = socket | ||
if (this.sockets[peerId].readyState > this.CONNECTED) { | ||
return this.removeSocket(peerId) | ||
} | ||
return peers.push(peerId) | ||
}) | ||
const message = JSON.stringify({ | ||
type: 'peers', | ||
data: { | ||
peers | ||
} | ||
}) | ||
this.sendMessage(socket.peerId, message) | ||
this.emit('peers', socket, peers) | ||
} | ||
removeSocket (peerId) { | ||
Reflect.deleteProperty(this.sockets, peerId) | ||
this.emit('remove', peerId) | ||
} | ||
} | ||
server.on('connection', onConnection) | ||
log.info('Server started') | ||
module.exports = PeeroServer |
const path = require('path') | ||
const winston = require('winston') | ||
module.exports = (options = {}) => { | ||
module.exports = (options) => { | ||
let dir = './' | ||
let transports = [] | ||
if (options.dir) { | ||
dir = options.dir | ||
if (options.log) { | ||
dir = options.log | ||
transports.push(new winston.transports.File({ | ||
filename: path.resolve(dir, 'error.log'), | ||
level: 'error' | ||
})) | ||
transports.push(new winston.transports.File({ | ||
filename: path.resolve(dir, 'combined.log') | ||
})) | ||
} | ||
const logger = winston.createLogger({ | ||
transports, | ||
exitOnError: false, | ||
transports: [ | ||
new winston.transports.File({ | ||
filename: path.resolve(dir, 'error.log'), | ||
level: 'error' | ||
}), | ||
new winston.transports.File({ | ||
filename: path.resolve(dir, 'combined.log') | ||
}) | ||
], | ||
format: winston.format.combine( | ||
@@ -23,0 +25,0 @@ winston.format.timestamp(), |
const WebSocket = require('ws') | ||
module.exports = (options = {}) => { | ||
const defaults = { | ||
port: 8080 | ||
} | ||
let opts = {} | ||
opts = Object.assign({}, defaults, options) | ||
return new WebSocket.Server(opts) | ||
module.exports = (options) => { | ||
return new WebSocket.Server(options) | ||
} |
{ | ||
"name": "peero-server", | ||
"version": "1.0.1", | ||
"version": "2.0.0", | ||
"description": "Websocket server which facilitates discovery between Peero client peers.", | ||
"main": "index.js", | ||
"scripts": { | ||
"server": "pm2 start pm2.config.js", | ||
"shutdown": "pm2 stop pm2.config.js" | ||
}, | ||
"scripts": {}, | ||
"keywords": [ | ||
@@ -22,3 +19,5 @@ "peer-to-peer", | ||
}, | ||
"devDependencies": {} | ||
"devDependencies": { | ||
"eslint": "^5.6.1" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
Websocket server which facilitates discovery between [Peero client](https://github.com/riteable/peero-client) peers. | ||
WebSocket server which facilitates discovery between [Peero client](https://github.com/riteable/peero-client) peers. | ||
@@ -8,54 +8,33 @@ ## What & why | ||
## Installation & usage | ||
To run the server, you will need to have Node installed. And then in your CLI: | ||
## Installation | ||
To run the server, you will need to have Node.js and npm installed, so you can: | ||
$ npm install peero-server | ||
Install [PM2](https://pm2.io/doc/en/runtime/overview/) globally if it isn't installed already: | ||
$ npm install pm2 -g | ||
## Usage | ||
Then run the server: | ||
const PeeroServer = require('peero-server') | ||
$ cd peero-server | ||
$ pm2 pm2.config.js | ||
const server = new PeeroServer({ | ||
port: '80', | ||
log: '/path/to/log/directory' | ||
}) | ||
A client can connect with the server on `ws://localhost:8080`. You can read the [PM2 documentation](https://pm2.io/doc/en/runtime/overview/) on how to work with the process manager. | ||
## Options | ||
The constructor accepts the following options: | ||
You can copy `.env.example` to a new `.env` file to set some environment settings, for example: | ||
- **port**: The port of the websocket server. **Default:** 8080. | ||
- **log**: The directory for file logs. When null, no logs are written to disk. When a directory is set, two log files are generated: `error.log` and `combined.log`. The former contains only errors when they're caught, the latter contains `error`, `warn` and `info` log levels. When `process.env.NODE_ENV !== 'production'`, logs are output to stdout. **Default:** null. | ||
NODE_ENV=production | ||
WS_PORT=8000 | ||
## Events | ||
The instance emits the following events: | ||
## How it works | ||
The server works only with websocket requests. All messages passed from and to the server are serialized JSON/Javascript objects. For a client to connect to the server it needs to send a 'register' message: | ||
{ | ||
type: 'register' | ||
} | ||
When the server receives that message, it will generate a UUIDv4 ID and send it to the client: | ||
{ | ||
type: 'register', | ||
data: { peerId: 'af988091-4454...' } | ||
} | ||
The server will simultaneously send messages to other connected clients to announce a new client: | ||
{ | ||
type: 'announce', | ||
data: { peerId: 'af988091-4454...' } | ||
} | ||
It will also send all currently connected clients to the new client: | ||
{ | ||
type: 'peers', | ||
data: { | ||
peers: [ | ||
'6f01ab34-3a56...', | ||
'72a4ad27-bde5...' | ||
] | ||
} | ||
} | ||
- **on('connection', (socket))**: When a client establishes a connection with the server. | ||
- **on('message', (socket, message))**: When any WebSocket message is sent to a client. | ||
- **on('offer', (socket, signal))**: When an 'offer' signal is sent to all connected clients (except the signaling client). | ||
- **on('answer', (socket, peerId, signal))**: When an 'answer' signal is sent to a client. | ||
- **on('announce', (socket))**: When connected client have been notified of a new connected client. | ||
- **on('peers', (socket, peers))**: When the list of connected client have been sent to a client. | ||
- **on('remove', (peerId))**: When a client has been removed from the list of connected clients (due to connectivity issues, for example). | ||
- **on('error', (err, socket))**: When a message fails to reach a client (due to connectivity issues, for example). The client is also automatically removed from the list of connected clients when this occurs. |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
18137
481
2
1
6
40
1