浏览代码

增加患者消息透传

Sand 8 年之前
父节点
当前提交
f17dec8853

+ 1 - 1
src/doctor/app.armour.js

@ -1,7 +1,7 @@
/**
    服务守护脚本。当服务器进程失败时,重启IM服务器。
    守护服务不是应用程序的入口,但作为服务的外壳,提供进程信号监听与进程重启,保证服务的连接性。
    守护服务不是应用程序的入口,但作为服务的外壳,提供进程信号监听与进程重启,保证服务的连续性。
 */
var cp = require('child_process');
var worker;

+ 119 - 111
src/doctor/endpoints/chats.endpoint.js

@ -11,12 +11,15 @@ var getui = require('getui');
var log = require('../util/log.js');
var objectUtil = require("../util/objectUtil.js");
var Patient = new require("../models/patient");
var patient = new Patient();
var smRepo = require("../repository/system.msg.repo.js");
var pmRepo = require('../repository/private.msg.repo.js');
var gmRepo = require("../repository/group.msg.repo.js");
var nmRepo = require("../repository/notify.msg.repo.js");
var statsRepo = require("../repository/stats.msg.repo.js");
var userRepo = require("../repository/doctor.repo.js");
var doctorRepo = require("../repository/doctor.repo.js");
var groupRepo = require("../repository/group.repo.js");
var searchRepo = require('../repository/search.repo.js');
@ -64,7 +67,7 @@ router.post(APIv1.Chats.SM, function (req, res) {
    }
    // 消息处理
    userRepo.getUserStatus(message.to, function (err, rows) {
    doctorRepo.getUserStatus(message.to, function (err, rows) {
        if (err) {
            console.log("Lookup system message receiver failed: ", err);
@ -158,123 +161,128 @@ router.post(APIv1.Chats.PM, function (req, res) {
    // 字段判断
    var testing = objectUtil.fieldsCheck(message, "from", "to", "contentType", "content");
    if (!testing.pass) {
        throw {httpStatus: 406, message: testing.message}
        throw {httpStatus: 406, message: testing.message};
    }
    // 处理消息
    userRepo.isExist(message.to, function (err, rows) {
        if (err) {
            console.log('Lookup receiving users failed: ', err);
            res.status(500).send({message: 'Lookup receiving users failed.'});
            return;
        }
        if (rows.length == 0) {
            res.status(404).send({message: 'Receiving users not found.'});
            return;
        }
        // 保存消息
        var tempContent = message.contentType === CONTENT_TYPES.Article ? JSON.stringify(message.content) : message.content;
        pmRepo.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
            if (err) {
                res.status(500).send({message: 'Save private message failed.'});
                return;
            }
            // 结束网络连接,后续操作继续执行
            pmRepo.findOneMessage(result.insertId, function (err, msg) {
    patient.isPatientCode(message.to,
        function () {
            patient.sendMessage(message);
        }, function () {
            // 处理消息
            doctorRepo.isExist(message.to, function (err, rows) {
                if (err) {
                    res.status(500).send("Save private message success, but return last message failed.");
                } else {
                    var message = fillMessages(msg);
                    res.status(200).send(message);
                }
            });
            // 更新自身的聊天统计信息
            statsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
            // 更新对端的聊天统计信息
            statsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
                if (err) log.error(err);
            });
                    console.log('Lookup receiving users failed: ', err);
            // 获取对方状态,即对端的系统平台,token等信息,并推送通知消息给对端
            userRepo.getUserStatus(message.to, function (err, result) {
                if (err) {
                    log.error('Get target user status for private message failed: ' + message.to);
                    res.status(500).send({message: 'Lookup receiving users failed.'});
                    return;
                }
                // 构建通知消息
                var title = '新消息';
                var content = '';
                if (message.contentType === CONTENT_TYPES.PlainText) {
                    content = message.content;
                } else if (message.contentType === CONTENT_TYPES.Image) {
                    content = '[图片]';
                } else if (message.contentType === CONTENT_TYPES.Audio) {
                    content = '[语音]';
                } else {
                    content = '接收到一条新消息';
                if (rows.length == 0) {
                    res.status(404).send({message: 'Receiving users not found.'});
                    return;
                }
                var pushable = false;
                var target;
                if (result.length > 0) {
                    target = result[0];
                    if (target.is_online) {
                        pushable = true;
                // 保存消息
                var tempContent = message.contentType === CONTENT_TYPES.Article ? JSON.stringify(message.content) : message.content;
                pmRepo.save(message.to, message.from, message.contentType, tempContent, function (err, result) {
                    if (err) {
                        res.status(500).send({message: 'Save private message failed.'});
                        return;
                    }
                }
                var notifyMessage = JSON.stringify({type: 'p2p_msg', from_uid: message.from});
                    // 结束网络连接,后续操作继续执行
                    pmRepo.findOneMessage(result.insertId, function (err, msg) {
                        if (err) {
                            res.status(500).send({message: "Save private message success, but return last message failed."});
                        } else {
                            var message = fillMessages(msg);
                            res.status(200).send(message);
                        }
                    });
                // 保存通知消息到数据库中并根据用户在线状态推送此消息
                nmRepo.save(message.to, message.contentType, title, content, notifyMessage, pushable, function (err, result) {
                    if (err) {
                        log.error('Save private notify message failed, ', err);
                    } else {
                        if (pushable === true) {
                            if (target.platform === PLATFORMS.iOS) {
                                getui.pushAPN(message.to,
                                    target.token,
                                    message.contentType,
                                    title,
                                    content,
                                    notifyMessage,
                                    function (err, result) {
                                        if (err != null) {
                                            console.log(err);
                                        } else {
                                            console.log(result);
                                        }
                                    });
                            } else if (target.platform === PLATFORMS.Android) {
                                getui.pushAndroid(target.client_id,
                                    message.contentType,
                                    title,
                                    content,
                                    notifyMessage,
                                    target.status,
                                    function (err, result) {
                                        if (err != null) {
                                            console.log(err);
                                        } else {
                                            console.log(result);
                                        }
                                    });
                    // 更新自身的聊天统计信息
                    statsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
                        if (err) log.error(err);
                    });
                    // 更新对端的聊天统计信息
                    statsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
                        if (err) log.error(err);
                    });
                    // 获取对方状态,即对端的系统平台,token等信息,并推送通知消息给对端
                    doctorRepo.getUserStatus(message.to, function (err, result) {
                        if (err) {
                            log.error('Get target user status for private message failed: ' + message.to);
                            return;
                        }
                        // 构建通知消息
                        var title = '新消息';
                        var content = '';
                        if (message.contentType === CONTENT_TYPES.PlainText) {
                            content = message.content;
                        } else if (message.contentType === CONTENT_TYPES.Image) {
                            content = '[图片]';
                        } else if (message.contentType === CONTENT_TYPES.Audio) {
                            content = '[语音]';
                        } else {
                            content = '接收到一条新消息';
                        }
                        var pushable = false;
                        var target;
                        if (result.length > 0) {
                            target = result[0];
                            if (target.is_online) {
                                pushable = true;
                            }
                        }
                    }
                        var notifyMessage = JSON.stringify({type: 'p2p_msg', from_uid: message.from});
                        // 保存通知消息到数据库中并根据用户在线状态推送此消息
                        nmRepo.save(message.to, message.contentType, title, content, notifyMessage, pushable, function (err, result) {
                            if (err) {
                                log.error('Save private notify message failed, ', err);
                            } else {
                                if (pushable === true) {
                                    if (target.platform === PLATFORMS.iOS) {
                                        getui.pushAPN(message.to,
                                            target.token,
                                            message.contentType,
                                            title,
                                            content,
                                            notifyMessage,
                                            function (err, result) {
                                                if (err != null) {
                                                    console.log(err);
                                                } else {
                                                    console.log(result);
                                                }
                                            });
                                    } else if (target.platform === PLATFORMS.Android) {
                                        getui.pushAndroid(target.client_id,
                                            message.contentType,
                                            title,
                                            content,
                                            notifyMessage,
                                            target.status,
                                            function (err, result) {
                                                if (err != null) {
                                                    console.log(err);
                                                } else {
                                                    console.log(result);
                                                }
                                            });
                                    }
                                }
                            }
                        });
                    });
                });
            });
        });
    });
});
/**
@ -363,12 +371,12 @@ router.post(APIv1.Chats.GM, function (req, res) {
                // 逐个推送通知
                for (var i = 0; i < members.length; i++) {
                    var member = members[i];
                    if (member.user_id === message.from){
                    if (member.user_id === message.from) {
                        continue;
                    }
                    (function (user_id) {
                        userRepo.getUserStatus(user_id, function (err, result) {
                        doctorRepo.getUserStatus(user_id, function (err, result) {
                            if (err) {
                                console.error('Get group member status failed: ', err);
                                return;
@ -540,7 +548,7 @@ router.get(APIv1.Chats.List, function (req, res) {
                var group = groups[i];
                // 过滤掉医生间的求助团队
                if(group.group_type === 2) continue;
                if (group.group_type === 2) continue;
                //查找医生在讨论组的最新的消息记录数
@ -655,7 +663,7 @@ router.get(APIv1.Chats.ListWithPatient, function (req, res) {
                var group = groups[i];
                // 过滤掉医生间的求助团队
                if(group.group_type === 2) continue;
                if (group.group_type === 2) continue;
                chats.groups.push({
                    code: group.code,
@ -1442,27 +1450,27 @@ router.get(APIv1.Chats.SearchAboutDoctor, function (req, res) {
router.get(APIv1.Chats.PMFinished, function (req, res) {
    var userId = req.query.user_id;
    var peerId = req.query.peer_id;
    if(!userId){
    if (!userId) {
        throw {httpStatus: 406, message: "Missing field: user_id"};
    }
    if(!peerId){
    if (!peerId) {
        throw {httpStatus: 406, message: "Missing field: peer_id"};
    }
    pmRepo.isCurrentSessionFinished(userId, peerId, function (err, result) {
        if(err){
        if (err) {
            log.error("Get session finish status failed: ", err);
            throw {httpStatus: 500, message: "Get session finish status failed."};
        }
        var data = {finished: true, consultId: ''};
        if(result.length > 0){
        if (result.length > 0) {
            var finishRow = result[0];
            data.finished = finishRow.finished === 1;
            if(!data.finished){
            if (!data.finished) {
                data.consultId = finishRow.consult_id;
            }
        }

+ 5 - 0
src/doctor/include/commons.js

@ -52,6 +52,11 @@ exports.GROUP_TYPE = {
    DiscussionGroup: 2
};
/**
 * 模型事件。
 *
 * @type {{Error: string, DataNotFound: string, OK: string}}
 */
exports.MODEL_EVENTS = {
    Error: "error",                 // 数据库访问出错
    DataNotFound: "no_data",        // 找不到指定的数据

+ 16 - 0
src/doctor/include/transparent.endpoints.js

@ -0,0 +1,16 @@
/**
 * 透传服务API。透传服务是一个基于C++的服务。
 *
 * author: Sand
 * since: 2016/11/18
 */
"use strict";
exports.TRAN_ENDPOINTS = {
    User: {
        Message: {
            Path: "/user/senddata.do",
            Method: "GET"
        }
    }
};

+ 16 - 0
src/doctor/include/wlyy.endpoints.js

@ -0,0 +1,16 @@
/**
 * 家庭医生平台API。需要与配置文件中的平台地址配合使用。
 *
 * author: Sand
 * since: 2016/11/18
 */
"use strict";
exports.WLYY_ENPOINTS = {
    Doctor: {
        MessageCount: {
            Path: '/wlyy/doctor/message/amount',
            Method: 'POST'
        }
    }
};

+ 128 - 0
src/doctor/models/patient.js

@ -2,3 +2,131 @@
 * 患者模型。
 */
"use strict";
var http = require('http');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var configFile = require('../include/commons').CONFIG_FILE;
var config = require('../resources/config/' + configFile);
var log = require("../util/log.js");
var patientRepo = require('../repository/patient.repo');
var pmRepo = require('../repository/private.msg.repo.js');
var statsRepo = require("../repository/stats.msg.repo.js");
var objectUtil = require("../util/objectUtil.js");
var TRANS_ENDPOINTS = require('../include/transparent.endpoints').TRAN_ENDPOINTS;
// inherit and expose class
util.inherits(Patient, EventEmitter);
module.exports = Patient;
function Patient() {
    EventEmitter.call(this);
}
Patient.prototype.isPatientCode = function (code, trueCallback, falseCallback) {
    patientRepo.isPatientCode(code, function (err, result) {
        if(err){
            log.error('Send message to patient failed: ', err);
            return;
        }
        if(result.length > 0){
            trueCallback();
        } else {
            falseCallback();
        }
    });
};
/**
 * 向患者发送消息。
 *
 * @param userId
 * @param message
 */
Patient.prototype.sendMessage = function (message) {
    // 保存消息,并发送给患者
    pmRepo.save(message.to, message.from, message.contentType, message.contentType, function (err, result) {
        if (err) {
            log.error('Save patient private message failed.');
            return;
        }
        pmRepo.findOneMessage(result.insertId, function (err, msg) {
            if (err) {
                log.error("Save private message success, but return last message failed.");
            } else {
                var feedback = fillMessages(msg);
                // 通知患者
                var postData = JSON.stringify(feedback);
                var options = {
                    hostname: config.transServerConfig.host,
                    port: config.transServerConfig.port,
                    path: TRANS_ENDPOINTS.User.Message.Path + "?userid=" + message.to + "&data=" + encodeURIComponent(postData),
                    method: TRANS_ENDPOINTS.User.Message.Method,
                    headers: {
                        "Content-Type": 'application/json',
                        "Content-Length": postData.length
                    }
                };
                log.info('患者消息透传: http://' + options.hostname + ":" + options.port + options.path);
                var req = http.request(options, function (res) {
                    res.setEncoding('utf8');
                    res.on('data', function (chunk) {
                        log.info('透传服务器返回: ', chunk);
                    });
                });
                req.on('error', function (e) {
                    log.error('患者消息透传出错: ', e.message);
                });
                req.write(postData);
                req.end();
            }
        });
        // 更新自身的聊天统计信息
        statsRepo.updatePrivateChatSummary(message.from, message.to, message.from, message.contentType, message.content, function (err, result) {
            if (err) log.error(err);
        });
        // 更新对端的聊天统计信息
        statsRepo.updatePrivateChatSummary(message.to, message.from, message.from, message.contentType, message.content, function (err, result) {
            if (err) log.error(err);
        });
    });
};
/**
 * 将消息的返回结果合并成JSON。
 *
 * @param rows
 *
 * @returns {startId: 0, count: 0, records: []}
 */
function fillMessages(rows) {
    var messages = {startId: rows.length > 0 ? rows[0].msg_id : '', count: rows.length, records: []};
    for (var i = 0; i < rows.length; i++) {
        var row = rows[i];
        var record = {
            id: row.msg_id,
            from: row.from_uid,
            contentType: row.type,
            content: row.content,
            timestamp: objectUtil.timestampToLong(row.timestamp)
        };
        if (row.to_uid !== undefined) record.to = row.to_uid;
        if (row.at_uid !== undefined) record.at = row.at_uid;
        messages.records.push(record);
    }
    return messages;
}

+ 6 - 5
src/doctor/models/stats.js

@ -2,6 +2,7 @@
 * 统计。
 */
"use strict";
var EventEmitter = require("events").EventEmitter;
var util = require("util");
@ -11,6 +12,10 @@ var modelUtil = require('../util/modelUtil');
var MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
// This class inherits from EventEmitter and expose class
util.inherits(StatsMessage, EventEmitter);
module.exports = StatsMessage;
function StatsMessage() {
    // call the super constructor to initialize `this`
    EventEmitter.call(this);
@ -33,8 +38,4 @@ StatsMessage.prototype.getBadgeNumber = function(userId){
        var data = {userId: userId, badge: result};
        self.emit(MODEL_EVENTS.OK, data);
    });
};
// This class inherits from EventEmitter and expose class
util.inherits(StatsMessage, EventEmitter);
module.exports = StatsMessage;
};

+ 15 - 1
src/doctor/repository/patient.repo.js

@ -1,5 +1,19 @@
/**
 * 患者数据。
 *
 * author: Sand
 * since: 2016/11/18
 */
"use strict";
var wlyyDb = require('./database/wlyy.db');
exports.isPatientCode = function (code, handler) {
    var sql = "select count(1) from wlyy_patient where code = ?";
    wlyyDb.execQuery({
        "sql": sql,
        "args": [code],
        "handler": handler
    });
};

+ 7 - 6
src/doctor/repository/stats.msg.repo.js

@ -13,6 +13,8 @@ var log = require('../util/log');
var wlyyRepo = require("./database/wlyy.db.js");
var imRepo = require("./database/im.db.js");
var WLYY_ENPOINTS = require('../include/wlyy.endpoints').WLYY_ENPOINTS;
//--------------------About all chats--------------------
/**
 * 所有聊天列表。
@ -199,10 +201,10 @@ exports.getAppMsgAmount = function (userId, handler) {
            }
            var options = {
                hostname: config.wlyyServerConfig.hostname,
                hostname: config.wlyyServerConfig.host,
                port: config.wlyyServerConfig.port,
                path: config.wlyyServerConfig.path,
                method: config.wlyyServerConfig.method,
                path: WLYY_ENPOINTS.Doctor.MessageCount.Path,
                method: WLYY_ENPOINTS.Doctor.MessageCount.Method,
                headers: {
                    'userAgent': '{"token":"' + result[0].token + '","uid":"' + userId + '","imei":"' + result[0].imei + '"}'
                }
@ -210,17 +212,16 @@ exports.getAppMsgAmount = function (userId, handler) {
            var req = http.request(options, function (res) {
                res.setEncoding('utf8');
                log.info('请求家庭医生平台: http://', options.hostname + ":" + options.port + options.path);
                res.on('data', function (chunk) {
                    log.info('请求家庭医生平台: ', options.hostname + ":" + options.port + options.path);
                    log.info('家庭医生平台返回: ', chunk);
                    handler(null, JSON.parse(chunk));
                });
            });
            req.on('error', function (e) {
                log.error('家庭医生平台接口调用出错: ', e.message);
                handler(e, null);
            });

+ 10 - 5
src/doctor/resources/config/config.dev.js

@ -34,10 +34,14 @@ var geTuiAppStoreCfg = {
// 三师后台
var wlyyServerConfig = {
    hostname: '172.19.103.87',
    port: 9092,
    path: '/wlyy/doctor/message/amount',
    method: 'POST'
    host: '172.19.103.87',
    port: 9092
};
// 透传服务
var transServerConfig = {
    host: '172.19.103.76',
    port: 8000
};
exports.app = 'IM.Server';
@ -52,4 +56,5 @@ exports.imDbConfig = imDbConfig;
exports.geTuiConfig = geTuiConfig;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.wlyyServerConfig = wlyyServerConfig;
exports.wlyyServerConfig = wlyyServerConfig;
exports.transServerConfig = transServerConfig;

+ 10 - 5
src/doctor/resources/config/config.prod.js

@ -34,10 +34,14 @@ var geTuiAppStoreCfg = {
// 三师后台
var wlyyServerConfig = {
    hostname: '172.19.103.87',
    port: 9090,
    path: '/wlyy/doctor/message/amount',
    method: 'POST'
    host: '172.19.103.87',
    port: 9090
};
// 透传服务
var transServerConfig = {
    host: '120.41.253.95',
    port: 3030
};
exports.app = 'im.server';
@ -52,4 +56,5 @@ exports.imDbConfig = imDbConfig;
exports.geTuiConfig = geTuiConfig;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.wlyyServerConfig = wlyyServerConfig;
exports.wlyyServerConfig = wlyyServerConfig;
exports.transServerConfig = transServerConfig;

+ 10 - 5
src/doctor/resources/config/config.test.js

@ -34,10 +34,14 @@ var geTuiAppStoreCfg = {
// 三师后台
var wlyyServerConfig = {
    hostname: '172.19.103.87',
    port: 9090,
    path: '/wlyy/doctor/message/amount',
    method: 'POST'
    host: '172.19.103.87',
    port: 9090
};
// 透传服务
var transServerConfig = {
    host: '172.19.103.76',
    port: 8000
};
exports.app = 'im.server';
@ -52,4 +56,5 @@ exports.imDbConfig = imDbConfig;
exports.geTuiConfig = geTuiConfig;
exports.geTuiAppStoreCfg = geTuiAppStoreCfg;
exports.wlyyServerConfig = wlyyServerConfig;
exports.wlyyServerConfig = wlyyServerConfig;
exports.transServerConfig = transServerConfig;

+ 44 - 0
test/doctor/models/patient.Test.js

@ -0,0 +1,44 @@
/**
 * 患者模型测试。
 *
 * author: Sand
 * since: 2016/11/18
 */
"use strict";
var assert = require('assert');
var Patient =  require('../../../src/doctor/models/patient');
describe('Patient class', function () {
    describe('Method: sendMessage', function () {
        describe('when send to patient', function () {
            it('should return success', function (done) {
                var patient = new Patient();
                patient.sendMessage({
                    startId: 102,
                    count: 1,
                    records: [
                        {
                            id: 102,
                            from: 'cd914c70-5b06-11e6-8344-fa163e8aee56',
                            to: 'shiliuP20160926001',
                            contentType: '1',
                            content: '您的血小板值偏低,平时有贫血症状吗?',
                            timestamp: new Date()
                        },
                        {
                            id: 100,
                            from: 'cd914c70-5b06-11e6-8344-fa163e8aee56',
                            to: 'shiliuP20160926001',
                            contentType: '1',
                            content: 'Hello',
                            timestamp: new Date()
                        }
                    ]});
                done();
            });
        });
    });
});