UNPKG

omelop

Version:

[![Build Status](https://travis-ci.org/node-omelop/omelop.svg?branch=master)](https://travis-ci.org/node-omelop/omelop)

337 lines 22.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BackendSession = exports.BackendSessionService = void 0; /** * backend session service for backend session */ const utils = require("../../util/utils"); let EXPORTED_FIELDS = ['id', 'frontendId', 'uid', 'settings']; /** * Service that maintains backend sessions and the communication with frontend * servers. * * BackendSessionService would be created in each server process and maintains * backend sessions for current process and communicates with the relative * frontend servers. * * BackendSessionService instance could be accessed by * `app.get('backendSessionService')` or app.backendSessionService. * * @class * @constructor */ class BackendSessionService { constructor(app) { this.aget = utils.promisify(this.get.bind(this)); this.agetByUid = utils.promisify(this.getByUid.bind(this)); this.akickBySid = utils.promisify(this.kickBySid.bind(this)); this.akickByUid = utils.promisify(this.kickByUid.bind(this)); this.abind = utils.promisify(this.bind.bind(this)); this.aunbind = utils.promisify(this.unbind.bind(this)); this.apush = utils.promisify(this.push.bind(this)); this.apushAll = utils.promisify(this.pushAll.bind(this)); this.app = app; } create(opts) { if (!opts) { throw new Error('opts should not be empty.'); } return new BackendSession(opts, this); } /** * Get backend session by frontend server id and session id. * * @param {String} frontendId frontend server id that session attached * @param {String} sid session id * @param {Function} cb callback function. args: cb(err, BackendSession) * * @memberOf BackendSessionService */ get(frontendId, sid, cb) { let namespace = 'sys'; let service = 'sessionRemote'; let method = 'getBackendSessionBySid'; let args = [sid]; rpcInvoke(this.app, frontendId, namespace, service, method, args, BackendSessionCB.bind(null, this, cb)); } /** * Get backend sessions by frontend server id and user id. * * @param {String} frontendId frontend server id that session attached * @param {String} uid user id binded with the session * @param {Function} cb callback function. args: cb(err, BackendSessions) * * @memberOf BackendSessionService */ getByUid(frontendId, uid, cb) { let namespace = 'sys'; let service = 'sessionRemote'; let method = 'getBackendSessionsByUid'; let args = [uid]; rpcInvoke(this.app, frontendId, namespace, service, method, args, BackendSessionCB.bind(null, this, cb)); } kickBySid(frontendId, sid, reason, cb) { let namespace = 'sys'; let service = 'sessionRemote'; let method = 'kickBySid'; let args = [sid]; if (typeof reason === 'function') { cb = reason; } else { args.push(reason); } rpcInvoke(this.app, frontendId, namespace, service, method, args, cb); } /** * Kick sessions by user id. * * @param {String} frontendId cooperating frontend server id * @param {Number|String} uid user id * @param {String} reason kick reason * @param {Function} cb callback function * * @memberOf BackendSessionService */ kickByUid(frontendId, uid, reason, cb) { let namespace = 'sys'; let service = 'sessionRemote'; let method = 'kickByUid'; let args = [uid]; if (typeof reason === 'function') { cb = reason; } else { args.push(reason); } rpcInvoke(this.app, frontendId, namespace, service, method, args, cb); } /** * Bind the session with the specified user id. It would finally invoke the * the sessionService.bind in the cooperating frontend server. * * @param {String} frontendId cooperating frontend server id * @param {Number} sid session id * @param {String} uid user id * @param {Function} cb callback function * * @memberOf BackendSessionService * @api private */ bind(frontendId, sid, uid, cb) { let namespace = 'sys'; let service = 'sessionRemote'; let method = 'bind'; let args = [sid, uid]; rpcInvoke(this.app, frontendId, namespace, service, method, args, cb); } /** * Unbind the session with the specified user id. It would finally invoke the * the sessionService.unbind in the cooperating frontend server. * * @param {String} frontendId cooperating frontend server id * @param {Number} sid session id * @param {String} uid user id * @param {Function} cb callback function * * @memberOf BackendSessionService * @api private */ unbind(frontendId, sid, uid, cb) { let namespace = 'sys'; let service = 'sessionRemote'; let method = 'unbind'; let args = [sid, uid]; rpcInvoke(this.app, frontendId, namespace, service, method, args, cb); } /** * Push the specified customized change to the frontend internal session. * * @param {String} frontendId cooperating frontend server id * @param {Number} sid session id * @param {String} key key in session that should be push * @param {Object} value value in session, primitive js object * @param {Function} cb callback function * * @memberOf BackendSessionService * @api private */ push(frontendId, sid, key, value, cb) { let namespace = 'sys'; let service = 'sessionRemote'; let method = 'push'; let args = [sid, key, value]; rpcInvoke(this.app, frontendId, namespace, service, method, args, cb); } /** * Push all the customized changes to the frontend internal session. * * @param {String} frontendId cooperating frontend server id * @param {Number} sid session id * @param {Object} settings key/values in session that should be push * @param {Function} cb callback function * * @memberOf BackendSessionService * @api private */ pushAll(frontendId, sid, settings, cb) { let namespace = 'sys'; let service = 'sessionRemote'; let method = 'pushAll'; let args = [sid, settings]; rpcInvoke(this.app, frontendId, namespace, service, method, args, cb); } } exports.BackendSessionService = BackendSessionService; let rpcInvoke = function (app, sid, namespace, service, method, args, cb) { app.rpcInvoke(sid, { namespace: namespace, service: service, method: method, args: args }, cb); }; /** * BackendSession is the proxy for the frontend internal session passed to handlers and * it helps to keep the key/value pairs for the server locally. * Internal session locates in frontend server and should not be accessed directly. * * The mainly operation on backend session should be read and any changes happen in backend * session is local and would be discarded in next request. You have to push the * changes to the frontend manually if necessary. Any push would overwrite the last push * of the same key silently and the changes would be saw in next request. * And you have to make sure the transaction outside if you would push the session * concurrently in different processes. * * See the api below for more details. * * @class * @constructor */ class BackendSession { constructor(opts, service) { for (let f in opts) { this[f] = opts[f]; } this.__sessionService__ = service; } /** * Bind current session with the user id. It would push the uid to frontend * server and bind uid to the frontend internal session. * * @param {Number|String} uid user id * @param {Function} cb callback function * * @memberOf BackendSession */ bind(uid, cb) { let self = this; this.__sessionService__.bind(this.frontendId, this.id, uid, function (err) { if (!err) { self.uid = uid; } utils.invokeCallback(cb, err); }); } /** * Unbind current session with the user id. It would push the uid to frontend * server and unbind uid from the frontend internal session. * * @param {Number|String} uid user id * @param {Function} cb callback function * * @memberOf BackendSession */ unbind(uid, cb) { let self = this; this.__sessionService__.unbind(this.frontendId, this.id, uid, function (err) { if (!err) { self.uid = null; } utils.invokeCallback(cb, err); }); } /** * Set the key/value into backend session. * * @param {String} key key * @param {Object} value value */ set(key, value) { this.settings[key] = value; } /** * Get the value from backend session by key. * * @param {String} key key * @return {Object} value */ get(key) { return this.settings[key]; } /** * Push the key/value in backend session to the front internal session. * * @param {String} key key * @param {Function} cb callback function */ push(key, cb) { this.__sessionService__.push(this.frontendId, this.id, key, this.get(key), cb); } /** * Push all the key/values in backend session to the frontend internal session. * * @param {Function} cb callback function */ pushAll(cb) { this.__sessionService__.pushAll(this.frontendId, this.id, this.settings, cb); } abind(uid) { return new Promise((resolve, reject) => this.bind(uid, (err, ret) => err ? reject(err) : resolve(ret))); } aunbind(uid) { return new Promise((resolve, reject) => this.unbind(uid, (err, ret) => err ? reject(err) : resolve(ret))); } apush(key) { return new Promise((resolve, reject) => this.push(key, (err, ret) => err ? reject(err) : resolve(ret))); } apushAll() { return new Promise((resolve, reject) => this.pushAll((err, ret) => err ? reject(err) : resolve(ret))); } // abind = utils.promisify(this.bind.bind(this)); // aunbind = utils.promisify(this.unbind.bind(this)); // apush = utils.promisify(this.push.bind(this)); // apushAll = utils.promisify(this.pushAll.bind(this)); /** * Export the key/values for serialization. * * @api private */ export() { let res = {}; EXPORTED_FIELDS.forEach((field) => { res[field] = this[field]; }); return res; } } exports.BackendSession = BackendSession; let BackendSessionCB = function (service, cb, err, sinfo) { if (err) { utils.invokeCallback(cb, err); return; } if (!sinfo) { utils.invokeCallback(cb); return; } let sessions = []; if (Array.isArray(sinfo)) { // #getByUid for (let i = 0, k = sinfo.length; i < k; i++) { sessions.push(service.create(sinfo[i])); } utils.invokeCallback(cb, null, sessions); } else { // #get let session = service.create(sinfo); utils.invokeCallback(cb, null, session); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja2VuZFNlc3Npb25TZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vbGliL2NvbW1vbi9zZXJ2aWNlL2JhY2tlbmRTZXNzaW9uU2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQTs7R0FFRztBQUNILDBDQUEwQztBQU0xQyxJQUFJLGVBQWUsR0FBRyxDQUFDLElBQUksRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0FBRTlEOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFhLHFCQUFxQjtJQUk5QixZQUFZLEdBQWdCO1FBOEs1QixTQUFJLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQzVDLGNBQVMsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDdEQsZUFBVSxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUN4RCxlQUFVLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3hELFVBQUssR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDOUMsWUFBTyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNsRCxVQUFLLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENB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