'use strict'
const ActionHero = require('./../index.js')
const api = ActionHero.api
/**
* This callback is displayed as part of the Requester class.
* @callback ActionHero~ConnectionCallback
* @param {Object} connection - The connection being created/destroyed.
* @see ActionHero~ConnectionMiddleware
*/
/**
* Middleware definition for processing connection events
*
* @typedef {Object} ActionHero~ConnectionMiddleware
* @property {string} name - Unique name for the middleware.
* @property {Number} priority - Module load order. Defaults to `api.config.general.defaultMiddlewarePriority`.
* @property {ActionHero~ConnectionCallback} create - Called for each new connection when it is created.
* @property {ActionHero~ConnectionCallback} destroy - Called for each connection before it is destroyed.
* @see api.connections.addMiddleware
* @example
var connectionMiddleware = {
name: 'connection middleware',
priority: 1000,
create: (connection) => {
// do stuff
},
destroy:(connection) => {
// do stuff
}
}
api.connections.addMiddleware(connectionMiddleware)
*/
/**
* Server connection handling.
*
* @namespace api.connections
* @property {Object} connections - Dictionary of currently-established client connections.
* @property {Object} middleware - Dictionary of loaded middleware modules.
* @property {Array} globalMiddleware - Array of global middleware modules.
* @property {Array} allowedVerbs - Verbs the server will allow clients to send.
* @extends ActionHero.Initializer
*/
module.exports = class Connections extends ActionHero.Initializer {
constructor () {
super()
this.name = 'connections'
this.loadPriority = 400
}
initialize () {
api.connections = {
connections: {},
middleware: {},
globalMiddleware: [],
allowedVerbs: [
'quit',
'exit',
'documentation',
'paramAdd',
'paramDelete',
'paramView',
'paramsView',
'paramsDelete',
'roomAdd',
'roomLeave',
'roomView',
'detailsView',
'say'
],
/**
* @private
*/
apply: async (connectionId, method, args) => {
return api.redis.doCluster('api.connections.applyResponder', [connectionId, method, args], connectionId, true)
},
/**
* @private
*/
applyResponder: async (connectionId, method, args) => {
const connection = api.connections.connections[connectionId]
if (!connection) { return }
if (method && args) {
if (method === 'sendMessage' || method === 'sendFile') {
await connection[method](args)
} else {
await connection[method].apply(connection, args)
}
}
return api.connections.cleanConnection(connection)
},
/**
* Add a middleware component to connection handling.
*
* @param {object} data The middleware definition to add.
* @memberOf api.connections
* @see ActionHero~ConnectionMiddleware
*/
addMiddleware: (data) => {
if (!data.name) { throw new Error('middleware.name is required') }
if (!data.priority) { data.priority = api.config.general.defaultMiddlewarePriority }
data.priority = Number(data.priority)
api.connections.middleware[data.name] = data
api.connections.globalMiddleware.push(data.name)
api.connections.globalMiddleware.sort((a, b) => {
if (api.connections.middleware[a].priority > api.connections.middleware[b].priority) {
return 1
} else {
return -1
}
})
},
/**
* @private
*/
cleanConnection: (connection) => {
let clean = {}
for (let i in connection) {
if (i !== 'rawConnection' && i !== 'api') {
try {
JSON.stringify(connection[i])
clean[i] = connection[i]
} catch (error) {}
}
}
return clean
}
}
}
}