UNPKG

omelop

Version:

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

610 lines 35.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FrontendSession = exports.Session = exports.SessionService = void 0; const events_1 = require("events"); const omelop_logger_1 = require("omelop-logger"); const utils = require("../../util/utils"); const path = require("path"); let logger = (0, omelop_logger_1.getLogger)('omelop', path.basename(__filename)); let FRONTEND_SESSION_FIELDS = ['id', 'frontendId', 'uid', '__sessionService__']; let EXPORTED_SESSION_FIELDS = ['id', 'frontendId', 'uid', 'settings']; let ST_INITED = 0; let ST_CLOSED = 1; /** * Session service maintains the internal session for each client connection. * * Session service is created by session component and is only * <b>available</b> in frontend servers. You can access the service by * `app.get('sessionService')` or `app.sessionService` in frontend servers. * * @param {Object} opts constructor parameters * @class * @constructor */ class SessionService { constructor(opts) { this.akick = utils.promisify(this.kick.bind(this)); this.akickBySessionId = utils.promisify(this.kickBySessionId.bind(this)); this.abind = utils.promisify(this.bind.bind(this)); this.aunbind = utils.promisify(this.unbind.bind(this)); this.aimport = utils.promisify(this.import.bind(this)); this.aimportAll = utils.promisify(this.importAll.bind(this)); opts = opts || {}; this.singleSession = opts.singleSession; this.sessions = {}; // sid -> session this.uidMap = {}; // uid -> sessions } /** * Create and return internal session. * * @param {Integer} sid uniqe id for the internal session * @param {String} frontendId frontend server in which the internal session is created * @param {Object} socket the underlying socket would be held by the internal session * * @return {Session} * * @memberOf SessionService * @api private */ create(sid, frontendId, socket) { let session = new Session(sid, frontendId, socket, this); this.sessions[session.id] = session; return session; } /** * Bind the session with a user id. * * @memberOf SessionService * @api private */ bind(sid, uid, cb) { let session = this.sessions[sid]; if (!session) { process.nextTick(function () { cb(new Error('session does not exist, sid: ' + sid)); }); return; } if (session.uid) { if (session.uid === uid) { // already bound with the same uid cb(null); return; } // already bound with other uid process.nextTick(function () { cb(new Error('session has already bound with ' + session.uid)); }); return; } let sessions = this.uidMap[uid]; if (!!this.singleSession && !!sessions) { process.nextTick(function () { cb(new Error('singleSession is enabled, and session has already bound with uid: ' + uid)); }); return; } if (!sessions) { sessions = this.uidMap[uid] = []; } for (let i = 0, l = sessions.length; i < l; i++) { // session has binded with the uid if (sessions[i].id === session.id) { process.nextTick(cb); return; } } sessions.push(session); session.bind(uid); if (cb) { process.nextTick(cb); } } /** * Unbind a session with the user id. * * @memberOf SessionService * @api private */ unbind(sid, uid, cb) { let session = this.sessions[sid]; if (!session) { process.nextTick(function () { cb(new Error('session does not exist, sid: ' + sid)); }); return; } if (!session.uid || session.uid !== uid) { process.nextTick(function () { cb(new Error('session has not bind with ' + session.uid)); }); return; } let sessions = this.uidMap[uid], sess; if (sessions) { for (let i = 0, l = sessions.length; i < l; i++) { sess = sessions[i]; if (sess.id === sid) { sessions.splice(i, 1); break; } } if (sessions.length === 0) { delete this.uidMap[uid]; } } session.unbind(uid); if (cb) { process.nextTick(cb); } } /** * Get session by id. * * @param {Number} id The session id * @return {Session} * * @memberOf SessionService * @api private */ get(sid) { return this.sessions[sid]; } /** * Get sessions by userId. * * @param {Number} uid User id associated with the session * @return {Array} list of session binded with the uid * * @memberOf SessionService * @api private */ getByUid(uid) { return this.uidMap[uid]; } /** * Remove session by key. * * @param {Number} sid The session id * * @memberOf SessionService * @api private */ remove(sid) { let session = this.sessions[sid]; if (session) { let uid = session.uid; delete this.sessions[session.id]; let sessions = this.uidMap[uid]; if (!sessions) { return; } for (let i = 0, l = sessions.length; i < l; i++) { if (sessions[i].id === sid) { sessions.splice(i, 1); if (sessions.length === 0) { delete this.uidMap[uid]; } break; } } } } /** * Import the key/value into session. * * @api private */ import(sid, key, value, cb) { let session = this.sessions[sid]; if (!session) { utils.invokeCallback(cb, new Error('session does not exist, sid: ' + sid)); return; } session.set(key, value); utils.invokeCallback(cb); } /** * Import new value for the existed session. * * @memberOf SessionService * @api private */ importAll(sid, settings, cb) { let session = this.sessions[sid]; if (!session) { utils.invokeCallback(cb, new Error('session does not exist, sid: ' + sid)); return; } for (let f in settings) { session.set(f, settings[f]); } utils.invokeCallback(cb); } /** * Kick all the session offline under the user id. * * @param {Number} uid user id asscociated with the session * @param {Function} cb callback function * * @memberOf SessionService */ kick(uid, reason, cb) { // compatible for old kick(uid, cb); if (typeof reason === 'function') { cb = reason; reason = 'kick'; } let sessions = this.getByUid(uid); if (sessions) { // notify client let sids = []; let self = this; sessions.forEach(function (session) { sids.push(session.id); }); sids.forEach(function (sid) { self.sessions[sid].closed(reason); }); process.nextTick(function () { utils.invokeCallback(cb); }); } else { process.nextTick(function () { utils.invokeCallback(cb); }); } } /** * Kick a user offline by session id. * * @param {Number} sid session id * @param {Function} cb callback function * * @memberOf SessionService */ kickBySessionId(sid, reason, cb) { if (typeof reason === 'function') { cb = reason; reason = 'kick'; } let session = this.get(sid); if (session) { // notify client session.closed(reason); process.nextTick(function () { utils.invokeCallback(cb); }); } else { process.nextTick(function () { utils.invokeCallback(cb); }); } } /** * Get client remote address by session id. * * @param {Number} sid session id * @return {Object} remote address of client * * @memberOf SessionService */ getClientAddressBySessionId(sid) { let session = this.get(sid); if (session) { let socket = session.__socket__; return socket.remoteAddress; } else { return null; } } /** * Send message to the client by session id. * * @param {String} sid session id * @param {Object} msg message to send * * @memberOf SessionService * @api private */ sendMessage(sid, msg) { let session = this.sessions[sid]; if (!session) { logger.debug('Fail to send message for non-existing session, sid: ' + sid + ' msg: ' + msg); return false; } return send(this, session, msg); } /** * Send message to the client by user id. * * @param {String} uid userId * @param {Object} msg message to send * * @memberOf SessionService * @api private */ sendMessageByUid(uid, msg) { let sessions = this.uidMap[uid]; if (!sessions) { logger.debug('fail to send message by uid for non-existing session. uid: %j', uid); return false; } for (let i = 0, l = sessions.length; i < l; i++) { send(this, sessions[i], msg); } } /** * Iterate all the session in the session service. * * @param {Function} cb callback function to fetch session * @api private */ forEachSession(cb) { for (let sid in this.sessions) { cb(this.sessions[sid]); } } /** * Iterate all the binded session in the session service. * * @param {Function} cb callback function to fetch session * @api private */ forEachBindedSession(cb) { let i, l, sessions; for (let uid in this.uidMap) { sessions = this.uidMap[uid]; for (i = 0, l = sessions.length; i < l; i++) { cb(sessions[i]); } } } /** * Get sessions' quantity in specified server. * */ getSessionsCount() { return Object.keys(this.sessions).length; } } exports.SessionService = SessionService; /** * Send message to the client that associated with the session. * * @api private */ let send = function (service, session, msg) { session.send(msg); return true; }; /** * Session maintains the relationship between client connection and user information. * There is a session associated with each client connection. And it should bind to a * user id after the client passes the identification. * * Session is created in frontend server and should not be accessed in handler. * There is a proxy class called BackendSession in backend servers and FrontendSession * in frontend servers. */ class Session extends events_1.EventEmitter { constructor(sid, frontendId, socket, service) { super(); this.id = sid; // r this.frontendId = frontendId; // r this.uid = null; // r this.settings = {}; // private this.__socket__ = socket; this.__sessionService__ = service; this.__state__ = ST_INITED; } /* * Export current session as frontend session. */ toFrontendSession() { return new FrontendSession(this); } /** * Bind the session with the the uid. * * @param {Number} uid User id * @api public */ bind(uid) { this.uid = uid; this.emit('bind', uid); } /** * Unbind the session with the the uid. * * @param {Number} uid User id * @api private */ unbind(uid) { this.uid = null; this.emit('unbind', uid); } set(keyOrValues, value) { if (utils.isObject(keyOrValues)) { let values = keyOrValues; for (let i in values) { this.settings[i] = values[i]; } } else { this.settings[keyOrValues] = value; } } /** * Remove value from the session. * * @param {String} key session key * @api public */ remove(key) { delete this.settings[key]; } /** * Get value from the session. * * @param {String} key session key * @return {Object} value associated with session key * @api public */ get(key) { return this.settings[key]; } /** * Send message to the session. * * @param {Object} msg final message sent to client */ send(msg) { this.__socket__.send(msg); } /** * Send message to the session in batch. * * @param {Array} msgs list of message */ sendBatch(msgs) { this.__socket__.sendBatch(msgs); } /** * Closed callback for the session which would disconnect client in next tick. * * @api public */ closed(reason) { if (this.__state__ === ST_CLOSED) { return; } logger.debug('session on [%s] is closed with session id: %s,uid:%s,reason:%j', this.frontendId, this.id, this.uid, reason); this.__state__ = ST_CLOSED; this.__sessionService__.remove(this.id); this.emit('closed', this.toFrontendSession(), reason); this.__socket__.emit('closing', reason); let self = this; // give a chance to send disconnect message to client process.nextTick(function () { self.__socket__.disconnect(); }); } /** * 是否在线 */ get isOnline() { return this.__state__ !== ST_CLOSED; } /** * 获取客户端的地址 */ get remoteAddress() { return this.__socket__.remoteAddress; } } exports.Session = Session; /** * Frontend session for frontend server. */ class FrontendSession extends events_1.EventEmitter { constructor(session) { super(); clone(session, this, FRONTEND_SESSION_FIELDS); // deep copy for settings this.settings = dclone(session.settings); this.__session__ = session; } bind(uid, cb) { let self = this; this.__sessionService__.bind(this.id, uid, function (err) { if (!err) { self.uid = uid; } utils.invokeCallback(cb, err); }); } unbind(uid, cb) { let self = this; this.__sessionService__.unbind(this.id, uid, function (err) { if (!err) { self.uid = null; } utils.invokeCallback(cb, err); }); } set(key, value) { this.settings[key] = value; } get(key) { return this.settings[key]; } push(key, cb) { this.__sessionService__.import(this.id, key, this.get(key), cb); } pushAll(cb) { this.__sessionService__.importAll(this.id, this.settings, cb); } on(event, listener) { this.__session__.on(event, listener); return super.on(event, listener); } 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 = {}; clone(this, res, EXPORTED_SESSION_FIELDS); return res; } /** * 是否在线 */ get isOnline() { return this.__session__.isOnline; } /** * 获取客户端的地址 */ get remoteAddress() { return this.__session__.remoteAddress; } } exports.FrontendSession = FrontendSession; let clone = function (src, dest, includes) { let f; for (let i = 0, l = includes.length; i < l; i++) { f = includes[i]; dest[f] = src[f]; } }; let dclone = function (src) { let res = {}; for (let f in src) { res[f] = src[f]; } return res; }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvblNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9saWIvY29tbW9uL3NlcnZpY2Uvc2Vzc2lvblNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUNBQXNDO0FBRXRDLGlEQUEwQztBQUMxQywwQ0FBMEM7QUFHMUMsNkJBQTZCO0FBRTdCLElBQUksTUFBTSxHQUFHLElBQUEseUJBQVMsRUFBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0FBRTVELElBQUksdUJBQXVCLEdBQUcsQ0FBQyxJQUFJLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO0FBQ2hGLElBQUksdUJBQXVCLEdBQUcsQ0FBQyxJQUFJLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxVQUFVLENBQUMsQ0FBQztBQUV0RSxJQUFJLFNBQVMsR0FBRyxDQUFDLENBQUM7QUFDbEIsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0FBTWxCOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFhLGNBQWM7SUFLdkIsWUFBWSxJQUE0QjtRQWlZeEMsVUFBSyxHQUFpRCxLQUFLLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDNUYscUJBQWdCLEdBQWlELEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNsSCxVQUFLLEdBQTBDLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNyRixZQUFPLEdBQTBDLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUN6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LENBQUM7SUFFRCxFQUFFLENBQUMsS0FBc0IsRUFBRSxRQUFrQztRQUN6RCxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDckMsT0FBTyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQztJQUNyQyxDQUFDO0lBRUQsS0FBSyxDQUFDLEdBQVc7UUFDYixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNuSCxDQUFDO0lBRUQsT0FBTyxDQUFDLEdBQVc7UUFDZixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNySCxDQUFDO0lBRUQsS0FBSyxDQUFDLEdBQVc7UUFDYixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNuSCxDQUFDO0lBRUQsUUFBUTtRQUNKLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakgsQ0FBQztJQUdELGlEQUFpRDtJQUNqRCxxREFBcUQ7SUFDckQsaURBQWlEO0lBQ2pELHVEQUF1RDtJQUV2RDs7OztPQUlHO0lBQ0gsTUFBTTtRQUNGLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQztRQUNiLEtBQUssQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLHVCQUF1QixDQUFDLENBQUM7UUFDMUMsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJLFFBQVE7UUFDUixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDO0lBQ3JDLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksYUFBYTtRQUNiLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUM7SUFDMUMsQ0FBQztDQUNKO0FBeEdELDBDQXdHQztBQUVELElBQUksS0FBSyxHQUFHLFVBQVUsR0FBUSxFQUFFLElBQVMsRUFBRSxRQUFhO0lBQ3BELElBQUksQ0FBQyxDQUFDO0lBQ04sS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUM3QyxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2hCLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDcEI7QUFDTCxDQUFDLENBQUM7QUFFRixJQUFJLE1BQU0sR0FBRyxVQUFVLEdBQVE7SUFDM0IsSUFBSSxHQUFHLEdBQVEsRUFBRSxDQUFDO0lBQ2xCLEtBQUssSUFBSSxDQUFDLElBQUksR0FBRyxFQUFFO1FBQ2YsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUNuQjtJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2YsQ0FBQyxDQUFDIn0=