sessions.js 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262
  1. /**
  2. * 会话模型。
  3. */
  4. "use strict";
  5. let RedisClient = require('../../repository/redis/redis.client.js');
  6. let RedisModel = require('./../redis.model.js');
  7. let ModelUtil = require('../../util/model.util');
  8. let Messages = require('../messages/messages');
  9. let Users = require('../user/users');
  10. let Participants = require('./participants');
  11. let SessionRepo = require('../../repository/mysql/session.repo');
  12. let TopicRepo = require('../../repository/mysql/topics.repo');
  13. let ParticipantRepo = require('../../repository/mysql/participant.repo');
  14. let WechatClient = require("../client/wechat.client.js");
  15. let AppClient = require("../client/app.client.js");
  16. let configFile = require('../../include/commons').CONFIG_FILE;
  17. let config = require('../../resources/config/' + configFile);
  18. let redis = RedisClient.redisClient().connection;
  19. let logger = require('../../util/log.js');
  20. let mongoose = require('mongoose');
  21. let async = require("async");
  22. let log = require("../../util/log.js");
  23. const REDIS_KEYS = require('../../include/commons').REDIS_KEYS;
  24. const SESSION_TYPES = require('../../include/commons').SESSION_TYPES;
  25. const STICKY_SESSION_BASE_SCORE = require('../../include/commons').STICKY_SESSION_BASE_SCORE;
  26. const PARTICIPANT_ROLES = require('../../include/commons').PARTICIPANT_ROLES;
  27. const CONTENT_TYPES = require('../../include/commons').CONTENT_TYPES;
  28. const SESSION_BUSINESS_TYPE = require('../../include/commons').SESSION_BUSINESS_TYPE;
  29. class Sessions extends RedisModel {
  30. constructor() {
  31. super();
  32. }
  33. /**
  34. * 创建会话。会话的ID来源:
  35. * MUC:患者的ID
  36. * P2P:对成员的ID排序后,取hash值
  37. * GROUP:团队的ID
  38. *
  39. * @param sessionId
  40. * @param name 会话名称
  41. * @param type 会话类型
  42. * @param participantArray 会话成员
  43. * @param handler 回调,仅MUC模式使用
  44. */
  45. createSession(sessionId, name, type, participantArray, handler) {
  46. let self = this;
  47. let messageId = mongoose.Types.ObjectId().toString();
  48. //创建session到mysql
  49. self.createSessionToMysql(sessionId, name, type, participantArray, messageId, function (err, res) {
  50. if (err) {
  51. if (handler) {
  52. handler(err, null);
  53. return;
  54. }
  55. ModelUtil.emitError(self.eventEmitter, {message: err, status: -1}, null);
  56. } else {
  57. //创建session到redis
  58. self.createSessionToRedis(sessionId, name, type, participantArray, messageId, function (err, res) {
  59. if (err) {
  60. if (handler) {
  61. handler(err, null);
  62. return;
  63. }
  64. ModelUtil.emitError(self.eventEmitter, {message: err, status: -1}, null);
  65. } else {
  66. //更新成为进行中的会话
  67. self.updateSessionStatus(sessionId,0);
  68. if (handler) {
  69. handler(null, res);
  70. return;
  71. }
  72. ModelUtil.emitOK(self.eventEmitter, {status: 200, data: res});
  73. }
  74. });
  75. }
  76. });
  77. }
  78. /**
  79. * 创建会话。REDIS
  80. * @param sessionId
  81. * @param name
  82. * @param type
  83. * @param participantArray
  84. * @param messageId
  85. * @param handler
  86. * @returns {boolean}
  87. */
  88. createSessionToRedis(sessionId, name, type, participantArray, messageId, handler) {
  89. let self = this;
  90. let messages = new Messages();
  91. let participantIdArray = [];
  92. for (let i in participantArray) {
  93. participantIdArray.push(participantArray[i].split(":")[0]);
  94. }
  95. if (type == SESSION_TYPES.P2P || type == SESSION_TYPES.SYSTEM) {
  96. if (sessionId) {
  97. callBusinessType(sessionId);
  98. return;
  99. }
  100. else if (participantIdArray.length != 2) {
  101. handler("P2P session only allow 2 participants.", null);
  102. return false;
  103. }else{
  104. ParticipantRepo.findSessionIdByParticipantIds(participantIdArray[0], participantIdArray[1], function (err, res) {
  105. sessionId = res;
  106. callBusinessType(sessionId);
  107. return;
  108. });
  109. }
  110. } else {
  111. if (!sessionId) {
  112. handler("MUC OR GROUP session sessionId is not allow null .", null);
  113. return;
  114. }
  115. callBusinessType(sessionId);
  116. }
  117. function callBusinessType(sessionId) {
  118. ParticipantRepo.getBusinessType(participantIdArray, function (err, businessType) {
  119. callCreate(sessionId, businessType);
  120. });
  121. }
  122. function callCreate(sessionId, businessType) {
  123. let createDate = new Date();
  124. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  125. let message = {
  126. sender_id: "system",
  127. sender_name: "系统",
  128. content_type: 11,
  129. content: "会话创建成功",
  130. timestamp: createDate,
  131. id: messageId
  132. };
  133. if (type == SESSION_TYPES.MUC) {
  134. businessType = 2;
  135. }
  136. let session = {
  137. id: sessionId,
  138. name: name,
  139. type: type,
  140. create_date: createDate.getTime(),
  141. business_type: businessType,
  142. last_sender_id: message.sender_id,
  143. last_sender_name: message.sender_name,
  144. last_message_time: message.timestamp.getTime(),
  145. last_content: message.content,
  146. last_content_type: message.content_type
  147. };
  148. redis.hmsetAsync(sessionKey, session).then(function () {
  149. Participants.saveParticipantsToRedis(sessionId, participantArray, createDate, function (res) {
  150. handler(null, session);
  151. //messages.saveMessageToRedisFromCreateSession(sessionId, messageId, message);
  152. });
  153. })
  154. }
  155. }
  156. /**
  157. * 创建会话。mysql
  158. * @param sessionId
  159. * @param name
  160. * @param type
  161. * @param participantArray
  162. * @param messageId
  163. * @param handler
  164. */
  165. createSessionToMysql(sessionId, name, type, participantArray, messageId, handler) {
  166. let self = this;
  167. //如果sessionId不存在则执行创建sessionId过程
  168. let participantIdArray = [];
  169. for (let i in participantArray) {
  170. participantIdArray.push(participantArray[i].split(":")[0]);
  171. }
  172. //流程1-判断是否存在sessionId不存在则创建对应的sessionId;
  173. if (!sessionId) {
  174. if (type == SESSION_TYPES.P2P || type == SESSION_TYPES.SYSTEM) {
  175. ParticipantRepo.findSessionIdByParticipantIds(participantIdArray[0], participantIdArray[1], function (err, res) {
  176. sessionId = res;
  177. callBusinessType();
  178. });
  179. } else {
  180. return handler("MUC模式和团队模式,不允许sessionId为空!", null);
  181. }
  182. } else {
  183. callBusinessType();
  184. }
  185. //流程2-判断session的业务类型;
  186. function callBusinessType() {
  187. ParticipantRepo.getBusinessType(participantIdArray, function (err, businessType) {
  188. if (err) {
  189. handler(err, null);
  190. return;
  191. }
  192. callCreateSession(businessType);
  193. });
  194. }
  195. //流程3-发起session创建 返回session实例
  196. function callCreateSession(businessType) {
  197. //查找该sessionId是否存在存在则直接返回实例
  198. SessionRepo.findOne(sessionId, function (err, res) {
  199. if (res.length > 0) {//已经存在
  200. //更新成员
  201. Participants.saveParticipantsToMysql(sessionId, participantArray, function (err, update) {
  202. handler(null, res[0]);
  203. return;
  204. })
  205. } else {
  206. let createDate = new Date();
  207. let session = {
  208. id: sessionId,
  209. name: name,
  210. type: type,
  211. create_date: createDate.getTime(),
  212. business_type: businessType
  213. };
  214. //将session写入数据库
  215. self.saveSessionToMysql(sessionId, name, type, createDate, businessType, function (err, res) {
  216. if (err) {
  217. handler(err, null);
  218. return;
  219. }
  220. callCreateParticipants(session);
  221. })
  222. }
  223. });
  224. }
  225. //流程4-发起session成员创建
  226. function callCreateParticipants(session) {
  227. Participants.saveParticipantsToMysql(sessionId, participantArray, function (err, res) {
  228. if (err) {
  229. handler(err, null);
  230. return;
  231. } else {
  232. handler(null, session);
  233. return;
  234. }
  235. })
  236. }
  237. }
  238. /**
  239. * 最近会话列表,7天内。
  240. *
  241. * @param userId
  242. * @param dateSpan
  243. */
  244. getRecentSessions(userId, dateSpan) {
  245. let self = this;
  246. SessionRepo.findAllByTimestampAndType(userId, dateSpan, function (err, res) {
  247. if (err) {
  248. ModelUtil.emitError(self.eventEmitter, "Get recent sessions failed", err);
  249. return;
  250. }
  251. let sessions = [];
  252. res.forEach(function (session) {
  253. sessions.push({
  254. id: session.id,
  255. name: session.name,
  256. type: session.type,
  257. business_type: session.business_type,
  258. create_date: session.create_date
  259. })
  260. });
  261. ModelUtil.emitOK(self.eventEmitter, sessions);
  262. });
  263. }
  264. /**
  265. * 保存session到MySQL
  266. * @param sessionId
  267. * @param name
  268. * @param type
  269. * @param createDate
  270. * @param businessType
  271. * @param handler
  272. */
  273. saveSessionToMysql(sessionId, name, type, createDate, businessType, handler) {
  274. SessionRepo.saveSession(sessionId, name, type, createDate, businessType, handler);
  275. }
  276. /**
  277. * 获取某个用户的全部session列表
  278. * @param userId
  279. * @param handler
  280. */
  281. getUserSessionsFromMysql(userId, handler) {
  282. SessionRepo.findAll(userId, handler);
  283. }
  284. /**
  285. * 获取session单个对象
  286. * @param sessionId
  287. * @param handler
  288. */
  289. getSessions(sessionId, handler) {
  290. SessionRepo.findOne(sessionId, handler);
  291. }
  292. /**
  293. * 根据用户ID获取用户的session列表
  294. * @param userId
  295. * @param page
  296. * @param size
  297. * @param businessType
  298. */
  299. getUserSessions(userId, page, size, businessType) {
  300. let userSessionKey = RedisModel.makeRedisKey(REDIS_KEYS.UserSessions, userId);
  301. let self = this;
  302. if (page > 0) {
  303. if (page == 1) {
  304. page = 0;
  305. }
  306. page = page + page * size;
  307. }
  308. async.waterfall([
  309. // 获取会话ID列表
  310. function (callback) {
  311. redis.zrevrangeAsync(userSessionKey, page, size)
  312. .then(function (sessionIds) {
  313. if (sessionIds.length == 0) {
  314. ModelUtil.emitOK(self.eventEmitter, []);
  315. return;
  316. }
  317. callback(null, sessionIds);
  318. })
  319. },
  320. // 遍历会话
  321. function (sessionIds) {
  322. let sessionList = [];
  323. let functionList = [];
  324. for (let j = 0; j < sessionIds.length; j++) {
  325. let fun = function (index, callback) {
  326. if (!callback) {
  327. callback = index, index = 0
  328. }
  329. let sessionId = sessionIds[index];
  330. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  331. let participantsRoleKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipantsRole, sessionId);
  332. let sessionParticipantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  333. redis.multi()
  334. .hgetall(sessionKey) // 会话实体
  335. .hget(participantsRoleKey, userId) // 用户在此会话中的角色
  336. .zscore(sessionParticipantsKey, userId) // 用户在此会话中最后一次获取未读消息的时间
  337. .zrange(sessionParticipantsKey, 0, -1)
  338. .zrange(sessionParticipantsKey, 0,-1,'withscores') // 所有用户在此会话中最后一次获取未读消息的时间
  339. .execAsync()
  340. .then(function (res) {
  341. let session = res[0];
  342. let role = res[1];
  343. let lastFetchTime = res[2];
  344. let users = res[3];
  345. let participantsTimeArray = res[4];
  346. let participantsTime = [];
  347. for(var j = 0 ;j<participantsTimeArray.length;j++){
  348. if(j%2!=0)continue;
  349. let participantsTimeJson = {};
  350. participantsTimeJson[participantsTimeArray[j]] = participantsTimeArray[j+1];
  351. participantsTime.push(participantsTimeJson);
  352. }
  353. let sessionName = "";
  354. let otherUserId = "";
  355. if (session.type == SESSION_TYPES.P2P) {
  356. for (let j in users) {
  357. if (users[j] != userId) {
  358. otherUserId = users[j];
  359. }
  360. }
  361. }
  362. if (!role) role = 0;
  363. if (!lastFetchTime) lastFetchTime = new Date().getTime();
  364. // 计算未读消息数
  365. let messagesByTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  366. redis.zcountAsync(messagesByTimestampKey, lastFetchTime, new Date().getTime())
  367. .then(function (count) {
  368. if (!otherUserId) otherUserId = userId;
  369. ParticipantRepo.findNameById(otherUserId, function (err, res) {
  370. if ((res && res.length == 0) || session.type != SESSION_TYPES.P2P) {
  371. sessionName = session.name;
  372. } else {
  373. sessionName = res[0].name;
  374. }
  375. var bir = new Date().getTime();
  376. if (res.length != 0 && res[0].birthdate) {
  377. bir = res[0].birthdate.getTime();
  378. }
  379. var sex = 1;
  380. if (res.length != 0 && res[0].sex) {
  381. sex = res[0].sex;
  382. }
  383. sessionList.push({
  384. id: sessionId,
  385. name: sessionName,
  386. create_date: session.create_date,
  387. last_content_type: session.last_content_type,
  388. last_content: session.last_content,
  389. sender_id: session.last_sender_id,
  390. type: session.type,
  391. sender_name: session.last_sender_name,
  392. unread_count: count,
  393. business_type: session.business_type,
  394. my_role: role,
  395. sender_sex: sex,
  396. sender_birthday: bir,
  397. participantsTimeArray:participantsTime,
  398. status:session.status
  399. });
  400. index = (parseInt(index) + 1);
  401. if (index == sessionIds.length) {
  402. ModelUtil.emitOK(self.eventEmitter, sessionList);
  403. } else {
  404. callback(null, index);
  405. }
  406. })
  407. })
  408. })
  409. .catch(function (err) {
  410. logger.error("Get sessions failed: ", err);
  411. });
  412. };
  413. functionList.push(fun);
  414. }
  415. async.waterfall(functionList);
  416. }
  417. ]);
  418. }
  419. /**
  420. * 根据用户ID获取用户已经结束咨询的session列表
  421. * @param userId
  422. * @param page
  423. * @param size
  424. * @param businessType
  425. */
  426. getUserStatusSessions(userId,status,businessType,page, size) {
  427. let userSessionKey = RedisModel.makeRedisKey(REDIS_KEYS.UserSessions, userId);
  428. let self = this;
  429. async.waterfall([
  430. // 获取会话ID列表
  431. function (callback) {
  432. SessionRepo.findAllByTypeAndStatus(userId,businessType,status,page,size,function(err,res){
  433. if (res.length == 0) {
  434. ModelUtil.emitOK(self.eventEmitter, []);
  435. return;
  436. }
  437. var sessionIds=[];
  438. for(var j in res){
  439. sessionIds.push(res[j].id);
  440. }
  441. callback(null,sessionIds);
  442. })
  443. },
  444. // 遍历会话
  445. function (sessionIds) {
  446. let sessionList = [];
  447. let functionList = [];
  448. for (let j = 0; j < sessionIds.length; j++) {
  449. let fun = function (index, callback) {
  450. if (!callback) {
  451. callback = index, index = 0
  452. }
  453. let sessionId = sessionIds[index];
  454. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  455. let participantsRoleKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipantsRole, sessionId);
  456. let sessionParticipantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  457. redis.multi()
  458. .hgetall(sessionKey) // 会话实体
  459. .hget(participantsRoleKey, userId) // 用户在此会话中的角色
  460. .zscore(sessionParticipantsKey, userId) // 用户在此会话中最后一次获取未读消息的时间
  461. .zrange(sessionParticipantsKey, 0, -1)
  462. .zrange(sessionParticipantsKey, 0,-1,'withscores') // 所有用户在此会话中最后一次获取未读消息的时间
  463. .execAsync()
  464. .then(function (res) {
  465. let session = res[0];
  466. let role = res[1];
  467. let lastFetchTime = res[2];
  468. let users = res[3];
  469. let participantsTimeArray = res[4];
  470. let participantsTime = [];
  471. for(var j = 0 ;j<participantsTimeArray.length;j++){
  472. if(j%2!=0)continue;
  473. let participantsTimeJson = {};
  474. participantsTimeJson[participantsTimeArray[j]] = participantsTimeArray[j+1];
  475. participantsTime.push(participantsTimeJson);
  476. }
  477. let sessionName = "";
  478. let otherUserId = "";
  479. if (session.type == SESSION_TYPES.P2P) {
  480. for (let j in users) {
  481. if (users[j] != userId) {
  482. otherUserId = users[j];
  483. }
  484. }
  485. }
  486. if (!role) role = 0;
  487. if (!lastFetchTime) lastFetchTime = new Date().getTime();
  488. // 计算未读消息数
  489. let messagesByTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  490. redis.zcountAsync(messagesByTimestampKey, lastFetchTime, new Date().getTime())
  491. .then(function (count) {
  492. if (!otherUserId) otherUserId = userId;
  493. ParticipantRepo.findNameById(otherUserId, function (err, res) {
  494. if ((res && res.length == 0) || session.type != SESSION_TYPES.P2P) {
  495. sessionName = session.name;
  496. } else {
  497. sessionName = res[0].name;
  498. }
  499. var bir = new Date().getTime();
  500. if (res.length != 0 && res[0].birthdate) {
  501. bir = res[0].birthdate.getTime();
  502. }
  503. var sex = 1;
  504. if (res.length != 0 && res[0].sex) {
  505. sex = res[0].sex;
  506. }
  507. sessionList.push({
  508. id: sessionId,
  509. name: sessionName,
  510. create_date: session.create_date,
  511. last_content_type: session.last_content_type,
  512. last_content: session.last_content,
  513. sender_id: session.last_sender_id,
  514. type: session.type,
  515. sender_name: session.last_sender_name,
  516. unread_count: count,
  517. business_type: session.business_type,
  518. my_role: role,
  519. sender_sex: sex,
  520. sender_birthday: bir,
  521. participantsTimeArray:participantsTime,
  522. status:session.status
  523. });
  524. index = (parseInt(index) + 1);
  525. if (index == sessionIds.length) {
  526. ModelUtil.emitOK(self.eventEmitter, sessionList);
  527. } else {
  528. callback(null, index);
  529. }
  530. })
  531. })
  532. })
  533. .catch(function (err) {
  534. logger.error("Get sessions failed: ", err);
  535. });
  536. };
  537. functionList.push(fun);
  538. }
  539. async.waterfall(functionList);
  540. }
  541. ]);
  542. }
  543. /**
  544. * 获取会话消息。全部,不管已读/未读状态。
  545. *
  546. * @param sessionId 会话ID
  547. * @param userId 拉取消息的人
  548. * @param page 第几页
  549. * @param pagesize 分页数量
  550. * @param start_msg_id 消息会话最新的一条消息的ID
  551. * @param end_msg_id 消息会话刚开始的消息ID
  552. * @remark
  553. * start_msg_id end_msg_id 为空取会话倒序的根据分页的消息数据
  554. * start_msg_id 为空 end_msg_id 不为空根据end_msg_id取旧的消息(offset=1可以排除本身)返回指定分页的数据
  555. * end_msg_id 为空 start_msg_id 不为空 根据 start_msg_id 取出新消息(offset=1可以排除本身)返回指定分页的数据
  556. * end_msg_id start_msg_id 都不为空返回指定区间的消息
  557. */
  558. getMessages(sessionId, user, start_msg_id, end_msg_id, page, pagesize, isoffset, handler) {
  559. let self = this;
  560. let message_timestamp_key = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  561. if (!start_msg_id && !end_msg_id) {
  562. redis.zrevrangeAsync(message_timestamp_key, 0, 0).then(function (res) {
  563. if (res.length == 0) {
  564. if (handler) {
  565. handler(null, res);
  566. return;
  567. }
  568. ModelUtil.emitOK(self.eventEmitter, res);
  569. return;
  570. }
  571. start_msg_id = res[0];
  572. redis.zrangeAsync(message_timestamp_key, 0, 0).then(function (res) {
  573. if (res.length == 0) {
  574. if (handler) {
  575. handler(null, res);
  576. return;
  577. }
  578. ModelUtil.emitOK(self.eventEmitter, res);
  579. return;
  580. }
  581. end_msg_id = res[0];
  582. self.getMessagesByPage(sessionId, user, end_msg_id, start_msg_id, page, pagesize, isoffset, function (err, res) {
  583. if (err) {
  584. if (handler) {
  585. handler(err, null);
  586. return;
  587. }
  588. logger.error("getMessagesByPage error" + err);
  589. ModelUtil.emitError(self.eventEmitter, err, err);
  590. } else {
  591. if (handler) {
  592. handler(null, res);
  593. return;
  594. }
  595. ModelUtil.emitOK(self.eventEmitter, res);
  596. }
  597. })
  598. })
  599. })
  600. } else if (!start_msg_id) {
  601. redis.zrevrangeAsync(message_timestamp_key, 0, 0).then(function (res) {
  602. if (res.length == 0) {
  603. if (handler) {
  604. handler(null, res);
  605. return;
  606. }
  607. ModelUtil.emitOK(self.eventEmitter, res);
  608. return;
  609. }
  610. start_msg_id = res[0];
  611. self.getMessagesByPage(sessionId, user, start_msg_id,end_msg_id , page, pagesize, isoffset, function (err, res) {
  612. if (err) {
  613. if (handler) {
  614. handler(err, null);
  615. return;
  616. }
  617. logger.error("getMessagesByPage error" + err);
  618. ModelUtil.emitError(self.eventEmitter, err, err);
  619. } else {
  620. if (handler) {
  621. handler(null, res);
  622. return;
  623. }
  624. ModelUtil.emitOK(self.eventEmitter, res);
  625. }
  626. })
  627. })
  628. } else if (!end_msg_id) {
  629. redis.zrangeAsync(message_timestamp_key, 0, 0).then(function (res) {
  630. if (res.length == 0) {
  631. ModelUtil.emitOK(self.eventEmitter, res);
  632. return;
  633. }
  634. end_msg_id = res[0];
  635. self.getMessagesByPage(sessionId, user, end_msg_id,start_msg_id, page, pagesize, isoffset, function (err, res) {
  636. if (err) {
  637. if (handler) {
  638. handler(err, null);
  639. return;
  640. }
  641. logger.error("getMessagesByPage error" + err);
  642. ModelUtil.emitError(self.eventEmitter, err, err);
  643. } else {
  644. if (handler) {
  645. handler(null, res);
  646. return;
  647. }
  648. ModelUtil.emitOK(self.eventEmitter, res);
  649. }
  650. })
  651. })
  652. } else {
  653. self.getMessagesByPage(sessionId, user, end_msg_id, start_msg_id, page, pagesize, isoffset, function (err, res) {
  654. if (err) {
  655. if (handler) {
  656. handler(err, null);
  657. return;
  658. }
  659. logger.error("getMessagesByPage error" + err);
  660. ModelUtil.emitError(self.eventEmitter, err, err);
  661. } else {
  662. if (handler) {
  663. handler(null, res);
  664. return;
  665. }
  666. ModelUtil.emitOK(self.eventEmitter, res);
  667. }
  668. })
  669. }
  670. }
  671. /**
  672. * 分页获取会话消息。
  673. *
  674. * @param sessionId 必选。会话ID
  675. * @param userId 必选。用户ID
  676. * @param startMsgId 必选。会话的的起始消息ID,作为检索的起始依据
  677. * @param endMsgId 必选。会话中的结束消息ID
  678. * @param page 必选。页码
  679. * @param size 必选。页面大小
  680. * @param handler 必选。回调
  681. */
  682. getMessagesByPage(sessionId, userId, startMsgId, endMsgId, page, size, isoffset, handler) {
  683. let messagesTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  684. let messagesKey = RedisModel.makeRedisKey(REDIS_KEYS.Messages, sessionId);
  685. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  686. let sessionParticipantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  687. let participants = new Participants();
  688. let offset = (page - 1 < 0 ? 0 : page - 1) * size;
  689. let count = size;
  690. if (page > 1 || isoffset == 1) {
  691. offset += 1; // 翻页由于闭区间,需跳过本身数据
  692. }
  693. participants.existsParticipant(sessionId, userId, function (err, res) {
  694. if (!res) {
  695. handler(Error("User not found in session " + sessionId), null);
  696. } else {
  697. //将消息ID转换成分值
  698. redis.multi()
  699. .zscore(messagesTimestampKey, startMsgId)
  700. .zscore(messagesTimestampKey, endMsgId)
  701. .hgetall(sessionKey)
  702. .zrange(sessionParticipantsKey, 0, -1)
  703. .execAsync()
  704. .then(function (res) {
  705. let startMsgScore = res[1];
  706. let endMsgScore = res[0];
  707. let session = res[2];
  708. let users = res[3];
  709. if (startMsgScore == null || endMsgScore == null || (startMsgScore == endMsgScore && isoffset == 1)) {
  710. handler(null, []);
  711. return;
  712. }
  713. //结束大于开始,正序取数据,返回的数据顺序也是逆序的,反向拉取数据,
  714. // 当end>start取出来都是空的,为了给前端获取新数据使用,一般不出现这种情况
  715. if(endMsgScore>startMsgScore){
  716. redis.zrangebyscoreAsync(messagesTimestampKey, startMsgScore, endMsgScore, "limit", offset, count)
  717. .then(function (res) {
  718. if (res.length == 0) {
  719. handler(null, []);
  720. return;
  721. }
  722. redis.hmgetAsync(messagesKey, res).then(function (messages) {
  723. messages.reverse();
  724. handler(null, messages);
  725. }).then(function () {
  726. Sessions.updateParticipantLastFetchTime(sessionId, userId, new Date().getTime());
  727. if(session.type == SESSION_TYPES.P2P){
  728. for(var j in users){
  729. if(users[j]==userId)continue;
  730. WechatClient.sendAllRead(users[j],sessionId);
  731. }
  732. }else if(session.type == SESSION_TYPES.MUC){
  733. for(var j in users){
  734. if(users[j]==userId)continue;
  735. WechatClient.sendMucAllRead(users[j],userId,sessionId);
  736. }
  737. }
  738. })
  739. })
  740. .catch(function (err) {
  741. logger.error("Get message by page failed: ", err);
  742. handler(err, false);
  743. })
  744. }else{
  745. // 从消息时间表中过滤出要获取的消息ID列表,倒序取出消息
  746. redis.zrevrangebyscoreAsync(messagesTimestampKey, startMsgScore, endMsgScore, "limit", offset, count)
  747. .then(function (res) {
  748. if (res.length == 0) {
  749. handler(null, []);
  750. return;
  751. }
  752. redis.hmgetAsync(messagesKey, res).then(function (messages) {
  753. handler(null, messages);
  754. }).then(function () {
  755. Sessions.updateParticipantLastFetchTime(sessionId, userId, new Date().getTime());
  756. if(session.type == SESSION_TYPES.P2P){
  757. for(var j in users){
  758. if(users[j]==userId)continue;
  759. //通知对方自己已经读取数据
  760. WechatClient.sendAllRead(users[j],sessionId);
  761. }
  762. }else if(session.type == SESSION_TYPES.MUC){
  763. for(var j in users){
  764. if(users[j]==userId)continue;
  765. //如果是患者拉取数据告诉在线的医生患者已经读取数据
  766. WechatClient.sendMucAllRead(users[j],userId,sessionId);
  767. }
  768. }
  769. })
  770. })
  771. .catch(function (err) {
  772. logger.error("Get message by page failed: ", err);
  773. handler(err, false);
  774. })
  775. }
  776. })
  777. }
  778. })
  779. }
  780. /**
  781. * 获取所有会话的未读消息数。
  782. */
  783. getAllSessionsUnreadMessageCount(userId) {
  784. let self = this;
  785. let count = 0;
  786. let patientCount = 0;
  787. let doctorCount = 0;
  788. SessionRepo.findAll(userId, function (err, res) {
  789. if (err) {
  790. ModelUtil.logError("getAllSessionsUnreadMessageCount is failed", err);
  791. return;
  792. }
  793. if (res.length == 0) {
  794. ModelUtil.emitOK(self.eventEmitter, {count: count});
  795. return;
  796. }
  797. for (let j in res) {
  798. if (res[j].type == SESSION_TYPES.SYSTEM) {
  799. if (j == res.length - 1) {
  800. ModelUtil.emitOK(self.eventEmitter, {count: count});
  801. }
  802. continue;
  803. }
  804. callback(res, j, res[j]);
  805. }
  806. });
  807. function callback(res, j, session) {
  808. self.getSessionUnreadMessageCount(res[j].id, userId, function (err, con) {
  809. if (err) {
  810. ModelUtil.logError("getAllSessionsUnreadMessageCount is failed", err);
  811. }
  812. count = count + con;
  813. if (session.type == SESSION_BUSINESS_TYPE.PATIENT) {
  814. patientCount = patientCount + con;
  815. } else {
  816. doctorCount = doctorCount + con;
  817. }
  818. if (j == res.length - 1) {
  819. ModelUtil.emitOK(self.eventEmitter, {count: count, patient: patientCount, doctor: doctorCount});
  820. }
  821. })
  822. }
  823. }
  824. /**
  825. * 获取会话的未读消息数。根据成员最后一次获取消息的时候与当前时间。
  826. *
  827. * @param sessionId
  828. * @param userId
  829. */
  830. getSessionUnreadMessageCount(sessionId, userId, handler) {
  831. let self = this;
  832. let messagesByTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  833. let participantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  834. async.waterfall([
  835. // 此成员最后获取消息的时间
  836. function (callback) {
  837. redis.zscoreAsync(participantsKey, userId)
  838. .then(function (lastFetchTime) {
  839. callback(null, lastFetchTime);
  840. })
  841. },
  842. // 计算最后获取消息的时间之后到现在有多少条消息
  843. function (lastFetchTime, callback) {
  844. if (!lastFetchTime) lastFetchTime = 0;
  845. let now = new Date().getTime();
  846. redis.zcountAsync(messagesByTimestampKey, lastFetchTime, now)
  847. .then(function (count) {
  848. if (handler) {
  849. handler(null, count);
  850. } else {
  851. ModelUtil.emitOK(self.eventEmitter, {count: count});
  852. }
  853. })
  854. }
  855. ], function (err, res) {
  856. if (err) {
  857. if (handler) {
  858. handler(err, 0);
  859. } else {
  860. ModelUtil.emitError(self.eventEmitter, "Get session unread message count failed.")
  861. }
  862. }
  863. });
  864. }
  865. /**
  866. * 获取会话未读消息数。根据成员最后一次获取消息的时候与当前时间。
  867. */
  868. getSessionUnreadMessages(sessionId, userId) {
  869. let self = this;
  870. let messagesByTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  871. let participantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  872. async.waterfall([
  873. // 此成员最后获取消息的时间
  874. function (callback) {
  875. redis.zscoreAsync(participantsKey, userId)
  876. .then(function (lastFetchTime) {
  877. callback(null, lastFetchTime);
  878. })
  879. },
  880. // 最后获取消息的时间之后到现在的消息ID列表
  881. function (lastFetchTime, callback) {
  882. if (!lastFetchTime) lastFetchTime = 0;
  883. let now = new Date().getTime();
  884. redis.zrangebyscoreAsync(messagesByTimestampKey, lastFetchTime, now)
  885. .then(function (messageIds) {
  886. callback(null, messageIds);
  887. })
  888. },
  889. // 获取消息
  890. function (messageIds, callback) {
  891. if (messageIds.length == 0) {
  892. ModelUtil.emitOK(self.eventEmitter, []);
  893. return;
  894. }
  895. let startMsgId = messageIds[0];
  896. let endMsgId = messageIds[messageIds.length - 1];
  897. self.getMessagesByPage(sessionId, userId, startMsgId, endMsgId, 0, messageIds.length, 0, function (err, res) {
  898. if (err) {
  899. ModelUtil.emitError(self.eventEmitter, err.message);
  900. return;
  901. }
  902. ModelUtil.emitOK(self.eventEmitter, res);
  903. });
  904. }
  905. ], function (err, res) {
  906. if (err) {
  907. ModelUtil.emitError(self.eventEmitter, "Get session unread message count failed.")
  908. }
  909. });
  910. }
  911. /**
  912. * 保存消息。
  913. *
  914. * 也可以根据议题保存消息,但最终还是保存到与会话对象。
  915. *
  916. * see also: saveMessageByTopic
  917. *
  918. * @param message
  919. * @param sessionId
  920. */
  921. saveMessageBySession(sessionId, message) {
  922. let self = this;
  923. let messages = new Messages();
  924. let participants = new Participants();
  925. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  926. let messageId = mongoose.Types.ObjectId().toString();
  927. let sessionType =0;
  928. message.id = messageId;
  929. // 检查会话中是否存在此成员
  930. participants.existsParticipant(sessionId, message.sender_id, function (err, res) {
  931. if (err) {
  932. ModelUtil.emitError(self.eventEmitter, "Check session participant failed: ", err);
  933. return;
  934. }
  935. if (res) {
  936. redis.hmgetAsync(sessionKey, ["type", "name"]).then(function (res) {
  937. sessionType = res[0];
  938. let sessionName = res[1];
  939. if (sessionType == null) {
  940. ModelUtil.emitError(self.eventEmitter, "Session " + sessionId + " is not found.");
  941. return;
  942. }
  943. // 消息保存到Redis,并更新会话最后状态、用户最后消息获取时间
  944. messages.saveMessageToRedis(sessionId, sessionType, messageId, message);
  945. Messages.updateLastContent(sessionKey, sessionType, sessionName, message);
  946. Sessions.updateParticipantLastFetchTime(sessionId, message.sender_id, message.timestamp.getTime());
  947. // 更新MYSQL中会话的最新状态,并保存消息
  948. SessionRepo.updateSessionLastStatus(message.sender_id, message.sender_name, message.timestamp, message.content, message.content_type, sessionId);
  949. messages.saveMessageToMysql(sessionId, sessionType, messageId, message, function (err, res) {
  950. if (err) {
  951. ModelUtil.emitError(self.eventEmitter, {message: "Failed to save message to mysql: " + err});
  952. } else {
  953. message.timestamp = message.timestamp.getTime();
  954. ModelUtil.emitOK(self.eventEmitter, {count: 1, messages: [message]});
  955. }
  956. });
  957. }).then(function (res) {
  958. // 推送消息
  959. ParticipantRepo.findIds(sessionId, function (err, res) {
  960. if (err) {
  961. ModelUtil.logError("Push message from session: get participant's id list failed: ", err);
  962. } else {
  963. message.session_id = sessionId;
  964. res.forEach(function (participant) {
  965. if (participant.id == message.sender_id){
  966. message.sender_img = participant.avatar;
  967. // if(participant.participant_role == PARTICIPANT_ROLES.REGULAR){
  968. // if (message.content_type == CONTENT_TYPES.PlainText ||
  969. // message.content_type == CONTENT_TYPES.Image ||
  970. // message.content_type == CONTENT_TYPES.Audio||
  971. // message.content_type == CONTENT_TYPES.Video){
  972. // participants.updateUser(sessionId,message.sender_id,PARTICIPANT_ROLES.HOST);
  973. // }
  974. // }
  975. callPush(res,message);
  976. }
  977. })
  978. }
  979. })
  980. }).catch(function (err) {
  981. ModelUtil.emitError(self.eventEmitter, {message: "Error occurred while save message to session: " + err});
  982. })
  983. } else {
  984. ModelUtil.emitDataNotFound(self.eventEmitter, {message: "当前会话找不到此发送者"});
  985. }
  986. });
  987. function callPush(participants,message){
  988. participants.forEach(function (participant) {
  989. if (participant.id !== message.sender_id &&
  990. participant.participant_role == PARTICIPANT_ROLES.HOST) {
  991. Sessions.pushNotification(participant.id, participant.name, message,sessionType);
  992. }
  993. });
  994. }
  995. }
  996. sendTopicMessages(topicId, message) {
  997. let self = this;
  998. TopicRepo.findAllByTopicId(topicId, function (err, res) {
  999. if (err || res.length == 0) {
  1000. ModelUtil.emitOK(self.eventEmitter, {status: -1, "message": "议题获取失败"});
  1001. return;
  1002. }
  1003. self.saveMessageByTopic(message, res[0].session_id, function (err, messageId) {
  1004. if (err) {
  1005. ModelUtil.emitOK(self.eventEmitter, {status: -1, "message": err});
  1006. } else {
  1007. message.id = messageId;
  1008. ModelUtil.emitOK(self.eventEmitter, {status: 200, "message": "发送成功", data: message});
  1009. }
  1010. });
  1011. });
  1012. }
  1013. /**
  1014. * 保存消息
  1015. *
  1016. * @param message
  1017. * @param sessionId
  1018. * @param handler
  1019. */
  1020. saveMessageByTopic(message, sessionId, handler) {
  1021. let messages = new Messages();
  1022. let participants = new Participants();
  1023. let session_key = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  1024. let messageId = mongoose.Types.ObjectId().toString();
  1025. let self = this;
  1026. let sessionType = 0;
  1027. let sessionName = "";
  1028. message.id = messageId;
  1029. // 发送成员必须处于会话中
  1030. participants.existsParticipant(sessionId, message.sender_id, function (err, res) {
  1031. if (res) {
  1032. redis.hmgetAsync(session_key, ["type", "name"]).then(function (res) {
  1033. sessionType = res[0];
  1034. sessionName = res[1];
  1035. if (!sessionType || !sessionName) {
  1036. logger.error("Unknown session key " + session_key);
  1037. if (handler) {handler(new Error("Unknown session key " + session_key));return;} ;
  1038. }
  1039. }).then(function (res) {
  1040. // 消息数据双写,并更新用户最后消息获取时间,会话新状态等
  1041. messages.saveMessageToRedis(sessionId, sessionType, messageId, message);
  1042. messages.saveMessageToMysql(sessionId, sessionType, messageId, message);
  1043. // 更新会话最新状态及成员最后一次消息获取时间
  1044. Sessions.updateParticipantLastFetchTime(sessionId, message.sender_id, message.timestamp.getTime());
  1045. Messages.updateLastContent(session_key, sessionType, sessionName, message);
  1046. SessionRepo.updateSessionLastStatus(message.sender_id, message.sender_name, message.timestamp, message.content, message.content_type, sessionId);
  1047. if (handler) {handler(null, messageId);return;}
  1048. }).then(function (res) {
  1049. // 推送消息
  1050. ParticipantRepo.findIds(sessionId, function (err, res) {
  1051. if (err) {
  1052. logger.error(err);
  1053. } else {
  1054. message.session_id = sessionId;
  1055. res.forEach(function (participant) {
  1056. if (participant.id == message.sender_id){
  1057. message.sender_img = participant.avatar;
  1058. callPush(res,message);
  1059. }
  1060. })
  1061. }
  1062. })
  1063. }).catch(function (err) {
  1064. if (handler) { handler(err, messageId);return;}
  1065. })
  1066. } else {
  1067. if (handler){ handler("用户不在此会话当中!", messageId);return;}
  1068. }
  1069. });
  1070. function callPush(participants,message){
  1071. participants.forEach(function (participant) {
  1072. if (participant.id !== message.sender_id &&
  1073. participant.participant_role == PARTICIPANT_ROLES.HOST) {
  1074. Sessions.pushNotification(participant.id, participant.name, message,sessionType);
  1075. }
  1076. });
  1077. }
  1078. }
  1079. /**
  1080. * 置顶操作
  1081. */
  1082. stickSession(sessionId, user) {
  1083. let user_session_key = RedisModel.makeRedisKey(REDIS_KEYS.UserSessions, user);
  1084. let self = this;
  1085. //取出最大的session
  1086. redis.zrevrangeAsync(user_session_key, 0, 0).then(function (res) {
  1087. //获取该session的时间搓
  1088. redis.zscoreAsync(user_session_key, res).then(function (scoreres) {
  1089. let nowtime = new Date().getTime();
  1090. //当前时间搓比redis的时间搓更早证明没有置顶过
  1091. if (scoreres <= nowtime) {
  1092. //初始化置顶
  1093. redis.zaddAsync(user_session_key, STICKY_SESSION_BASE_SCORE, sessionId).then(function (res) {
  1094. logger.info("stickSession:" + sessionId + ",res:" + res);
  1095. ModelUtil.emitOK(self.eventEmitter, {});
  1096. }).then(function () {
  1097. SessionRepo.saveStickySession(sessionId, user, STICKY_SESSION_BASE_SCORE);
  1098. })
  1099. } else {
  1100. //已有置顶的数据,取出来加1保存回去
  1101. scoreres = Number(scoreres) + 1;
  1102. redis.zaddAsync(user_session_key, scoreres, sessionId).then(function () {
  1103. logger.info("stickSession:" + sessionId + ",res:" + res);
  1104. ModelUtil.emitOK(self.eventEmitter, {});
  1105. }).then(function () {
  1106. SessionRepo.saveStickySession(sessionId, user, scoreres);
  1107. })
  1108. }
  1109. })
  1110. })
  1111. }
  1112. /**
  1113. * 取消会话置顶
  1114. */
  1115. cancelStickSession(sessionId, user) {
  1116. let user_session_key = RedisModel.makeRedisKey(REDIS_KEYS.UserSessions, user);
  1117. let participants_key = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  1118. let self = this;
  1119. redis.zscoreAsync(participants_key, user).then(function (res) {
  1120. if (!res) {
  1121. res = new Date().getTime();
  1122. }
  1123. redis.zaddAsync(user_session_key, res, sessionId).then(function (res) {
  1124. logger.info("cancelStickSession:" + sessionId);
  1125. ModelUtil.emitOK(self.eventEmitter, {});
  1126. }).then(function () {
  1127. SessionRepo.unstickSession(sessionId, user);
  1128. });
  1129. })
  1130. }
  1131. /**
  1132. * 更新会话参与者的最后消息获取时间。
  1133. *
  1134. * @param sessionId
  1135. * @param userId
  1136. */
  1137. static updateParticipantLastFetchTime(sessionId, userId, score) {
  1138. score = score + 1;
  1139. let participantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  1140. redis.zaddAsync(participantsKey, score, userId)
  1141. .then(function (res) {
  1142. ParticipantRepo.updateLastFetchTime(new Date(score), sessionId, userId, function (err, res) {
  1143. if (err) {
  1144. logger.error("Update participant last fetch time failed: ", err);
  1145. }
  1146. });
  1147. })
  1148. .catch(function (err) {
  1149. logger.error("Update participant last fetch time failed: ", err);
  1150. });
  1151. }
  1152. /**
  1153. * 向用户推送通知,微信端用户直接推送消息,APP端通过个推发送通知消息。
  1154. *
  1155. * @param targetUserId
  1156. * @param message
  1157. */
  1158. static pushNotification(targetUserId, targetUserName, message,sessionType) {
  1159. Users.isPatientId(targetUserId, function (err, isPatient) {
  1160. if (isPatient) {
  1161. WechatClient.sendMessage(targetUserId, targetUserName, message);
  1162. }
  1163. else {
  1164. if(sessionType==SESSION_TYPES.P2P){
  1165. WechatClient.sendReadDoctorByDoctorId(targetUserId, message);
  1166. }
  1167. AppClient.sendNotification(targetUserId, message);
  1168. }
  1169. });
  1170. }
  1171. /**
  1172. * 针对MUC模式更新会话的当前状态
  1173. * @param sessionId
  1174. */
  1175. updateSessionStatus(sessionId,status){
  1176. let self = this;
  1177. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session,sessionId);
  1178. redis.hsetAsync(sessionKey,"status",status).then(function(res){
  1179. SessionRepo.updateSessionStatus(sessionId,status,function(err,sqlResult){
  1180. if(err){
  1181. logger.error("set session status to mysql is error !");
  1182. }else{
  1183. logger.info("set session status is success");
  1184. }
  1185. });
  1186. });
  1187. }
  1188. }
  1189. // Expose class
  1190. module.exports = Sessions;