backendSessionService.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /**
  2. * backend session service for backend session
  3. */
  4. var utils = require('../../util/utils');
  5. var EXPORTED_FIELDS = ['id', 'frontendId', 'uid', 'settings'];
  6. /**
  7. * Service that maintains backend sessions and the communication with frontend
  8. * servers.
  9. *
  10. * BackendSessionService would be created in each server process and maintains
  11. * backend sessions for current process and communicates with the relative
  12. * frontend servers.
  13. *
  14. * BackendSessionService instance could be accessed by
  15. * `app.get('backendSessionService')` or app.backendSessionService.
  16. *
  17. * @class
  18. * @constructor
  19. */
  20. var BackendSessionService = function(app) {
  21. this.app = app;
  22. };
  23. module.exports = BackendSessionService;
  24. BackendSessionService.prototype.create = function(opts) {
  25. if(!opts) {
  26. throw new Error('opts should not be empty.');
  27. }
  28. return new BackendSession(opts, this);
  29. };
  30. /**
  31. * Get backend session by frontend server id and session id.
  32. *
  33. * @param {String} frontendId frontend server id that session attached
  34. * @param {String} sid session id
  35. * @param {Function} cb callback function. args: cb(err, BackendSession)
  36. *
  37. * @memberOf BackendSessionService
  38. */
  39. BackendSessionService.prototype.get = function(frontendId, sid, cb) {
  40. var namespace = 'sys';
  41. var service = 'sessionRemote';
  42. var method = 'getBackendSessionBySid';
  43. var args = [sid];
  44. rpcInvoke(this.app, frontendId, namespace, service, method,
  45. args, BackendSessionCB.bind(null, this, cb));
  46. };
  47. /**
  48. * Get backend sessions by frontend server id and user id.
  49. *
  50. * @param {String} frontendId frontend server id that session attached
  51. * @param {String} uid user id binded with the session
  52. * @param {Function} cb callback function. args: cb(err, BackendSessions)
  53. *
  54. * @memberOf BackendSessionService
  55. */
  56. BackendSessionService.prototype.getByUid = function(frontendId, uid, cb) {
  57. var namespace = 'sys';
  58. var service = 'sessionRemote';
  59. var method = 'getBackendSessionsByUid';
  60. var args = [uid];
  61. rpcInvoke(this.app, frontendId, namespace, service, method,
  62. args, BackendSessionCB.bind(null, this, cb));
  63. };
  64. /**
  65. * Kick a session by session id.
  66. *
  67. * @param {String} frontendId cooperating frontend server id
  68. * @param {Number} sid session id
  69. * @param {Function} cb callback function
  70. *
  71. * @memberOf BackendSessionService
  72. */
  73. BackendSessionService.prototype.kickBySid = function(frontendId, sid, reason, cb) {
  74. var namespace = 'sys';
  75. var service = 'sessionRemote';
  76. var method = 'kickBySid';
  77. var args = [sid];
  78. if(typeof reason === 'function') {
  79. cb = reason;
  80. }else{
  81. args.push(reason);
  82. }
  83. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  84. };
  85. /**
  86. * Kick sessions by user id.
  87. *
  88. * @param {String} frontendId cooperating frontend server id
  89. * @param {Number|String} uid user id
  90. * @param {String} reason kick reason
  91. * @param {Function} cb callback function
  92. *
  93. * @memberOf BackendSessionService
  94. */
  95. BackendSessionService.prototype.kickByUid = function(frontendId, uid, reason, cb) {
  96. var namespace = 'sys';
  97. var service = 'sessionRemote';
  98. var method = 'kickByUid';
  99. var args = [uid];
  100. if(typeof reason === 'function') {
  101. cb = reason;
  102. }else{
  103. args.push(reason);
  104. }
  105. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  106. };
  107. /**
  108. * Bind the session with the specified user id. It would finally invoke the
  109. * the sessionService.bind in the cooperating frontend server.
  110. *
  111. * @param {String} frontendId cooperating frontend server id
  112. * @param {Number} sid session id
  113. * @param {String} uid user id
  114. * @param {Function} cb callback function
  115. *
  116. * @memberOf BackendSessionService
  117. * @api private
  118. */
  119. BackendSessionService.prototype.bind = function(frontendId, sid, uid, cb) {
  120. var namespace = 'sys';
  121. var service = 'sessionRemote';
  122. var method = 'bind';
  123. var args = [sid, uid];
  124. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  125. };
  126. /**
  127. * Unbind the session with the specified user id. It would finally invoke the
  128. * the sessionService.unbind in the cooperating frontend server.
  129. *
  130. * @param {String} frontendId cooperating frontend server id
  131. * @param {Number} sid session id
  132. * @param {String} uid user id
  133. * @param {Function} cb callback function
  134. *
  135. * @memberOf BackendSessionService
  136. * @api private
  137. */
  138. BackendSessionService.prototype.unbind = function(frontendId, sid, uid, cb) {
  139. var namespace = 'sys';
  140. var service = 'sessionRemote';
  141. var method = 'unbind';
  142. var args = [sid, uid];
  143. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  144. };
  145. /**
  146. * Push the specified customized change to the frontend internal session.
  147. *
  148. * @param {String} frontendId cooperating frontend server id
  149. * @param {Number} sid session id
  150. * @param {String} key key in session that should be push
  151. * @param {Object} value value in session, primitive js object
  152. * @param {Function} cb callback function
  153. *
  154. * @memberOf BackendSessionService
  155. * @api private
  156. */
  157. BackendSessionService.prototype.push = function(frontendId, sid, key, value, cb) {
  158. var namespace = 'sys';
  159. var service = 'sessionRemote';
  160. var method = 'push';
  161. var args = [sid, key, value];
  162. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  163. };
  164. /**
  165. * Push all the customized changes to the frontend internal session.
  166. *
  167. * @param {String} frontendId cooperating frontend server id
  168. * @param {Number} sid session id
  169. * @param {Object} settings key/values in session that should be push
  170. * @param {Function} cb callback function
  171. *
  172. * @memberOf BackendSessionService
  173. * @api private
  174. */
  175. BackendSessionService.prototype.pushAll = function(frontendId, sid, settings, cb) {
  176. var namespace = 'sys';
  177. var service = 'sessionRemote';
  178. var method = 'pushAll';
  179. var args = [sid, settings];
  180. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  181. };
  182. var rpcInvoke = function(app, sid, namespace, service, method, args, cb) {
  183. app.rpcInvoke(sid, {namespace: namespace, service: service, method: method, args: args}, cb);
  184. };
  185. /**
  186. * BackendSession is the proxy for the frontend internal session passed to handlers and
  187. * it helps to keep the key/value pairs for the server locally.
  188. * Internal session locates in frontend server and should not be accessed directly.
  189. *
  190. * The mainly operation on backend session should be read and any changes happen in backend
  191. * session is local and would be discarded in next request. You have to push the
  192. * changes to the frontend manually if necessary. Any push would overwrite the last push
  193. * of the same key silently and the changes would be saw in next request.
  194. * And you have to make sure the transaction outside if you would push the session
  195. * concurrently in different processes.
  196. *
  197. * See the api below for more details.
  198. *
  199. * @class
  200. * @constructor
  201. */
  202. var BackendSession = function(opts, service) {
  203. for(var f in opts) {
  204. this[f] = opts[f];
  205. }
  206. this.__sessionService__ = service;
  207. };
  208. /**
  209. * Bind current session with the user id. It would push the uid to frontend
  210. * server and bind uid to the frontend internal session.
  211. *
  212. * @param {Number|String} uid user id
  213. * @param {Function} cb callback function
  214. *
  215. * @memberOf BackendSession
  216. */
  217. BackendSession.prototype.bind = function(uid, cb) {
  218. var self = this;
  219. this.__sessionService__.bind(this.frontendId, this.id, uid, function(err) {
  220. if(!err) {
  221. self.uid = uid;
  222. }
  223. utils.invokeCallback(cb, err);
  224. });
  225. };
  226. /**
  227. * Unbind current session with the user id. It would push the uid to frontend
  228. * server and unbind uid from the frontend internal session.
  229. *
  230. * @param {Number|String} uid user id
  231. * @param {Function} cb callback function
  232. *
  233. * @memberOf BackendSession
  234. */
  235. BackendSession.prototype.unbind = function(uid, cb) {
  236. var self = this;
  237. this.__sessionService__.unbind(this.frontendId, this.id, uid, function(err) {
  238. if(!err) {
  239. self.uid = null;
  240. }
  241. utils.invokeCallback(cb, err);
  242. });
  243. };
  244. /**
  245. * Set the key/value into backend session.
  246. *
  247. * @param {String} key key
  248. * @param {Object} value value
  249. */
  250. BackendSession.prototype.set = function(key, value) {
  251. this.settings[key] = value;
  252. };
  253. /**
  254. * Get the value from backend session by key.
  255. *
  256. * @param {String} key key
  257. * @return {Object} value
  258. */
  259. BackendSession.prototype.get = function(key) {
  260. return this.settings[key];
  261. };
  262. /**
  263. * Push the key/value in backend session to the front internal session.
  264. *
  265. * @param {String} key key
  266. * @param {Function} cb callback function
  267. */
  268. BackendSession.prototype.push = function(key, cb) {
  269. this.__sessionService__.push(this.frontendId, this.id, key, this.get(key), cb);
  270. };
  271. /**
  272. * Push all the key/values in backend session to the frontend internal session.
  273. *
  274. * @param {Function} cb callback function
  275. */
  276. BackendSession.prototype.pushAll = function(cb) {
  277. this.__sessionService__.pushAll(this.frontendId, this.id, this.settings, cb);
  278. };
  279. /**
  280. * Export the key/values for serialization.
  281. *
  282. * @api private
  283. */
  284. BackendSession.prototype.export = function() {
  285. var res = {};
  286. EXPORTED_FIELDS.forEach(function(field) {
  287. res[field] = this[field];
  288. });
  289. return res;
  290. };
  291. var BackendSessionCB = function(service, cb, err, sinfo) {
  292. if(err) {
  293. utils.invokeCallback(cb, err);
  294. return;
  295. }
  296. if(!sinfo) {
  297. utils.invokeCallback(cb);
  298. return;
  299. }
  300. var sessions = [];
  301. if(Array.isArray(sinfo)){
  302. // #getByUid
  303. for(var i = 0,k = sinfo.length;i<k;i++){
  304. sessions.push(service.create(sinfo[i]));
  305. }
  306. }
  307. else{
  308. // #get
  309. sessions = service.create(sinfo);
  310. }
  311. utils.invokeCallback(cb, null, sessions);
  312. };