Browse Source

Merge branch 'feature-refactor' of https://git.oschina.net/iceblur/im.doctor into feature-refactor

Sand 8 years ago
parent
commit
69ca594e19

+ 4 - 0
readme.md

@ -87,6 +87,10 @@ IM提供了开发SDK,一个JS脚本。客户端可以通过引用此脚本或
- REST API相关的放在endpoints
- 与页面相关的放在controllers
### 模型与控制层之间的交互
控制层提供两种类型的API:含有回调与不含回调。不含回调的API通过事件向外发送消息,用于与controller之间的交互。含回调的API通过回调与其他API交互,用于模型之间的交互。
### 消息发送
	实时与延时

+ 5 - 2
src/server/endpoints/users.endpoint.js

@ -23,6 +23,9 @@ const MODEL_EVENTS = require('../include/commons').MODEL_EVENTS;
 * 请求URL:
 *  /users/login?user_id=sand&token=0PFWlKmLBN9YzhCfFWVgYA&client_id=H6FYbDejks6VjMmW3uH7V6&platform=0
 *
 * 返回值:
 *  登录后的token.
 *
 * 参数说明:
 *  user_id:用户ID
 *  token:个推的token
@ -51,8 +54,8 @@ router.get(APIv1.Users.Login, function (req, res) {
    }
    let users = new Users();
    users.login(userId, function (err, result) {
    users.login(userId, platform, token, clientId, function (err, result) {
        res.status(200).send(result);
    });
});

+ 11 - 14
src/server/include/commons.js

@ -31,11 +31,7 @@ exports.CONTENT_TYPE = {
    Article: 4,     // 文章信息
    GoTo: 5,        // 跳转信息
    SessionBegin: 6,// 咨询开始
    SessionEnd: 7,  // 咨询结束
    commaValues: function () {
        return "1,2,3,4,5,6,7";
    }
    SessionEnd: 7   // 咨询结束
};
/**
@ -43,7 +39,8 @@ exports.CONTENT_TYPE = {
 */
exports.PLATFORM = {
    iOS: 0,
    Android: 1
    Android: 1,
    Wechat: 10
};
/**
@ -88,19 +85,19 @@ exports.REDIS_KEY_REPLACER = REDIS_KEY_REPLACER;
exports.REDIS_KEYS = {
    Users: "users:",
    User: "users:" + REDIS_KEY_REPLACER,
    UserStatus: "users:" + REDIS_KEY_REPLACER + ":status",
    UsersSessions: "users:"+REDIS_KEY_REPLACER+":sessions",
    UserAppStatus: "users:" + REDIS_KEY_REPLACER + ":app_status",
    UserWechatStatus: "users:" + REDIS_KEY_REPLACER + ":wechat_status",
    Participants:"participants:"+REDIS_KEY_REPLACER,
    UserSessions: "users:" + REDIS_KEY_REPLACER + ":sessions",
    Sessions: "sessions:",
    Session: "sessions:" + REDIS_KEY_REPLACER,
    Messages: "sessions:" + REDIS_KEY_REPLACER + ":messages",
    MessagesTimestamp: "sessions:" + REDIS_KEY_REPLACER + ":messages_by_timestamp",
    Participants: "participants:" + REDIS_KEY_REPLACER,
    Topics: "sessions:" + REDIS_KEY_REPLACER + ":topics",
    Topic: "topics:" + REDIS_KEY_REPLACER
    Topic: "topics:" + REDIS_KEY_REPLACER,
    Messages: "sessions:" + REDIS_KEY_REPLACER + ":messages",
    MessagesByTimestamp: "sessions:" + REDIS_KEY_REPLACER + ":messages_by_timestamp"
};
exports.STICK_NUM = 9000000000000;

+ 1 - 1
src/server/models/messages/messages.js

@ -72,7 +72,7 @@ class Messages extends RedisModel {
    saveMessageForRedis(message_id,sessionId,message){
        let message_key = super.makeRedisKey(RedisKey.Messages,sessionId);
        let message_timestamp_key = super.makeRedisKey(RedisKey.MessagesTimestamp,sessionId);
        let message_timestamp_key = super.makeRedisKey(RedisKey.MessagesByTimestamp,sessionId);
        redis.hsetAsync(message_key, message_id, JSON.stringify(message)).then(function (res) {
            log.info("success save redis message by session :"+sessionId);
            //保存message_timestamp_key redis

+ 1 - 1
src/server/models/sessions/participants.js

@ -90,7 +90,7 @@ class Participants extends RedisModel {
    createParticipantsToRedis(session_id,users,createDate,handler){
        let participants_key =  super.makeRedisKey(RedisKey.Participants,session_id);
        for(var j in users){
            let user_session_key =  super.makeRedisKey(RedisKey.UsersSessions,users[j]);
            let user_session_key =  super.makeRedisKey(RedisKey.UserSessions,users[j]);
            redis.zaddAsync(participants_key, createDate.getTime(),users[j]).then(function(res){
                    return  redis.zaddAsync(user_session_key,createDate.getTime(),session_id);
              }

+ 7 - 11
src/server/models/sessions/sessions.js

@ -46,7 +46,7 @@ class Sessions extends RedisModel {
     * @param userId
     */
    getUserSessions(userId,page,pagesize){
        let user_session_key =  super.makeRedisKey(RedisKeys.UsersSessions,userId);
        let user_session_key =  super.makeRedisKey(RedisKeys.UserSessions,userId);
        let self = this;
        let _super = super.makeRedisKey;
        if(page >0){
@ -86,7 +86,7 @@ class Sessions extends RedisModel {
             * @param restimestamp 当前会话当前用户的最后一次时间搓
             */
            function callamount(res,j,_len,session,restimestamp){
                let message_time_key = _super(RedisKeys.MessagesTimestamp,session);
                let message_time_key = _super(RedisKeys.MessagesByTimestamp,session);
                redis.zrangebyscoreAsync(message_time_key,restimestamp,(new Date().getTime())).then(function(messagetimelist){
                    res.sessionId = session;
                    res.message = messagetimelist.length;
@ -122,7 +122,7 @@ class Sessions extends RedisModel {
     */
    getSessionMessages(sessionId,user,page,pagesize){
        let self = this;
        let message_timestamp_key = super.makeRedisKey(RedisKeys.MessagesTimestamp,sessionId);
        let message_timestamp_key = super.makeRedisKey(RedisKeys.MessagesByTimestamp,sessionId);
        let message_key = super.makeRedisKey(RedisKeys.Messages,sessionId);
        let participants_key = super.makeRedisKey(RedisKeys.Participants,sessionId);
        //超过最大限制后从mysql获取数据
@ -175,13 +175,9 @@ class Sessions extends RedisModel {
    /**
     * 更新最后一条消息
     * @param session_key rediskey
     * @param create_date 创建时间
     * @param last_content 最后一条消息内容
     * @param last_content_type 消息类型
     * @param type 会话类型
     * @param sender 发送者ID
     * @param sendername 发送者名字
     * @param session_type
     * @param name 议题名称
     * @param message
     * @returns {*}
     */
    updateLastContent(session_key,session_type,name,message){
@ -290,7 +286,7 @@ class Sessions extends RedisModel {
     *置顶操作
     */
    stickSession(sessionId,user){
        let user_session_key = super.makeRedisKey(RedisKeys.UsersSessions,user);
        let user_session_key = super.makeRedisKey(RedisKeys.UserSessions,user);
        let self = this;
        //取出最大的session
        redis.zrevrangeAsync(user_session_key,0,0).then(function(res){
@ -324,7 +320,7 @@ class Sessions extends RedisModel {
     *取消置顶操作
     */
    cancelStickSession(sessionId,user){
        let user_session_key = super.makeRedisKey(RedisKeys.UsersSessions,user);
        let user_session_key = super.makeRedisKey(RedisKeys.UserSessions,user);
        let participants_key = super.makeRedisKey(RedisKeys.Participants,sessionId);
        let self = this;
        redis.zscoreAsync(participants_key,user).then(function(res){

+ 59 - 5
src/server/models/user/users.js

@ -6,16 +6,19 @@
 */
"use strict";
const RedisKeys = require('../../include/commons').REDIS_KEYS;
const REDIS_KEYS = require('../../include/commons').REDIS_KEYS;
const PLATFORMS = require('../../include/commons').PLATFORM;
let RedisModel = require('../redis.model');
let Doctor = require('./doctor');
let Patient = require('./patient');
let Sessions = require('../sessions/sessions');
let ImDb = require('../../repository/mysql/db/im.db');
let DoctorRepo = require('../../repository/mysql/doctor.repo');
let PatientRepo = require('../../repository/mysql/patient.repo');
let AppStatusRepo = require('../../repository/mysql/app.status.repo');
let ModelUtil = require('../../util/model.util');
let RedisClient = require('../../repository/redis/redis.client');
let redisConn = RedisClient.redisClient().connection;
@ -26,7 +29,7 @@ class Users extends RedisModel {
    constructor() {
        super();
        this._key = RedisKeys.Users;
        this._key = REDIS_KEYS.Users;
    }
    /**
@ -73,7 +76,7 @@ class Users extends RedisModel {
        async.waterfall([
            // get from redis
            function (callback) {
                let userStatusKey = self.makeRedisKey(RedisKeys.UserStatus, userId);
                let userStatusKey = self.makeRedisKey(REDIS_KEYS.UserStatus, userId);
                redisConn.hgetallAsync(userStatusKey).then(function (res) {
                   if(res === null){
                       callback(null);  // get from mysql
@ -134,11 +137,62 @@ class Users extends RedisModel {
    /**
     * 用户登录。
     *
     * 用户登录时会加载与之相关的会话列表,会话消息,用户自身信息:App状态与微信状态。
     *
     * @param userId
     * @param outCallback
     * @param platform
     * @param token
     * @param clientId
     *
     * @return 用户token
     */
    login(userId, outCallback){
    login(userId, platform, token, clientId){
        let self = this;
        let loginFromApp = platform === PLATFORMS.Wechat;
        let usersKey = REDIS_KEYS.Users;
        let userKey = self.makeRedisKey(REDIS_KEYS.User, userId);
        let userStatusKey = self.makeRedisKey(loginFromApp ? REDIS_KEYS.UserWechatStatus : REDIS_KEYS.UserWechatStatus, userId);
        let lastLoginTime = new Date();
        async.waterfall([
            // get user info
            function (callback) {
                self.getUser(userId, function (err, userInfo) {
                    if(userInfo === null){
                        ModelUtil.emitDataNotFound(self, 'User not exists.');
                        return;
                    }
                    callback(null, userInfo);
                })
            },
            // save user info and app status/wechat status
            function (userInfo, callback) {
                let multi = redisConn.multi()
                    .zadd(usersKey, lastLoginTime.getMilliseconds(), userId)
                    .hmset(userKey, 'avatar', userInfo.avatar, 'birthdate', userInfo.birthdate,
                        'name', userInfo.name, 'role', loginFromApp ? 'doctor' : 'patient');
                if(loginFromApp){
                    // app status
                    multi = multi.hmset(userStatusKey, 'platform', platform, 'app_in_bg', false, 'client_id', clientId,
                        'token', token, 'last_login_time', lastLoginTime);
                } else {
                    // wechat status
                    multi = multi.hmset(userKey, 'open_id', userInfo.open_id);
                }
                multi.execAsnyc().then(function (res) {
                        callback(null);
                    });
            },
            // load sessions
            function (callback) {
                /*let sessions = new Sessions();
                sessions.getUserSessionsFromMysql();*/
            }
        ]);
        DoctorRepo.deleteToken(token, function (err, result) {
            if (err) {
                ModelUtil.emitDbError(self.eventEmitter, 'Error occurs when user login and delete token', err);

+ 20 - 9
src/server/resources/schema/ichat_schema.1.2.8.sql

@ -8,6 +8,9 @@ SET FOREIGN_KEY_CHECKS=0;
/* Drop Tables */
DROP TABLE IF EXISTS `app_status` CASCADE
;
DROP TABLE IF EXISTS `topics` CASCADE
;
@ -26,7 +29,7 @@ DROP TABLE IF EXISTS `participants` CASCADE
DROP TABLE IF EXISTS `sessions` CASCADE
;
DROP TABLE IF EXISTS `app_status` CASCADE
DROP TABLE IF EXISTS `sticky_sessions` CASCADE
;
DROP TABLE IF EXISTS `wechat_access_tokens` CASCADE
@ -34,6 +37,17 @@ DROP TABLE IF EXISTS `wechat_access_tokens` CASCADE
/* Create Tables */
CREATE TABLE `app_status`
(
	`user_id` VARCHAR(50) NOT NULL COMMENT '用户ID',
	`platform` TINYINT COMMENT '平台,0为iOS,1为安卓',
	`token` VARCHAR(100) COMMENT '个推Token',
	`client_id` VARCHAR(100) COMMENT '客户端ID',
	`app_in_bg` TINYINT COMMENT 'App是否处于后台状态',
	`last_login_time` TIMESTAMP(0) COMMENT '最后登录 时间',
	CONSTRAINT `PK_user_status` PRIMARY KEY (`user_id`)
) COMMENT='app端状态'
CREATE TABLE `topics`
(
	`id` INTEGER NOT NULL COMMENT 'ID',
@ -106,16 +120,13 @@ CREATE TABLE `sessions`
) COMMENT='会话'
;
CREATE TABLE `app_status`
CREATE TABLE `sticky_sessions`
(
	`user_id` VARCHAR(50) NOT NULL COMMENT '用户ID',
	`platform` TINYINT COMMENT '平台,0为iOS,1为安卓',
	`token` VARCHAR(100) COMMENT '个推Token',
	`client_id` VARCHAR(100) COMMENT '客户端ID',
	`app_in_bg` TINYINT COMMENT 'App是否处于后台状态',
	`last_login_time` TIMESTAMP(0) COMMENT '最后登录 时间',
	CONSTRAINT `PK_user_status` PRIMARY KEY (`user_id`)
) COMMENT='app端状态'
	`session_id` VARCHAR(50) NOT NULL COMMENT '会话ID',
	`score` NUMERIC(15,0) COMMENT '置顶分值',
	CONSTRAINT `PK_sticky_sessions` PRIMARY KEY (`user_id`,`session_id`)
) COMMENT='置顶会话'
;
CREATE TABLE `wechat_access_tokens`

+ 8 - 8
src/server/resources/schema/temp.sql

@ -1,6 +1,6 @@
/* ---------------------------------------------------- */
/*  Generated by Enterprise Architect Version 12.0 		*/
/*  Created On : 15-Dec-2016 10:44:54 AM 				*/
/*  Created On : 19-12月-2016 11:01:00 				*/
/*  DBMS       : MySql 						*/
/* ---------------------------------------------------- */
@ -8,18 +8,18 @@ SET FOREIGN_KEY_CHECKS=0
/* Drop Tables */
DROP TABLE IF EXISTS `wechat_access_tokens` CASCADE
DROP TABLE IF EXISTS `sticky_sessions` CASCADE
;
/* Create Tables */
CREATE TABLE `wechat_access_tokens`
CREATE TABLE `sticky_sessions`
(
	`access_token` VARCHAR(50) NOT NULL COMMENT '访问token',
	`expiry_date` TIMESTAMP(0) COMMENT '过期时间',
	`create_time` TIMESTAMP(0) COMMENT '数据创建时间',
	CONSTRAINT `PK_wechat_access_tokens` PRIMARY KEY (`access_token`)
) COMMENT='微信接口调用所需要token'
	`user_id` VARCHAR(50) NOT NULL COMMENT '用户ID',
	`session_id` VARCHAR(50) NOT NULL COMMENT '会话ID',
	`score` NUMERIC(15,0) COMMENT '置顶分值',
	CONSTRAINT `PK_sticky_sessions` PRIMARY KEY (`user_id`,`session_id`)
) COMMENT='置顶会话'
;
SET FOREIGN_KEY_CHECKS=1