backendSessionService.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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 communiation 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 userstate id.
  49. *
  50. * @param {String} frontendId frontend server id that session attached
  51. * @param {String} uid userstate 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, cb) {
  74. var namespace = 'sys';
  75. var service = 'sessionRemote';
  76. var method = 'kickBySid';
  77. var args = [sid];
  78. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  79. };
  80. /**
  81. * Kick sessions by userstate id.
  82. *
  83. * @param {String} frontendId cooperating frontend server id
  84. * @param {Number|String} uid userstate id
  85. * @param {Function} cb callback function
  86. *
  87. * @memberOf BackendSessionService
  88. */
  89. BackendSessionService.prototype.kickByUid = function(frontendId, uid, cb) {
  90. var namespace = 'sys';
  91. var service = 'sessionRemote';
  92. var method = 'kickByUid';
  93. var args = [uid];
  94. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  95. };
  96. /**
  97. * Bind the session with the specified userstate id. It would finally invoke the
  98. * the sessionService.bind in the cooperating frontend server.
  99. *
  100. * @param {String} frontendId cooperating frontend server id
  101. * @param {Number} sid session id
  102. * @param {String} uid userstate id
  103. * @param {Function} cb callback function
  104. *
  105. * @memberOf BackendSessionService
  106. * @api private
  107. */
  108. BackendSessionService.prototype.bind = function(frontendId, sid, uid, cb) {
  109. var namespace = 'sys';
  110. var service = 'sessionRemote';
  111. var method = 'bind';
  112. var args = [sid, uid];
  113. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  114. };
  115. /**
  116. * Unbind the session with the specified userstate id. It would finally invoke the
  117. * the sessionService.unbind in the cooperating frontend server.
  118. *
  119. * @param {String} frontendId cooperating frontend server id
  120. * @param {Number} sid session id
  121. * @param {String} uid userstate id
  122. * @param {Function} cb callback function
  123. *
  124. * @memberOf BackendSessionService
  125. * @api private
  126. */
  127. BackendSessionService.prototype.unbind = function(frontendId, sid, uid, cb) {
  128. var namespace = 'sys';
  129. var service = 'sessionRemote';
  130. var method = 'unbind';
  131. var args = [sid, uid];
  132. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  133. };
  134. /**
  135. * Push the specified customized change to the frontend internal session.
  136. *
  137. * @param {String} frontendId cooperating frontend server id
  138. * @param {Number} sid session id
  139. * @param {String} key key in session that should be push
  140. * @param {Object} value value in session, primitive js object
  141. * @param {Function} cb callback function
  142. *
  143. * @memberOf BackendSessionService
  144. * @api private
  145. */
  146. BackendSessionService.prototype.push = function(frontendId, sid, key, value, cb) {
  147. var namespace = 'sys';
  148. var service = 'sessionRemote';
  149. var method = 'push';
  150. var args = [sid, key, value];
  151. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  152. };
  153. /**
  154. * Push all the customized changes to the frontend internal session.
  155. *
  156. * @param {String} frontendId cooperating frontend server id
  157. * @param {Number} sid session id
  158. * @param {Object} settings key/values in session that should be push
  159. * @param {Function} cb callback function
  160. *
  161. * @memberOf BackendSessionService
  162. * @api private
  163. */
  164. BackendSessionService.prototype.pushAll = function(frontendId, sid, settings, cb) {
  165. var namespace = 'sys';
  166. var service = 'sessionRemote';
  167. var method = 'pushAll';
  168. var args = [sid, settings];
  169. rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
  170. };
  171. var rpcInvoke = function(app, sid, namespace, service, method, args, cb) {
  172. app.rpcInvoke(sid, {namespace: namespace, service: service, method: method, args: args}, cb);
  173. };
  174. /**
  175. * BackendSession is the proxy for the frontend internal session passed to handlers and
  176. * it helps to keep the key/value pairs for the server locally.
  177. * Internal session locates in frontend server and should not be accessed directly.
  178. *
  179. * The mainly operation on backend session should be read and any changes happen in backend
  180. * session is local and would be discarded in next request. You have to push the
  181. * changes to the frontend manually if necessary. Any push would overwrite the last push
  182. * of the same key silently and the changes would be saw in next request.
  183. * And you have to make sure the transaction outside if you would push the session
  184. * concurrently in different processes.
  185. *
  186. * See the api below for more details.
  187. *
  188. * @class
  189. * @constructor
  190. */
  191. var BackendSession = function(opts, service) {
  192. for(var f in opts) {
  193. this[f] = opts[f];
  194. }
  195. this.__sessionService__ = service;
  196. };
  197. /**
  198. * Bind current session with the userstate id. It would push the uid to frontend
  199. * server and bind uid to the frontend internal session.
  200. *
  201. * @param {Number|String} uid userstate id
  202. * @param {Function} cb callback function
  203. *
  204. * @memberOf BackendSession
  205. */
  206. BackendSession.prototype.bind = function(uid, cb) {
  207. var self = this;
  208. this.__sessionService__.bind(this.frontendId, this.id, uid, function(err) {
  209. if(!err) {
  210. self.uid = uid;
  211. }
  212. utils.invokeCallback(cb, err);
  213. });
  214. };
  215. /**
  216. * Unbind current session with the userstate id. It would push the uid to frontend
  217. * server and unbind uid from the frontend internal session.
  218. *
  219. * @param {Number|String} uid userstate id
  220. * @param {Function} cb callback function
  221. *
  222. * @memberOf BackendSession
  223. */
  224. BackendSession.prototype.unbind = function(uid, cb) {
  225. var self = this;
  226. this.__sessionService__.unbind(this.frontendId, this.id, uid, function(err) {
  227. if(!err) {
  228. self.uid = null;
  229. }
  230. utils.invokeCallback(cb, err);
  231. });
  232. };
  233. /**
  234. * Set the key/value into backend session.
  235. *
  236. * @param {String} key key
  237. * @param {Object} value value
  238. */
  239. BackendSession.prototype.set = function(key, value) {
  240. this.settings[key] = value;
  241. };
  242. /**
  243. * Get the value from backend session by key.
  244. *
  245. * @param {String} key key
  246. * @return {Object} value
  247. */
  248. BackendSession.prototype.get = function(key) {
  249. return this.settings[key];
  250. };
  251. /**
  252. * Push the key/value in backend session to the front internal session.
  253. *
  254. * @param {String} key key
  255. * @param {Function} cb callback function
  256. */
  257. BackendSession.prototype.push = function(key, cb) {
  258. this.__sessionService__.push(this.frontendId, this.id, key, this.get(key), cb);
  259. };
  260. /**
  261. * Push all the key/values in backend session to the frontend internal session.
  262. *
  263. * @param {Function} cb callback function
  264. */
  265. BackendSession.prototype.pushAll = function(cb) {
  266. this.__sessionService__.pushAll(this.frontendId, this.id, this.settings, cb);
  267. };
  268. /**
  269. * Export the key/values for serialization.
  270. *
  271. * @api private
  272. */
  273. BackendSession.prototype.export = function() {
  274. var res = {};
  275. EXPORTED_FIELDS.forEach(function(field) {
  276. res[field] = this[field];
  277. });
  278. return res;
  279. };
  280. var BackendSessionCB = function(service, cb, err, sinfo) {
  281. if(err) {
  282. utils.invokeCallback(cb, err);
  283. return;
  284. }
  285. if(!sinfo) {
  286. utils.invokeCallback(cb);
  287. return;
  288. }
  289. var sessions = [];
  290. if(Array.isArray(sinfo)){
  291. // #getByUid
  292. for(var i = 0,k = sinfo.length;i<k;i++){
  293. sessions.push(service.create(sinfo[i]));
  294. }
  295. }
  296. else{
  297. // #get
  298. sessions = service.create(sinfo);
  299. }
  300. utils.invokeCallback(cb, null, sessions);
  301. };