sessions.js 82 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726
  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 MessageRepo = require('../../repository/mysql/message.repo');
  14. let ParticipantRepo = require('../../repository/mysql/participant.repo');
  15. let ImDb = require('../../repository/mysql/db/im.db');
  16. let WlyySDK = require("../../util/wlyy.sdk");
  17. let ObjectUtil = require("../../util/object.util.js");
  18. let WechatClient = require("../client/wechat.client.js");
  19. let AppClient = require("../client/app.client.js");
  20. let configFile = require('../../include/commons').CONFIG_FILE;
  21. let config = require('../../resources/config/' + configFile);
  22. let redis = RedisClient.redisClient().connection;
  23. let logger = require('../../util/log.js');
  24. let mongoose = require('mongoose');
  25. let async = require("async");
  26. let log = require("../../util/log.js");
  27. let pubSub = require("../redis/pubSub.js");
  28. const REDIS_KEYS = require('../../include/commons').REDIS_KEYS;
  29. const SESSION_TYPES = require('../../include/commons').SESSION_TYPES;
  30. const STICKY_SESSION_BASE_SCORE = require('../../include/commons').STICKY_SESSION_BASE_SCORE;
  31. const PARTICIPANT_ROLES = require('../../include/commons').PARTICIPANT_ROLES;
  32. const CONTENT_TYPES = require('../../include/commons').CONTENT_TYPES;
  33. const SESSION_BUSINESS_TYPE = require('../../include/commons').SESSION_BUSINESS_TYPE;
  34. const SESSION_STATUS = require('../../include/commons').SESSION_STATUS;
  35. class Sessions extends RedisModel {
  36. constructor() {
  37. super();
  38. }
  39. /**
  40. * 创建会话。会话的ID来源:
  41. * MUC:患者的ID
  42. * P2P:对成员的ID排序后,取hash值
  43. * GROUP:团队的ID
  44. *
  45. * @param sessionId
  46. * @param name 会话名称
  47. * @param type 会话类型
  48. * @param participantArray 会话成员
  49. * @param handler 回调,仅MUC模式使用
  50. */
  51. createSession(sessionId, name, type, participantArray, handler) {
  52. let self = this;
  53. let messageId = mongoose.Types.ObjectId().toString();
  54. //创建session到mysql
  55. self.createSessionToMysql(sessionId, name, type, participantArray, messageId, function (err, res) {
  56. if (err) {
  57. if (handler) {
  58. handler(err, null);
  59. return;
  60. }
  61. ModelUtil.emitError(self.eventEmitter, {message: err, status: -1}, null);
  62. } else {
  63. //创建session到redis
  64. self.createSessionToRedis(sessionId, name, type, participantArray, messageId, function (err, res) {
  65. if (err) {
  66. if (handler) {
  67. handler(err, null);
  68. return;
  69. }
  70. ModelUtil.emitError(self.eventEmitter, {message: err, status: -1}, null);
  71. } else {
  72. if (handler) {
  73. handler(null, res);
  74. return;
  75. }
  76. ModelUtil.emitOK(self.eventEmitter, {status: 200, data: res});
  77. }
  78. });
  79. }
  80. });
  81. }
  82. /**
  83. * 创建会话。REDIS
  84. * @param sessionId
  85. * @param name
  86. * @param type
  87. * @param participantArray
  88. * @param messageId
  89. * @param handler
  90. * @returns {boolean}
  91. */
  92. createSessionToRedis(sessionId, name, type, participantArray, messageId, handler) {
  93. let self = this;
  94. let messages = new Messages();
  95. let participantIdArray = [];
  96. for (let i in participantArray) {
  97. participantIdArray.push(participantArray[i].split(":")[0]);
  98. }
  99. if (type == SESSION_TYPES.P2P || type == SESSION_TYPES.SYSTEM) {
  100. if (sessionId) {
  101. callBusinessType(sessionId);
  102. return;
  103. }
  104. else if (participantIdArray.length != 2) {
  105. handler("P2P session only allow 2 participants.", null);
  106. return false;
  107. }else{
  108. ParticipantRepo.findSessionIdByParticipantIds(participantIdArray[0], participantIdArray[1], function (err, res) {
  109. sessionId = res;
  110. callBusinessType(sessionId);
  111. return;
  112. });
  113. }
  114. } else {
  115. if (!sessionId) {
  116. handler("MUC OR GROUP session sessionId is not allow null .", null);
  117. return;
  118. }
  119. callBusinessType(sessionId);
  120. }
  121. function callBusinessType(sessionId) {
  122. if(type == SESSION_TYPES.MUC||type == SESSION_TYPES.PRESCRIPTION){
  123. callCreate(sessionId, SESSION_BUSINESS_TYPE.PATIENT);
  124. }else {
  125. ParticipantRepo.getBusinessType(participantIdArray, function (err, businessType) {
  126. callCreate(sessionId, businessType);
  127. });
  128. }
  129. }
  130. function callCreate(sessionId, businessType) {
  131. let createDate = new Date();
  132. Participants.saveParticipantsToRedis(sessionId, participantArray, createDate, function (res) {
  133. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  134. if (type == SESSION_TYPES.MUC||type == SESSION_TYPES.PRESCRIPTION) {
  135. businessType = 2;
  136. }
  137. let session = {
  138. id: sessionId,
  139. name: name,
  140. type: type,
  141. create_date: createDate.getTime(),
  142. business_type: businessType
  143. };
  144. //如果会话已经存在的就不需要发送会话成功的消息不更新最后一条消息
  145. redis.hexistsAsync(sessionKey, sessionId).then(function(res){
  146. if(res==0){
  147. redis.hmsetAsync(sessionKey, session).then(function () {
  148. handler(null, session);
  149. })
  150. }
  151. })
  152. });
  153. }
  154. }
  155. /**
  156. * 创建会话。mysql
  157. * @param sessionId
  158. * @param name
  159. * @param type
  160. * @param participantArray
  161. * @param messageId
  162. * @param handler
  163. */
  164. createSessionToMysql(sessionId, name, type, participantArray, messageId, handler) {
  165. let self = this;
  166. //如果sessionId不存在则执行创建sessionId过程
  167. let participantIdArray = [];
  168. for (let i in participantArray) {
  169. participantIdArray.push(participantArray[i].split(":")[0]);
  170. }
  171. //流程1-判断是否存在sessionId不存在则创建对应的sessionId;
  172. if (!sessionId) {
  173. if (type == SESSION_TYPES.P2P || type == SESSION_TYPES.SYSTEM) {
  174. ParticipantRepo.findSessionIdByParticipantIds(participantIdArray[0], participantIdArray[1], function (err, res) {
  175. sessionId = res;
  176. callBusinessType();
  177. });
  178. } else {
  179. return handler("MUC模式和团队模式,不允许sessionId为空!", null);
  180. }
  181. } else {
  182. callBusinessType();
  183. }
  184. //流程2-判断session的业务类型;
  185. function callBusinessType() {
  186. if(type==SESSION_TYPES.MUC||type==SESSION_TYPES.PRESCRIPTION){
  187. callCreateSession(SESSION_BUSINESS_TYPE.PATIENT);
  188. }else{
  189. ParticipantRepo.getBusinessType(participantIdArray, function (err, businessType) {
  190. if (err) {
  191. handler(err, null);
  192. return;
  193. }
  194. callCreateSession(businessType);
  195. });
  196. }
  197. }
  198. //流程3-发起session创建 返回session实例
  199. function callCreateSession(businessType) {
  200. //查找该sessionId是否存在存在则直接返回实例
  201. SessionRepo.findOne(sessionId, function (err, res) {
  202. if (res.length > 0) {//已经存在
  203. //更新成员
  204. Participants.saveParticipantsToMysql(sessionId, participantArray, function (err, update) {
  205. handler(null, res[0]);
  206. return;
  207. })
  208. let createDate = new Date();
  209. self.saveSessionToMysql(sessionId, name, type, createDate, businessType, function (err, res) {
  210. logger.info("update session status is true");
  211. })
  212. } else {
  213. let createDate = new Date();
  214. let session = {
  215. id: sessionId,
  216. name: name,
  217. type: type,
  218. create_date: createDate.getTime(),
  219. business_type: businessType
  220. };
  221. //将session写入数据库
  222. self.saveSessionToMysql(sessionId, name, type, createDate, businessType, function (err, res) {
  223. if (err) {
  224. handler(err, null);
  225. return;
  226. }
  227. callCreateParticipants(session);
  228. })
  229. }
  230. });
  231. }
  232. //流程4-发起session成员创建
  233. function callCreateParticipants(session) {
  234. Participants.saveParticipantsToMysql(sessionId, participantArray, function (err, res) {
  235. if (err) {
  236. handler(err, null);
  237. return;
  238. } else {
  239. handler(null, session);
  240. return;
  241. }
  242. })
  243. }
  244. }
  245. /**
  246. * 最近会话列表,7天内。
  247. *
  248. * @param userId
  249. * @param dateSpan
  250. */
  251. getRecentSessions(userId, dateSpan) {
  252. let self = this;
  253. SessionRepo.findAllByTimestampAndType(userId, dateSpan, function (err, res) {
  254. if (err) {
  255. ModelUtil.emitError(self.eventEmitter, "Get recent sessions failed", err);
  256. return;
  257. }
  258. let sessions = [];
  259. res.forEach(function (session) {
  260. //最近列表用于转发,过滤不可用的咨询
  261. if(session.last_content_type != CONTENT_TYPES.TopicEnd){
  262. sessions.push({
  263. id: session.id,
  264. name: session.name,
  265. type: session.type,
  266. business_type: session.business_type,
  267. create_date: session.create_date
  268. })
  269. }
  270. });
  271. ModelUtil.emitOK(self.eventEmitter, sessions);
  272. });
  273. }
  274. /**
  275. * 保存session到MySQL
  276. * @param sessionId
  277. * @param name
  278. * @param type
  279. * @param createDate
  280. * @param businessType
  281. * @param handler
  282. */
  283. saveSessionToMysql(sessionId, name, type, createDate, businessType, handler) {
  284. SessionRepo.saveSession(sessionId, name, type, createDate, businessType, handler);
  285. }
  286. /**
  287. * 获取某个用户的全部session列表
  288. * @param userId
  289. * @param handler
  290. */
  291. getUserSessionsFromMysql(userId, handler) {
  292. SessionRepo.findAll(userId, handler);
  293. }
  294. /**
  295. * 获取session单个对象
  296. * @param sessionId
  297. * @param handler
  298. */
  299. getSessions(sessionId, handler) {
  300. SessionRepo.findOne(sessionId, handler);
  301. }
  302. /**
  303. * 判断会话是否存在
  304. * @param sessionId
  305. * @param handler
  306. */
  307. isExist(sessionId) {
  308. let self = this;
  309. SessionRepo.findOne(sessionId, function (err, res) {
  310. if(err){
  311. log.error(err);
  312. ModelUtil.emitError(self.eventEmitter, {message: err, status: -1}, null);
  313. } else if(res&&res.length>0){
  314. ModelUtil.emitOK(self.eventEmitter, {sessionId: res[0].id, status: 200});
  315. }else {
  316. ModelUtil.emitOK(self.eventEmitter, {sessionId: '', status: 200});
  317. }
  318. });
  319. }
  320. getSession(sessionId,userId,handler){
  321. let self = this;
  322. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  323. redis.hgetallAsync(sessionKey).then(function(session){
  324. if(session.type==SESSION_TYPES.P2P){
  325. ParticipantRepo.findNameById(userId, function (err, res) {
  326. session.name = res[0].name;
  327. if(handler){
  328. handler(null,session);
  329. return;
  330. }
  331. ModelUtil.emitOK(self.eventEmitter, session);
  332. })
  333. }else{
  334. if(handler){
  335. handler(null,session);
  336. return;
  337. }
  338. ModelUtil.emitOK(self.eventEmitter, session);
  339. }
  340. }).catch(function (err) {
  341. logger.error("Get session failed: ", err);
  342. if(handler){
  343. handler(null,session);
  344. return;
  345. }
  346. ModelUtil.emitError(self.eventEmitter, {message: err, status: -1}, null);
  347. })
  348. }
  349. /**
  350. * 根据用户ID获取用户的session列表
  351. * @param userId
  352. * @param page
  353. * @param size
  354. * @param businessType
  355. */
  356. getUserSessions(userId, page, size, businessType) {
  357. let userSessionKey = RedisModel.makeRedisKey(REDIS_KEYS.UserSessions, userId);
  358. let self = this;
  359. if (page > 0) {
  360. if (page == 1) {
  361. page = 0;
  362. }
  363. page = page + page * size;
  364. }
  365. async.waterfall([
  366. // 获取会话ID列表
  367. // function (callback) {
  368. // redis.zrevrangeAsync(userSessionKey, page, size)
  369. // .then(function (sessionIds) {
  370. // if (sessionIds.length == 0) {
  371. // ModelUtil.emitOK(self.eventEmitter, []);
  372. // return;
  373. // }
  374. // callback(null, sessionIds);
  375. // })
  376. // },
  377. function (callback) {
  378. SessionRepo.findAllByType(userId,businessType,page,size,function(err,res){
  379. if (res.length == 0) {
  380. ModelUtil.emitOK(self.eventEmitter, []);
  381. return;
  382. }
  383. var sessionIds=[];
  384. for(var j in res){
  385. sessionIds.push(res[j].id);
  386. }
  387. callback(null,sessionIds);
  388. })
  389. },
  390. // 遍历会话
  391. function (sessionIds) {
  392. let sessionList = [];
  393. let functionList = [];
  394. for (let j = 0; j < sessionIds.length; j++) {
  395. let fun = function (index, callback) {
  396. if (!callback) {
  397. callback = index, index = 0
  398. }
  399. let sessionId = sessionIds[index];
  400. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  401. let participantsRoleKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipantsRole, sessionId);
  402. let sessionParticipantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  403. redis.multi()
  404. .hgetall(sessionKey) // 会话实体
  405. .hget(participantsRoleKey, userId) // 用户在此会话中的角色
  406. .zscore(sessionParticipantsKey, userId) // 用户在此会话中最后一次获取未读消息的时间
  407. .zrange(sessionParticipantsKey, 0, -1)
  408. .zrange(sessionParticipantsKey, 0,-1,'withscores') // 所有用户在此会话中最后一次获取未读消息的时间
  409. .hgetall(participantsRoleKey) // 所有用户在此会话中角色
  410. .execAsync()
  411. .then(function (res) {
  412. let session = res[0];
  413. let role = res[1];
  414. let lastFetchTime = res[2];
  415. let users = res[3];
  416. let participantsTimeArray = res[4];
  417. let userRoles = res[5];
  418. let participantsTime = [];
  419. let isInvite = true;
  420. //处理session未加入redis的bug
  421. if(session==null){
  422. let lastLoginTime = new Date();
  423. SessionRepo.findOne(sessionId, function (err, res) {
  424. if(res){
  425. session = res;
  426. let redisSession = [
  427. "id", session.id,
  428. "name", session.name,
  429. "type", session.type,
  430. "business_type", session.business_type,
  431. "last_sender_id", session.last_sender_id||"",
  432. "last_sender_name", session.last_sender_name||"",
  433. "last_content_type", session.last_content_type||"",
  434. "last_content", session.last_content||"",
  435. "last_message_time", session.last_message_time||"",
  436. "create_date", ObjectUtil.timestampToLong(session.create_date),
  437. "status",session.status==null?0:session.status
  438. ];
  439. // cache sessions
  440. redis.multi()
  441. .zadd(REDIS_KEYS.Sessions, lastLoginTime.getTime(), sessionId) // 会话的最后活动时间设置为此用户的登录时间
  442. .zadd(RedisModel.makeRedisKey(REDIS_KEYS.UserSessions, userId), lastLoginTime.getTime(), sessionId) // 会话的最后活动时间设置为此用户的登录时间
  443. .hmset(RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId), redisSession)
  444. .execAsync()
  445. .then(function (res) {
  446. // cache participants
  447. let sessionParticipantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  448. let sessionParticipantsRoleKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipantsRole, sessionId);
  449. ParticipantRepo.findAll(sessionId, function (err, participants) {
  450. if (err) {
  451. ModelUtil.emitError(self.eventEmitter, err.message);
  452. return;
  453. }
  454. let multi = redis.multi();
  455. participants.forEach(function (participant) {
  456. let participantId = participant.id;
  457. let participantRole = participant.role;
  458. let score = ObjectUtil.timestampToLong(participant.last_fetch_time||(new Date()));
  459. multi = multi.zadd(sessionParticipantsKey, score, participantId)
  460. .hset(sessionParticipantsRoleKey, participantId, participantRole);
  461. });
  462. multi.execAsync()
  463. .then(function (res) {
  464. })
  465. .catch(function (ex) {
  466. log.error("Login failed while caching participants: ", ex);
  467. });
  468. });
  469. // cache messages
  470. let messagesKey = RedisModel.makeRedisKey(REDIS_KEYS.Messages, sessionId);
  471. let messagesByTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  472. MessageRepo.findBySessionId(sessionId, 0, config.sessionConfig.maxMessageCount, null, function (err, messages) {
  473. if (err) {
  474. ModelUtil.emitError(self.eventEmitter, err.message);
  475. return;
  476. }
  477. let multi = redis.multi();
  478. messages.forEach(function (message) {
  479. let msgJson = {
  480. id: message.id,
  481. sender_id: message.sender_id,
  482. sender_name: message.sender_name,
  483. timestamp: ObjectUtil.timestampToLong(message.timestamp),
  484. content_type: message.content_type,
  485. content: message.content
  486. };
  487. multi = multi.hset(messagesKey, message.id, JSON.stringify(msgJson))
  488. .zadd(messagesByTimestampKey, ObjectUtil.timestampToLong(message.timestamp), message.id);
  489. });
  490. multi.execAsync()
  491. .then(function (res) {
  492. })
  493. .catch(function (ex) {
  494. log.error("Login failed while caching messages: ", ex);
  495. });
  496. });
  497. // cache topics for MUC
  498. let topicsKey = RedisModel.makeRedisKey(REDIS_KEYS.Topics, sessionId);
  499. TopicRepo.findAllBySessionId(sessionId, function (err, topics) {
  500. if (err) {
  501. ModelUtil.emitError(self.eventEmitter, err.message);
  502. return;
  503. }
  504. topics.forEach(function (topic) {
  505. let topicKey = RedisModel.makeRedisKey(REDIS_KEYS.Topic, topic.id);
  506. let topicId = topic.id;
  507. let name = topic.name == null ? "" : topic.name;
  508. let createTime = ObjectUtil.timestampToLong(topic.create_time);
  509. let endBy = topic.end_by == null ? "" : topic.end_by;
  510. let endTime = topic.end_time == null ? 0 : ObjectUtil.timestampToLong(topic.end_time);
  511. let startMessageId = topic.start_message_id == null ? "" : topic.start_message_id;
  512. let endMessageId = topic.end_message_id == null ? "" : topic.end_message_id;
  513. let description = topic.description == null ? "" : topic.description;
  514. let status = topic.status == null ? 0 : topic.status;
  515. redisConn.multi()
  516. .zadd(topicsKey, createTime, topicId)
  517. .hmset(topicKey,
  518. 'name', name,
  519. 'session_id', sessionId,
  520. 'create_time', createTime,
  521. 'end_by', endBy,
  522. 'end_time', endTime,
  523. 'start_message_id', startMessageId,
  524. 'end_message_id', endMessageId,
  525. 'description', description,
  526. 'status', status)
  527. .execAsync()
  528. .catch(function (ex) {
  529. log.error("Login failed while caching topics: ", ex);
  530. });
  531. });
  532. });
  533. })
  534. .catch(function (ex) {
  535. log.error("Login failed while caching sessions: ", ex);
  536. });
  537. }
  538. });
  539. }
  540. for(var j in userRoles){
  541. if(userRoles[j]==1){
  542. isInvite = false;
  543. break;
  544. }
  545. }
  546. for(var j = 0 ;j<participantsTimeArray.length;j++){
  547. if(j%2!=0)continue;
  548. let participantsTimeJson = {};
  549. participantsTimeJson[participantsTimeArray[j]] = participantsTimeArray[j+1];
  550. participantsTime.push(participantsTimeJson);
  551. }
  552. let sessionName = "";
  553. let otherUserId = "";
  554. if (session.type == SESSION_TYPES.P2P) {
  555. for (let j in users) {
  556. if (users[j] != userId) {
  557. otherUserId = users[j];
  558. }
  559. }
  560. }
  561. if (!role) role = 0;
  562. if (!lastFetchTime) lastFetchTime = new Date().getTime();
  563. // 计算未读消息数
  564. let messagesByTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  565. redis.zcountAsync(messagesByTimestampKey, parseInt(lastFetchTime)+1, new Date().getTime())
  566. .then(function (count) {
  567. if (!otherUserId) otherUserId = userId;
  568. ParticipantRepo.findNameById(otherUserId, function (err, res) {
  569. if ((res && res.length == 0) || session.type != SESSION_TYPES.P2P) {
  570. sessionName = session.name;
  571. } else {
  572. sessionName = res[0].name;
  573. }
  574. var bir = new Date().getTime();
  575. if (res.length != 0 && res[0].birthdate) {
  576. bir = res[0].birthdate.getTime();
  577. }
  578. var sex = 1;
  579. if (res.length != 0 && res[0].sex) {
  580. sex = res[0].sex;
  581. }
  582. //end
  583. sessionList.push({
  584. id: sessionId,
  585. name: sessionName,
  586. create_date: session.create_date,
  587. last_content_type: session.last_content_type||"",
  588. last_content: session.last_content||"",
  589. sender_id: session.last_sender_id||"",
  590. type: session.type,
  591. sender_name: session.last_sender_name||"",
  592. unread_count: count,
  593. business_type: session.business_type,
  594. my_role: role,
  595. sender_sex: sex,
  596. sender_birthday: bir,
  597. participantsTimeArray:participantsTime,
  598. status:session.status,
  599. is_invite:isInvite
  600. });
  601. index = (parseInt(index) + 1);
  602. if (index == sessionIds.length) {
  603. ModelUtil.emitOK(self.eventEmitter, sessionList);
  604. } else {
  605. callback(null, index);
  606. }
  607. })
  608. })
  609. })
  610. .catch(function (err) {
  611. logger.error("Get sessions failed: ", err);
  612. });
  613. };
  614. functionList.push(fun);
  615. }
  616. async.waterfall(functionList);
  617. }
  618. ]);
  619. }
  620. /**
  621. * 根据用户ID获取用户已经结束咨询的session列表
  622. * @param userId
  623. * @param page
  624. * @param size
  625. * @param businessType
  626. */
  627. getUserStatusSessions(userId,status,businessType,page, size) {
  628. let userSessionKey = RedisModel.makeRedisKey(REDIS_KEYS.UserSessions, userId);
  629. let self = this;
  630. async.waterfall([
  631. // 获取会话ID列表
  632. function (callback) {
  633. SessionRepo.findAllByTypeAndStatus(userId,businessType,status,page,size,function(err,res){
  634. if (res.length == 0) {
  635. ModelUtil.emitOK(self.eventEmitter, []);
  636. return;
  637. }
  638. var sessionIds=[];
  639. for(var j in res){
  640. sessionIds.push(res[j].id);
  641. }
  642. callback(null,sessionIds);
  643. })
  644. },
  645. // 遍历会话
  646. function (sessionIds) {
  647. let sessionList = [];
  648. let functionList = [];
  649. for (let j = 0; j < sessionIds.length; j++) {
  650. let fun = function (index, callback) {
  651. if (!callback) {
  652. callback = index, index = 0
  653. }
  654. let sessionId = sessionIds[index];
  655. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  656. let participantsRoleKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipantsRole, sessionId);
  657. let sessionParticipantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  658. redis.multi()
  659. .hgetall(sessionKey) // 会话实体
  660. .hget(participantsRoleKey, userId) // 用户在此会话中的角色
  661. .zscore(sessionParticipantsKey, userId) // 用户在此会话中最后一次获取未读消息的时间
  662. .zrange(sessionParticipantsKey, 0, -1)
  663. .zrange(sessionParticipantsKey, 0,-1,'withscores') // 所有用户在此会话中最后一次获取未读消息的时间
  664. .hgetall(participantsRoleKey) // 所有用户在此会话中角色
  665. .execAsync()
  666. .then(function (res) {
  667. let session = res[0];
  668. let role = res[1];
  669. let lastFetchTime = res[2];
  670. let users = res[3];
  671. let participantsTimeArray = res[4];
  672. let userRoles = res[5];
  673. let participantsTime = [];
  674. let isInvite = true;
  675. for(var j in userRoles){
  676. if(userRoles[j]==1){
  677. isInvite = false;
  678. break;
  679. }
  680. }
  681. for(var j = 0 ;j<participantsTimeArray.length;j++){
  682. if(j%2!=0)continue;
  683. let participantsTimeJson = {};
  684. participantsTimeJson[participantsTimeArray[j]] = participantsTimeArray[j+1];
  685. participantsTime.push(participantsTimeJson);
  686. }
  687. let sessionName = "";
  688. let otherUserId = "";
  689. if (session.type == SESSION_TYPES.P2P) {
  690. for (let j in users) {
  691. if (users[j] != userId) {
  692. otherUserId = users[j];
  693. }
  694. }
  695. }
  696. if (!role) role = 0;
  697. if (!lastFetchTime) lastFetchTime = new Date().getTime();
  698. // 计算未读消息数
  699. let messagesByTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  700. redis.zcountAsync(messagesByTimestampKey, parseInt(lastFetchTime)+1, new Date().getTime())
  701. .then(function (count) {
  702. if (!otherUserId) otherUserId = userId;
  703. ParticipantRepo.findNameById(otherUserId, function (err, res) {
  704. if ((res && res.length == 0) || session.type != SESSION_TYPES.P2P) {
  705. sessionName = session.name;
  706. } else {
  707. sessionName = res[0].name;
  708. }
  709. var bir = new Date().getTime();
  710. if (res.length != 0 && res[0].birthdate) {
  711. bir = res[0].birthdate.getTime();
  712. }
  713. var sex = 1;
  714. if (res.length != 0 && res[0].sex) {
  715. sex = res[0].sex;
  716. }
  717. sessionList.push({
  718. id: sessionId,
  719. name: sessionName,
  720. create_date: session.create_date,
  721. last_content_type: session.last_content_type,
  722. last_content: session.last_content,
  723. sender_id: session.last_sender_id,
  724. type: session.type,
  725. sender_name: session.last_sender_name,
  726. unread_count: count,
  727. business_type: session.business_type,
  728. my_role: role,
  729. sender_sex: sex,
  730. sender_birthday: bir,
  731. participantsTimeArray:participantsTime,
  732. status:session.status,
  733. is_invite:isInvite
  734. });
  735. index = (parseInt(index) + 1);
  736. if (index == sessionIds.length) {
  737. ModelUtil.emitOK(self.eventEmitter, sessionList);
  738. } else {
  739. callback(null, index);
  740. }
  741. })
  742. })
  743. })
  744. .catch(function (err) {
  745. logger.error("Get sessions:"+sessionId+" failed: ", err);
  746. });
  747. };
  748. functionList.push(fun);
  749. }
  750. async.waterfall(functionList);
  751. }
  752. ]);
  753. }
  754. /**
  755. * 获取会话消息。全部,不管已读/未读状态。
  756. *
  757. * @param sessionId 会话ID
  758. * @param userId 拉取消息的人
  759. * @param page 第几页
  760. * @param pagesize 分页数量
  761. * @param start_msg_id 消息会话最新的一条消息的ID
  762. * @param end_msg_id 消息会话刚开始的消息ID
  763. * @remark
  764. * start_msg_id end_msg_id 为空取会话倒序的根据分页的消息数据
  765. * start_msg_id 为空 end_msg_id 不为空根据end_msg_id取旧的消息(offset=1可以排除本身)返回指定分页的数据
  766. * end_msg_id 为空 start_msg_id 不为空 根据 start_msg_id 取出新消息(offset=1可以排除本身)返回指定分页的数据
  767. * end_msg_id start_msg_id 都不为空返回指定区间的消息
  768. */
  769. getMessages(sessionId, user, start_msg_id, end_msg_id, page, pagesize, isoffset, handler) {
  770. let self = this;
  771. let message_timestamp_key = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  772. if (!start_msg_id && !end_msg_id) {
  773. redis.zrevrangeAsync(message_timestamp_key, 0, 0).then(function (res) {
  774. if (res.length == 0) {
  775. //修复应redis没有缓冲聊天记录导致会话列表加载不出来
  776. // cache messages
  777. let messagesKey = RedisModel.makeRedisKey(REDIS_KEYS.Messages, sessionId);
  778. MessageRepo.findBySessionId(sessionId, 0, config.sessionConfig.maxMessageCount, null, function (err, messages) {
  779. if (err) {
  780. ModelUtil.emitError(self.eventEmitter, err.message);
  781. return;
  782. }
  783. let multi = redis.multi();
  784. messages.forEach(function (message) {
  785. let msgJson = {
  786. id: message.id,
  787. sender_id: message.sender_id,
  788. sender_name: message.sender_name,
  789. timestamp: ObjectUtil.timestampToLong(message.timestamp),
  790. content_type: message.content_type,
  791. content: message.content
  792. };
  793. multi = multi.hset(messagesKey, message.id, JSON.stringify(msgJson))
  794. .zadd(message_timestamp_key, ObjectUtil.timestampToLong(message.timestamp), message.id);
  795. });
  796. multi.execAsync()
  797. .then(function (res) {
  798. })
  799. .catch(function (ex) {
  800. log.error("Login failed while caching messages: ", ex);
  801. ModelUtil.emitOK(self.eventEmitter, res);
  802. return;
  803. });
  804. });
  805. // if (handler) {
  806. // handler(null, res);
  807. // return;
  808. // }
  809. // ModelUtil.emitOK(self.eventEmitter, res);
  810. // return;
  811. }
  812. start_msg_id = res[0];
  813. redis.zrangeAsync(message_timestamp_key, 0, 0).then(function (res) {
  814. if (res.length == 0) {
  815. if (handler) {
  816. handler(null, res);
  817. return;
  818. }
  819. ModelUtil.emitOK(self.eventEmitter, res);
  820. return;
  821. }
  822. end_msg_id = res[0];
  823. self.getMessagesByPage(sessionId, user, end_msg_id, start_msg_id, page, pagesize, isoffset, function (err, res) {
  824. if (err) {
  825. if (handler) {
  826. handler(err, null);
  827. return;
  828. }
  829. logger.error("getMessagesByPage error" + err);
  830. ModelUtil.emitError(self.eventEmitter, err, err);
  831. } else {
  832. if (handler) {
  833. handler(null, res);
  834. return;
  835. }
  836. ModelUtil.emitOK(self.eventEmitter, res);
  837. }
  838. })
  839. })
  840. })
  841. } else if (!start_msg_id) {
  842. redis.zrevrangeAsync(message_timestamp_key, 0, 0).then(function (res) {
  843. if (res.length == 0) {
  844. if (handler) {
  845. handler(null, res);
  846. return;
  847. }
  848. ModelUtil.emitOK(self.eventEmitter, res);
  849. return;
  850. }
  851. start_msg_id = res[0];
  852. self.getMessagesByPage(sessionId, user, start_msg_id,end_msg_id , page, pagesize, isoffset, function (err, res) {
  853. if (err) {
  854. if (handler) {
  855. handler(err, null);
  856. return;
  857. }
  858. logger.error("getMessagesByPage error" + err);
  859. ModelUtil.emitError(self.eventEmitter, err, err);
  860. } else {
  861. if (handler) {
  862. handler(null, res);
  863. return;
  864. }
  865. ModelUtil.emitOK(self.eventEmitter, res);
  866. }
  867. })
  868. })
  869. } else if (!end_msg_id) {
  870. redis.zrangeAsync(message_timestamp_key, 0, 0).then(function (res) {
  871. if (res.length == 0) {
  872. ModelUtil.emitOK(self.eventEmitter, res);
  873. return;
  874. }
  875. end_msg_id = res[0];
  876. self.getMessagesByPage(sessionId, user, end_msg_id,start_msg_id, page, pagesize, isoffset, function (err, res) {
  877. if (err) {
  878. if (handler) {
  879. handler(err, null);
  880. return;
  881. }
  882. logger.error("getMessagesByPage error" + err);
  883. ModelUtil.emitError(self.eventEmitter, err, err);
  884. } else {
  885. if (handler) {
  886. handler(null, res);
  887. return;
  888. }
  889. ModelUtil.emitOK(self.eventEmitter, res);
  890. }
  891. })
  892. })
  893. } else {
  894. self.getMessagesByPage(sessionId, user, end_msg_id, start_msg_id, page, pagesize, isoffset, function (err, res) {
  895. if (err) {
  896. if (handler) {
  897. handler(err, null);
  898. return;
  899. }
  900. logger.error("getMessagesByPage error" + err);
  901. ModelUtil.emitError(self.eventEmitter, err, err);
  902. } else {
  903. if (handler) {
  904. handler(null, res);
  905. return;
  906. }
  907. ModelUtil.emitOK(self.eventEmitter, res);
  908. }
  909. })
  910. }
  911. }
  912. /**
  913. * 分页获取会话消息。
  914. *
  915. * @param sessionId 必选。会话ID
  916. * @param userId 必选。用户ID
  917. * @param startMsgId 必选。会话的的起始消息ID,作为检索的起始依据
  918. * @param endMsgId 必选。会话中的结束消息ID
  919. * @param page 必选。页码
  920. * @param size 必选。页面大小
  921. * @param handler 必选。回调
  922. */
  923. getMessagesByPage(sessionId, userId, startMsgId, endMsgId, page, size, isoffset, handler) {
  924. let messagesTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  925. let messagesKey = RedisModel.makeRedisKey(REDIS_KEYS.Messages, sessionId);
  926. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  927. let sessionParticipantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  928. let participants = new Participants();
  929. let offset = (page - 1 < 0 ? 0 : page - 1) * size;
  930. let count = size;
  931. if (page > 1 || isoffset == 1) {
  932. offset += 1; // 翻页由于闭区间,需跳过本身数据
  933. }
  934. participants.existsParticipant(sessionId, userId, function (err, res) {
  935. if (!res) {
  936. handler(Error("User not found in session " + sessionId), null);
  937. } else {
  938. //将消息ID转换成分值
  939. redis.multi()
  940. .zscore(messagesTimestampKey, startMsgId)
  941. .zscore(messagesTimestampKey, endMsgId)
  942. .hgetall(sessionKey)
  943. .zrange(sessionParticipantsKey, 0, -1)
  944. .execAsync()
  945. .then(function (res) {
  946. let startMsgScore = res[1];
  947. let endMsgScore = res[0];
  948. let session = res[2];
  949. let users = res[3];
  950. if (startMsgScore == null || endMsgScore == null || (startMsgScore == endMsgScore && isoffset == 1)) {
  951. handler(null, []);
  952. return;
  953. }
  954. //结束大于开始,正序取数据,返回的数据顺序也是逆序的,反向拉取数据,
  955. // 当end>start取出来都是空的,为了给前端获取新数据使用,一般不出现这种情况
  956. if(endMsgScore>startMsgScore){
  957. redis.zrangebyscoreAsync(messagesTimestampKey, startMsgScore, endMsgScore, "limit", offset, count)
  958. .then(function (res) {
  959. if (res.length == 0) {
  960. handler(null, []);
  961. return;
  962. }
  963. redis.hmgetAsync(messagesKey, res).then(function (messages) {
  964. messages.reverse();
  965. handler(null, messages);
  966. }).then(function () {
  967. Sessions.updateParticipantLastFetchTime(sessionId, userId, new Date().getTime());
  968. if(session.type == SESSION_TYPES.P2P){
  969. for(var j in users){
  970. if(users[j]==userId)continue;
  971. WechatClient.sendAllRead(users[j],sessionId);
  972. }
  973. }else if(session.type == SESSION_TYPES.MUC || session.type == SESSION_TYPES.PRESCRIPTION){
  974. for(var j in users){
  975. if(users[j]==userId)continue;
  976. WechatClient.sendMucAllRead(users[j],userId,sessionId);
  977. }
  978. }
  979. })
  980. })
  981. .catch(function (err) {
  982. logger.error("Get message by page failed: ", err);
  983. handler(err, false);
  984. })
  985. }else{
  986. // 从消息时间表中过滤出要获取的消息ID列表,倒序取出消息
  987. redis.zrevrangebyscoreAsync(messagesTimestampKey, startMsgScore, endMsgScore, "limit", offset, count)
  988. .then(function (res) {
  989. if (res.length == 0) {
  990. handler(null, []);
  991. return;
  992. }
  993. redis.hmgetAsync(messagesKey, res).then(function (messages) {
  994. handler(null, messages);
  995. }).then(function () {
  996. Sessions.updateParticipantLastFetchTime(sessionId, userId, new Date().getTime());
  997. if(session.type == SESSION_TYPES.P2P){
  998. for(var j in users){
  999. if(users[j]==userId)continue;
  1000. //通知对方自己已经读取数据
  1001. WechatClient.sendAllRead(users[j],sessionId);
  1002. }
  1003. }else if(session.type == SESSION_TYPES.MUC || session.type == SESSION_TYPES.PRESCRIPTION){
  1004. for(var j in users){
  1005. if(users[j]==userId)continue;
  1006. //如果是患者拉取数据告诉在线的医生患者已经读取数据
  1007. WechatClient.sendMucAllRead(users[j],userId,sessionId);
  1008. }
  1009. }
  1010. })
  1011. })
  1012. .catch(function (err) {
  1013. logger.error("Get message by page failed: ", err);
  1014. handler(err, false);
  1015. })
  1016. }
  1017. })
  1018. }
  1019. })
  1020. }
  1021. /**
  1022. * 获取所有会话的未读消息数。
  1023. */
  1024. getAllSessionsUnreadMessageCount(userId,handler) {
  1025. let self = this;
  1026. let count = 0;
  1027. let patientCount = 0;
  1028. let doctorCount = 0;
  1029. let patientEndCount = 0;
  1030. SessionRepo.findAll(userId, function (err, res) {
  1031. // SessionRepo.findUnEndAll(userId, function (err, res) {
  1032. if (err) {
  1033. if(handler)
  1034. {
  1035. handler(err,res);
  1036. return;
  1037. }
  1038. ModelUtil.logError("getAllSessionsUnreadMessageCount is failed", err);
  1039. return;
  1040. }
  1041. if (res.length == 0) {
  1042. if(handler)
  1043. {
  1044. handler(err,count);
  1045. return;
  1046. }
  1047. ModelUtil.emitOK(self.eventEmitter, {count: count});
  1048. return;
  1049. }
  1050. for (let j in res) {
  1051. if (res[j].type == SESSION_TYPES.SYSTEM) {
  1052. if (j == res.length - 1) {
  1053. if(handler){
  1054. handler(err,count);
  1055. return;
  1056. }
  1057. ModelUtil.emitOK(self.eventEmitter, {count: count, patient: patientCount, doctor: doctorCount});
  1058. }
  1059. continue;
  1060. }
  1061. callback(res, j, res[j]);
  1062. }
  1063. });
  1064. function callback(res, j, session) {
  1065. self.getSessionUnreadMessageCount(res[j].id, userId, function (err, con) {
  1066. if (err) {
  1067. if(handler)
  1068. {
  1069. handler(err,count);
  1070. return;
  1071. }
  1072. ModelUtil.logError("getAllSessionsUnreadMessageCount is failed", err);
  1073. }
  1074. count = count + con;
  1075. if (session.business_type == SESSION_BUSINESS_TYPE.PATIENT) {
  1076. if(session.status == SESSION_STATUS.ENDED){//新增判断是否咨询结束
  1077. patientEndCount = patientEndCount + con;
  1078. }else{
  1079. patientCount = patientCount + con;
  1080. }
  1081. } else {
  1082. doctorCount = doctorCount + con;
  1083. }
  1084. if (j == res.length - 1) {
  1085. if(handler)
  1086. {
  1087. handler(err,count)
  1088. return;
  1089. }
  1090. ModelUtil.emitOK(self.eventEmitter, {count: count, patient: patientCount,patientEnd: patientEndCount, doctor: doctorCount});
  1091. }
  1092. })
  1093. }
  1094. }
  1095. /**
  1096. * 获取会话的未读消息数。根据成员最后一次获取消息的时候与当前时间。
  1097. *
  1098. * @param sessionId
  1099. * @param userId
  1100. */
  1101. getSessionUnreadMessageCount(sessionId, userId, handler) {
  1102. let self = this;
  1103. let messagesByTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  1104. let participantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  1105. async.waterfall([
  1106. // 此成员最后获取消息的时间
  1107. function (callback) {
  1108. redis.zscoreAsync(participantsKey, userId)
  1109. .then(function (lastFetchTime) {
  1110. callback(null, lastFetchTime);
  1111. })
  1112. },
  1113. // 计算最后获取消息的时间之后到现在有多少条消息
  1114. function (lastFetchTime, callback) {
  1115. if (!lastFetchTime) lastFetchTime = 0;
  1116. let now = new Date().getTime();
  1117. redis.zcountAsync(messagesByTimestampKey, parseInt(lastFetchTime)+1, now)
  1118. .then(function (count) {
  1119. if (handler) {
  1120. handler(null, count);
  1121. } else {
  1122. ModelUtil.emitOK(self.eventEmitter, {count: count});
  1123. }
  1124. })
  1125. }
  1126. ], function (err, res) {
  1127. if (err) {
  1128. if (handler) {
  1129. handler(err, 0);
  1130. } else {
  1131. ModelUtil.emitError(self.eventEmitter, "Get session unread message count failed.")
  1132. }
  1133. }
  1134. });
  1135. }
  1136. /**
  1137. * 获取会话未读消息数。根据成员最后一次获取消息的时候与当前时间。
  1138. */
  1139. getSessionUnreadMessages(sessionId, userId) {
  1140. let self = this;
  1141. let messagesByTimestampKey = RedisModel.makeRedisKey(REDIS_KEYS.MessagesByTimestamp, sessionId);
  1142. let participantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  1143. async.waterfall([
  1144. // 此成员最后获取消息的时间
  1145. function (callback) {
  1146. redis.zscoreAsync(participantsKey, userId)
  1147. .then(function (lastFetchTime) {
  1148. callback(null, lastFetchTime);
  1149. })
  1150. },
  1151. // 最后获取消息的时间之后到现在的消息ID列表
  1152. function (lastFetchTime, callback) {
  1153. if (!lastFetchTime) lastFetchTime = 0;
  1154. let now = new Date().getTime();
  1155. redis.zrangebyscoreAsync(messagesByTimestampKey, lastFetchTime, now)
  1156. .then(function (messageIds) {
  1157. callback(null, messageIds);
  1158. })
  1159. },
  1160. // 获取消息
  1161. function (messageIds, callback) {
  1162. if (messageIds.length == 0) {
  1163. ModelUtil.emitOK(self.eventEmitter, []);
  1164. return;
  1165. }
  1166. let startMsgId = messageIds[0];
  1167. let endMsgId = messageIds[messageIds.length - 1];
  1168. self.getMessagesByPage(sessionId, userId, startMsgId, endMsgId, 0, messageIds.length, 0, function (err, res) {
  1169. if (err) {
  1170. ModelUtil.emitError(self.eventEmitter, err.message);
  1171. return;
  1172. }
  1173. ModelUtil.emitOK(self.eventEmitter, res);
  1174. });
  1175. }
  1176. ], function (err, res) {
  1177. if (err) {
  1178. ModelUtil.emitError(self.eventEmitter, "Get session unread message count failed.")
  1179. }
  1180. });
  1181. }
  1182. /**
  1183. * 保存消息。
  1184. *
  1185. * 也可以根据议题保存消息,但最终还是保存到与会话对象。
  1186. *
  1187. * see also: saveMessageByTopic
  1188. *
  1189. * @param message
  1190. * @param sessionId
  1191. */
  1192. saveMessageBySession(sessionId, message) {
  1193. let self = this;
  1194. let messages = new Messages();
  1195. let participants = new Participants();
  1196. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  1197. let messageId = mongoose.Types.ObjectId().toString();
  1198. let sessionType =0;
  1199. message.id = messageId;
  1200. // 检查会话中是否存在此成员
  1201. participants.existsParticipant(sessionId, message.sender_id, function (err, res) {
  1202. if (err) {
  1203. ModelUtil.emitError(self.eventEmitter, "Check session participant failed: ", err);
  1204. return;
  1205. }
  1206. if (res) {
  1207. redis.hmgetAsync(sessionKey, ["type", "name"]).then(function (res) {
  1208. sessionType = res[0];
  1209. let sessionName = res[1];
  1210. if (sessionType == null) {
  1211. ModelUtil.emitError(self.eventEmitter, "Session " + sessionId + " is not found.");
  1212. return;
  1213. }
  1214. if(sessionType == SESSION_TYPES.MUC || sessionType == SESSION_TYPES.PRESCRIPTION){
  1215. if(message.content_type == CONTENT_TYPES.PlainText ||
  1216. message.content_type == CONTENT_TYPES.Image ||
  1217. message.content_type == CONTENT_TYPES.Audio||
  1218. message.content_type == CONTENT_TYPES.Video){
  1219. TopicRepo.findLastBySessionId(sessionId,function(err,res){
  1220. if(res&&res.length>0&&res[0].reply==0){
  1221. TopicRepo.replyTopic(message.sender_id,message.id,res[0].id,function(err,res){
  1222. if(err){
  1223. logger.error("update topic reply error");
  1224. }else{
  1225. logger.warn("update topic reply success");
  1226. }
  1227. });
  1228. }
  1229. })
  1230. }
  1231. }
  1232. // 消息保存到Redis,并更新会话最后状态、用户最后消息获取时间
  1233. messages.saveMessageToRedis(sessionId, sessionType, messageId, message);
  1234. Messages.updateLastContent(sessionKey, sessionType, sessionName, message);
  1235. Sessions.updateParticipantLastFetchTime(sessionId, message.sender_id, message.timestamp.getTime());
  1236. // 更新MYSQL中会话的最新状态,并保存消息
  1237. SessionRepo.updateSessionLastStatus(message.sender_id, message.sender_name, message.timestamp, message.content, message.content_type, sessionId);
  1238. messages.saveMessageToMysql(sessionId, sessionType, messageId, message, function (err, res) {
  1239. if (err) {
  1240. ModelUtil.emitError(self.eventEmitter, {message: "Failed to save message to mysql: " + err});
  1241. } else {
  1242. message.timestamp = message.timestamp.getTime();
  1243. ModelUtil.emitOK(self.eventEmitter, {count: 1, messages: [message]});
  1244. }
  1245. });
  1246. }).then(function (res) {
  1247. // 推送消息
  1248. ParticipantRepo.findIds(sessionId, function (err, res) {
  1249. if (err) {
  1250. ModelUtil.logError("Push message from session: get participant's id list failed: ", err);
  1251. } else {
  1252. message.session_id = sessionId;
  1253. res.forEach(function (participant) {
  1254. if (participant.id == message.sender_id||sessionType==SESSION_TYPES.SYSTEM){
  1255. message.sender_img = participant.avatar;
  1256. callPush(res,message);
  1257. }
  1258. })
  1259. }
  1260. })
  1261. }).catch(function (err) {
  1262. ModelUtil.emitError(self.eventEmitter, {message: "Error occurred while save message to session: " + err});
  1263. })
  1264. } else {
  1265. ModelUtil.emitDataNotFound(self.eventEmitter, {message: "当前会话找不到此发送者"});
  1266. }
  1267. });
  1268. function callPush(participants,message){
  1269. participants.forEach(function (participant) {
  1270. if (participant.id !== message.sender_id &&
  1271. participant.participant_role == PARTICIPANT_ROLES.HOST) {
  1272. Sessions.pushNotification(participant.id, participant.name, message,sessionType);
  1273. }
  1274. });
  1275. }
  1276. }
  1277. sendTopicMessages(topicId, message) {
  1278. let self = this;
  1279. TopicRepo.findAllByTopicId(topicId, function (err, res) {
  1280. if (err || res.length == 0) {
  1281. ModelUtil.emitOK(self.eventEmitter, {status: -1, "message": "议题获取失败"});
  1282. return;
  1283. }
  1284. self.saveMessageByTopic(message, res[0].session_id, function (err, messageId) {
  1285. if (err) {
  1286. ModelUtil.emitOK(self.eventEmitter, {status: -1, "message": err});
  1287. } else {
  1288. message.id = messageId;
  1289. ModelUtil.emitOK(self.eventEmitter, {status: 200, "message": "发送成功", data: message});
  1290. }
  1291. });
  1292. });
  1293. }
  1294. /**
  1295. * 保存消息
  1296. *
  1297. * @param message
  1298. * @param sessionId
  1299. * @param handler
  1300. */
  1301. saveMessageByTopic(message, sessionId, handler) {
  1302. let messages = new Messages();
  1303. let participants = new Participants();
  1304. let session_key = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  1305. let messageId = mongoose.Types.ObjectId().toString();
  1306. let self = this;
  1307. let sessionType = 0;
  1308. let sessionName = "";
  1309. let agent = message.agent;//代理人
  1310. message.id = messageId;
  1311. if(!message.timestamp){
  1312. message.timestamp = new Date();
  1313. }
  1314. // 发送成员必须处于会话中
  1315. participants.existsParticipant(sessionId, message.sender_id, function (err, res) {
  1316. if (res) {
  1317. redis.hmgetAsync(session_key, ["type", "name"]).then(function (res) {
  1318. sessionType = res[0];
  1319. sessionName = res[1];
  1320. if (!sessionType || !sessionName) {
  1321. logger.error("Unknown session key " + session_key);
  1322. if (handler) {
  1323. handler(new Error("Unknown session key " + session_key));return;
  1324. };
  1325. }
  1326. }).then(function (res) {
  1327. // 消息数据双写,并更新用户最后消息获取时间,会话新状态等
  1328. messages.saveMessageToRedis(sessionId, sessionType, messageId, message);
  1329. messages.saveMessageToMysql(sessionId, sessionType, messageId, message);
  1330. // 更新会话最新状态及成员最后一次消息获取时间
  1331. Sessions.updateParticipantLastFetchTime(sessionId, message.sender_id, message.timestamp.getTime());
  1332. Messages.updateLastContent(session_key, sessionType, sessionName, message);
  1333. SessionRepo.updateSessionLastStatus(message.sender_id, message.sender_name, message.timestamp, message.content, message.content_type, sessionId);
  1334. if (handler) {
  1335. handler(null, messageId);
  1336. return;
  1337. }
  1338. }).then(function (res) {
  1339. // 推送消息
  1340. ParticipantRepo.findIds(sessionId, function (err, res) {
  1341. if (err) {
  1342. logger.error(err);
  1343. } else {
  1344. message.session_id = sessionId;
  1345. res.forEach(function (participant) {
  1346. if (participant.id == message.sender_id){
  1347. message.sender_img = participant.avatar;
  1348. callPush(res,message);
  1349. }
  1350. })
  1351. }
  1352. })
  1353. }).catch(function (err) {
  1354. log.error(err);
  1355. return;
  1356. })
  1357. } else {
  1358. if (handler){ handler("用户不在此会话当中!", messageId);return;}
  1359. }
  1360. });
  1361. function callPush(participants,message){
  1362. participants.forEach(function (participant) {
  1363. if ((participant.id !== message.sender_id||message.content_type == CONTENT_TYPES.PrescriptionBloodStatus ||
  1364. message.content_type == CONTENT_TYPES.PrescriptionFollowupContent) &&
  1365. participant.participant_role == PARTICIPANT_ROLES.HOST) {
  1366. Sessions.pushNotification(participant.id, participant.name, message,sessionType);
  1367. }
  1368. });
  1369. }
  1370. }
  1371. /**
  1372. * 保存代理人进入的消息
  1373. *
  1374. * @param message
  1375. * @param sessionId
  1376. * @param handler
  1377. */
  1378. saveIntoMessageByTopic(message, sessionId, handler) {
  1379. let messages = new Messages();
  1380. let participants = new Participants();
  1381. let session_key = RedisModel.makeRedisKey(REDIS_KEYS.Session, sessionId);
  1382. let messageId = mongoose.Types.ObjectId().toString();
  1383. let self = this;
  1384. let sessionType = 0;
  1385. let sessionName = "";
  1386. let agent = message.agent;//代理人
  1387. message.id = messageId;
  1388. if(!message.timestamp){
  1389. message.timestamp = new Date();
  1390. }
  1391. // 发送成员必须处于会话中
  1392. participants.existsParticipant(sessionId, message.sender_id, function (err, res) {
  1393. if (res) {
  1394. redis.hmgetAsync(session_key, ["type", "name"]).then(function (res) {
  1395. sessionType = res[0];
  1396. sessionName = res[1];
  1397. if (!sessionType || !sessionName) {
  1398. logger.error("Unknown session key " + session_key);
  1399. if (handler) {
  1400. handler(new Error("Unknown session key " + session_key));return;
  1401. };
  1402. }
  1403. }).then(function (res) {
  1404. //查找最后一条数据,如果一致就不保存
  1405. MessageRepo.findLastMessage(sessionId,sessionType,function (err, res) {
  1406. if (err) {
  1407. logger.error(err);
  1408. } else {
  1409. res.forEach(function (mes) {
  1410. // if(mes.content==message.content&&message.content_type==mes.content_type){
  1411. if(mes.agent==message.agent){
  1412. handler(null, messageId);
  1413. return;
  1414. }else {
  1415. // 消息数据双写,并更新用户最后消息获取时间,会话新状态等
  1416. messages.saveMessageToRedis(sessionId, sessionType, messageId, message);
  1417. messages.saveMessageToMysql(sessionId, sessionType, messageId, message);
  1418. // 更新会话最新状态及成员最后一次消息获取时间
  1419. Sessions.updateParticipantLastFetchTime(sessionId, message.sender_id, message.timestamp.getTime());
  1420. Messages.updateLastContent(session_key, sessionType, sessionName, message);
  1421. SessionRepo.updateSessionLastStatus(message.sender_id, message.sender_name, message.timestamp, message.content, message.content_type, sessionId);
  1422. if (handler) {
  1423. handler(null, messageId);
  1424. return;
  1425. }
  1426. }
  1427. })
  1428. }
  1429. });
  1430. }).then(function (res) {
  1431. // 推送消息
  1432. ParticipantRepo.findDoctorIds(sessionId, function (err, res) {
  1433. if (err) {
  1434. logger.error(err);
  1435. } else {
  1436. message.session_id = sessionId;
  1437. res.forEach(function (participant) {
  1438. Sessions.pushIntoNotification(participant.id, participant.name, message,sessionType);
  1439. })
  1440. }
  1441. })
  1442. }).catch(function (err) {
  1443. log.error(err);
  1444. return;
  1445. })
  1446. } else {
  1447. if (handler){ handler("用户不在此会话当中!", messageId);return;}
  1448. }
  1449. });
  1450. }
  1451. /**
  1452. * 置顶操作
  1453. */
  1454. stickSession(sessionId, user) {
  1455. let user_session_key = RedisModel.makeRedisKey(REDIS_KEYS.UserSessions, user);
  1456. let self = this;
  1457. //取出最大的session
  1458. redis.zrevrangeAsync(user_session_key, 0, 0).then(function (res) {
  1459. //获取该session的时间搓
  1460. redis.zscoreAsync(user_session_key, res).then(function (scoreres) {
  1461. let nowtime = new Date().getTime();
  1462. //当前时间搓比redis的时间搓更早证明没有置顶过
  1463. if (scoreres <= nowtime) {
  1464. //初始化置顶
  1465. redis.zaddAsync(user_session_key, STICKY_SESSION_BASE_SCORE, sessionId).then(function (res) {
  1466. logger.info("stickSession:" + sessionId + ",res:" + res);
  1467. ModelUtil.emitOK(self.eventEmitter, {});
  1468. }).then(function () {
  1469. SessionRepo.saveStickySession(sessionId, user, STICKY_SESSION_BASE_SCORE);
  1470. })
  1471. } else {
  1472. //已有置顶的数据,取出来加1保存回去
  1473. scoreres = Number(scoreres) + 1;
  1474. redis.zaddAsync(user_session_key, scoreres, sessionId).then(function () {
  1475. logger.info("stickSession:" + sessionId + ",res:" + res);
  1476. ModelUtil.emitOK(self.eventEmitter, {});
  1477. }).then(function () {
  1478. SessionRepo.saveStickySession(sessionId, user, scoreres);
  1479. })
  1480. }
  1481. })
  1482. })
  1483. }
  1484. /**
  1485. * 取消会话置顶
  1486. */
  1487. cancelStickSession(sessionId, user) {
  1488. let user_session_key = RedisModel.makeRedisKey(REDIS_KEYS.UserSessions, user);
  1489. let participants_key = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  1490. let self = this;
  1491. redis.zscoreAsync(participants_key, user).then(function (res) {
  1492. if (!res) {
  1493. res = new Date().getTime();
  1494. }
  1495. redis.zaddAsync(user_session_key, res, sessionId).then(function (res) {
  1496. logger.info("cancelStickSession:" + sessionId);
  1497. ModelUtil.emitOK(self.eventEmitter, {});
  1498. }).then(function () {
  1499. SessionRepo.unStickySession(sessionId, user);
  1500. });
  1501. })
  1502. }
  1503. /**
  1504. * 更新会话参与者的最后消息获取时间。
  1505. *
  1506. * @param sessionId
  1507. * @param userId
  1508. */
  1509. static updateParticipantLastFetchTime(sessionId, userId, score) {
  1510. score = score + 1;
  1511. let participantsKey = RedisModel.makeRedisKey(REDIS_KEYS.SessionParticipants, sessionId);
  1512. redis.zaddAsync(participantsKey, score, userId)
  1513. .then(function (res) {
  1514. ParticipantRepo.updateLastFetchTime(new Date(score), sessionId, userId, function (err, res) {
  1515. if (err) {
  1516. logger.error("Update participant last fetch time failed: ", err);
  1517. }
  1518. });
  1519. })
  1520. .catch(function (err) {
  1521. logger.error("Update participant last fetch time failed: ", err);
  1522. });
  1523. }
  1524. /**
  1525. * 向用户推送通知,微信端用户直接推送消息,APP端通过个推发送通知消息。
  1526. *
  1527. * @param targetUserId
  1528. * @param message
  1529. */
  1530. static pushNotification(targetUserId, targetUserName, message,sessionType) {
  1531. let self = this;
  1532. Users.isPatientId(targetUserId, function (err, isPatient) {
  1533. if (isPatient) {
  1534. if(config.environment!='local'){//pc版不直接发送给居民,通过redis的publish
  1535. WechatClient.sendMessage(targetUserId, targetUserName, message);
  1536. }
  1537. message.targetUserId = targetUserId;
  1538. message.targetUserName = targetUserName;
  1539. message.sessionType = sessionType;
  1540. message.targetType = 'patient';
  1541. } else {
  1542. if(sessionType==SESSION_TYPES.P2P){
  1543. WechatClient.sendReadDoctorByDoctorId(targetUserId, message);
  1544. }
  1545. //告知医生新消息
  1546. WechatClient.sendSocketMessageToDoctor(targetUserId,message);
  1547. WlyySDK.request(targetUserId, '', '', '', '/im/common/message/messages', 'POST', function (err, res) {
  1548. let count = 0;
  1549. res = JSON.parse(res)
  1550. if (res.status == 200) {
  1551. let data = res.data;
  1552. count = parseInt(JSON.parse(data.imMsgCount).count) + parseInt(data.system.amount) + parseInt(data.healthIndex.amount) + parseInt(data.sign.amount);
  1553. }
  1554. if(config.environment!='local'){//pc版不推送个推,通过redis的publish
  1555. AppClient.sendNotification(targetUserId, message,sessionType,count);
  1556. }
  1557. //外网pcim通过socket推送
  1558. WechatClient.sendPcImSocket(targetUserId,message,sessionType);
  1559. });
  1560. message.targetUserId = targetUserId;
  1561. message.targetUserName = targetUserName;
  1562. message.sessionType = sessionType;
  1563. message.targetType = 'doctor';
  1564. }
  1565. //redis发布消息
  1566. if(config.pubSubSwitch) {//接收订阅消息处理开关,本地运行和测试库单独运行时防止用户接收消息2次
  1567. pubSub.publish(config.pubChannel,JSON.stringify(message));
  1568. }
  1569. });
  1570. }
  1571. /**
  1572. * 获取redis订阅消息,并处理
  1573. * @param targetUserId
  1574. * @param targetUserName
  1575. * @param message
  1576. * @param sessionType
  1577. */
  1578. static getRedisPushNotification(message) {
  1579. if (message.targetType=='patient') {
  1580. if(config.environment!='local'){//pc版接收要发给居民的消息不做处理
  1581. WechatClient.sendMessage(message.targetUserId, message.targetUserName, message);
  1582. }
  1583. } else {
  1584. if(message.sessionType==SESSION_TYPES.P2P){
  1585. WechatClient.sendReadDoctorByDoctorId(message.targetUserId, message);
  1586. }
  1587. //告知医生新消息
  1588. WechatClient.sendSocketMessageToDoctor(message.targetUserId,message);
  1589. if(config.environment!='local'){//pc版不推送个推
  1590. WlyySDK.request(message.targetUserId, '', '', '', '/im/common/message/messages', 'POST', function (err, res) {
  1591. let count = 0;
  1592. res = JSON.parse(res)
  1593. if (res.status == 200) {
  1594. let data = res.data;
  1595. count = parseInt(JSON.parse(data.imMsgCount).count) + parseInt(data.system.amount) + parseInt(data.healthIndex.amount) + parseInt(data.sign.amount);
  1596. }
  1597. AppClient.sendNotification(message.targetUserId, message,message.sessionType,count);
  1598. });
  1599. }
  1600. }
  1601. }
  1602. /**
  1603. * 向APP端通过socket发送通知消息。
  1604. *
  1605. * @param targetUserId
  1606. * @param message
  1607. */
  1608. static pushIntoNotification(targetUserId, targetUserName, message,sessionType) {
  1609. if(sessionType==SESSION_TYPES.P2P){
  1610. WechatClient.sendReadDoctorByDoctorId(targetUserId, message);
  1611. }
  1612. //告知医生新消息
  1613. WechatClient.sendSocketMessageToDoctor(targetUserId,message);
  1614. }
  1615. /**
  1616. * 针对MUC模式更新会话的当前状态
  1617. * @param sessionId
  1618. */
  1619. updateSessionStatus(sessionId,status,handler){
  1620. let self = this;
  1621. let sessionKey = RedisModel.makeRedisKey(REDIS_KEYS.Session,sessionId);
  1622. redis.hsetAsync(sessionKey,"status",status).then(function(res){
  1623. SessionRepo.updateSessionStatus(sessionId,status,function(err,sqlResult){
  1624. if(handler){
  1625. handler(err,sqlResult);
  1626. return;
  1627. }
  1628. if(err){
  1629. logger.error("set session status to mysql is error !");
  1630. }else{
  1631. logger.info("set session status is success");
  1632. ModelUtil.emitOK(self.eventEmitter, []);
  1633. }
  1634. });
  1635. });
  1636. }
  1637. }
  1638. // Expose class
  1639. module.exports = Sessions;