sessions.js 68 KB

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