UNPKG

nightscout

Version:

Nightscout acts as a web-based CGM (Continuous Glucose Monitor) to allow multiple caregivers to remotely view a patients glucose data in realtime.

148 lines (119 loc) 4.7 kB
'use strict'; const apiConst = require('./const'); const forwarded = require('forwarded-for'); /** * Socket.IO broadcaster of any storage change */ function StorageSocket (app, env, ctx) { const self = this; const LOG_GREEN = '\x1B[32m' , LOG_MAGENTA = '\x1B[35m' , LOG_RESET = '\x1B[0m' , LOG = LOG_GREEN + 'STORAGE SOCKET: ' + LOG_RESET , LOG_ERROR = LOG_MAGENTA + 'STORAGE SOCKET: ' + LOG_RESET , NAMESPACE = '/storage' ; /** * Initialize socket namespace and bind the events * @param {Object} io Socket.IO object to multiplex namespaces */ self.init = function init (io) { self.io = io; self.namespace = io.of(NAMESPACE); self.namespace.on('connection', function onConnected (socket) { const address = forwarded(socket.request, socket.request.headers); const remoteIP = address.ip; console.log(LOG + 'Connection from client ID: ', socket.client.id, ' IP: ', remoteIP); socket.on('disconnect', function onDisconnect () { console.log(LOG + 'Disconnected client ID: ', socket.client.id); }); socket.on('subscribe', function onSubscribe (message, returnCallback) { self.subscribe(socket, message, returnCallback); }); }); ctx.bus.on('storage-socket-create', self.emitCreate); ctx.bus.on('storage-socket-update', self.emitUpdate); ctx.bus.on('storage-socket-delete', self.emitDelete); }; /** * Authorize Socket.IO client and subscribe him to authorized rooms * @param {Object} socket * @param {Object} message input message from the client * @param {Function} returnCallback function for returning a value back to the client */ self.subscribe = function subscribe (socket, message, returnCallback) { const shouldCallBack = typeof(returnCallback) === 'function'; if (message && message.accessToken) { return ctx.authorization.resolveAccessToken(message.accessToken, function resolveFinish (err, auth) { if (err) { console.log(`${LOG_ERROR} Authorization failed for accessToken:`, message.accessToken); if (shouldCallBack) { returnCallback({ success: false, message: apiConst.MSG.SOCKET_MISSING_OR_BAD_ACCESS_TOKEN }); } return err; } else { return self.subscribeAuthorized(socket, message, auth, returnCallback); } }); } console.log(`${LOG_ERROR} Authorization failed for message:`, message); if (shouldCallBack) { returnCallback({ success: false, message: apiConst.MSG.SOCKET_MISSING_OR_BAD_ACCESS_TOKEN}); } }; /** * Subscribe already authorized Socket.IO client to his rooms * @param {Object} socket * @param {Object} message input message from the client * @param {Object} auth authorization of the client * @param {Function} returnCallback function for returning a value back to the client */ self.subscribeAuthorized = function subscribeAuthorized (socket, message, auth, returnCallback) { const shouldCallBack = typeof(returnCallback) === 'function'; const enabledCols = app.get('enabledCollections'); const cols = Array.isArray(message.collections) ? message.collections : enabledCols; const subscribed = []; for (const col of cols) { if (enabledCols.includes(col)) { const permission = (col === 'settings') ? `api:${col}:admin` : `api:${col}:read`; if (ctx.authorization.checkMultiple(permission, auth.shiros)) { socket.join(col); subscribed.push(col); } } } const doc = subscribed.length > 0 ? { success: true, collections: subscribed } : { success: false, message: apiConst.MSG.SOCKET_UNAUTHORIZED_TO_ANY }; if (shouldCallBack) { returnCallback(doc); } return doc; }; /** * Emit create event to the subscribers (of the collection's room) * @param {Object} event */ self.emitCreate = function emitCreate (event) { self.namespace.to(event.colName) .emit('create', event); }; /** * Emit update event to the subscribers (of the collection's room) * @param {Object} event */ self.emitUpdate = function emitUpdate (event) { self.namespace.to(event.colName) .emit('update', event); }; /** * Emit delete event to the subscribers (of the collection's room) * @param {Object} event */ self.emitDelete = function emitDelete (event) { self.namespace.to(event.colName) .emit('delete', event); } } module.exports = StorageSocket;