yun2win-即时通讯云数据服务器部署方案

数据服务器源码下载地址:https://github.com/yun2win/yun2win-sdk-server

即时通讯云后台由数据服务器和推送服务器组成,其中数据服务器由开发者从Github获得源码,自行部署,保证开发者对其 数据的绝对控制。验证系统使用了OAtuth2.0,对外接口是RESTful Api。如果您只是配置部署后台,请转至服务器部署

先从Github下载源码,目前后台源码是nodejs版本, 可以使用Webstorm、Visual Studio或其它IDE打开源码。

下面看看源码结构

复制

    +
    //这里所有业务代码 | -- app //业务核心代码 | -- core //实体,可以持久化的 | -- model //使用的一些工具模块,目前有AES加密库,DB操作库,邮件操作库,汉字拼音库 | -- plugins //用提供给router的入口,目前已经慢慢由Core的代码代替 | -- service //附件存储临时位置,开发者可以另行定义,后面会讲到 | -- atts //路由,所有RESTful Api的入口都是这里实现 | -- router //一些基础的测试 | -- test //放一些静态文件 | -- public //主要是404和error时的展示模板 | -- views | -- app.js //启动入口,使用node server.js启动本程序 | -- server.js 

实体结构请看下图:

简单介绍一下各类的意义

  • User。用户类
  • Users。User的集合,管理User的生命周期
  • UserConversation。用户会话类,目前支持单聊&群聊类型
  • UserConversations。UserConversation的集合,管理其的生命周期
  • UserSession。群组类,即是对Session的收藏
  • UserSessions。UserSession的集合,管理其的生命周期
  • Contact。联系人类。
  • Contacts。Contact的集合,管理其的生命周期
  • Session。会话类,所有会话,包括单聊,群聊都以此为单位
  • Sessions。Session的集合,管理其的生命周期
  • SessionMember。会话成员类,即是所有参与此会话的成员
  • SessionMembers。SessionMember的集合,管理其的生命周期
  • Message。消息类,聊天产生的信息,支持各种类型
  • Messages。Message的集合,管理其的生命周期
以上类都带有 createdAtupdatedAt两个属性,分别是 加入时间最后修改时间

 

这里有两个核心类,分别是UserSession。用户包括联系人,群组及用户会话;Session包括成员和消息。 从UML图可以看出,其它类均围绕这两个类展开。

同步机制是保证客户端和服务器数据一致的重要机制,目前分五种集合:

  • 用户会话范围:用户
  • 联系人范围:用户
  • 群组范围:用户
  • SessionMember范围:Session
  • Message范围:Session

 

基本原理

同步机制的原理很简单,目前同步机制是以数据集合为单位的。每个数据集合同步流程为:

  1. 获得本地时间戳(如果没有,定为1900年1月1日 0时0分0秒)
  2. 以此时间戳访问业务服务器取得数据
  3. 将取得数据更新至本地(有三种情况:新增的,修改的,删除的)
  4. 取此数据最大的updatedAt时间为新的本地时间戳,保存这个时间戳.
  5. 判断数据是否同步完,如果没有,重回第1步

 

而服务端每更改数据,均要更新其updatedAt属性,如此,客户端便可以最少的流量,最少的请求获得完整数据。有了此同步机制, 各数据搜索也可以直接搜索本地数据,不用再浪费网络请求资源。

这里要特别指出,为了让各客户端能同步到被删除的指令,所有的数据删除并不是真正意义上的删除,而改其栏位isDelete,当其为 true时就表示他已经被删除了。

用户即是即时通讯的帐户体系,先看app/core/user.js的结构:

复制

    var User=function(users,entity){ this.users=users; this.entity=entity; this.id=entity.id; this.userConversations=new UserConversations(this); //用户会话集合 this.contacts=new Contacts(this); //联系人集合 //各项属性 for(var index in this.entity) this[index]=this.entity[index]; };

其中各项属性如下(参考app/model/user.js):

复制

    var Obj=db.define("User",{ email:db.String, name:db.String, password:db.String, role:db.String, phone:db.String, jobTitle:db.String, //职位 address:db.String, status:db.String, //用户状态,有效(active),封禁(inactive) avatarUrl:db.String, isDelete:db.Boolean //是否已删除 });

代码上app/core/user.js引用了app/model/user.js,前者负责实现User各项功能调用,后者只是持久定义。 本程序基本所有类都遵循代码逻辑处理和数据持久分开。

帐户对接

如您的业务系统已有帐户体系,您可以有两种方式来完成帐户对接

1、同步帐户体系

调用RESTful API将您业务系统的帐户体系全部注册一遍

2、改写用户接口

只要重写用户的以下几个方法即可:

  • 获取:app/core/users.js的方法get
  • 注册:app/core/users.js的方法register
  • 删除:app/core/users.js的方法delete
  • 保存:app/core/user.js的方法store

 

用户会话是此用户交流过的会话收藏列表,主要显示会话最新消息用户未读消息数。用户会话 应该是客户端访问最频繁的数据集合,为了增加服务负载,用户会话均读取入内存,将性能做到最优。

查看下其结构

复制

    var Obj=db.define("UserConversation",{ ownerId:db.String, //所属者Id,此时是用户Id targetId:db.String, name:db.String, type:db.String, //['p2p','group'] top:db.Boolean, //置顶 avatarUrl:db.String, isDelete:db.Boolean });

用户会话有以下几点需要注意的地方:

  • 所有用户会话均由服务端创建,客户端只需建立SessionSessionMmember,当发消息时会自动创建对应的会话
  • 用户会话的用户未读消息数并未持久化,故服务器重启后此值会重置0
  • 用户会话的updatedAt也是最新消息的updatedAt
  • 用户会话的targetId属性分两种情况:type=='p2p'时是对方UserIdtype=='group'时是SessionId
  • 用户会话的名称头像分两种情况:type=='p2p'时是对方的名称头像,非最新,需要客户端处理获得最新名称头像;type=='group'时是Session的名称头像,一直保持最新。

 

获得最新用户会话
复制

    UserConversations.prototype.getList=function(clientTime,cb){ //支持单参数访问 if(clientTime && !cb) { cb = clientTime; clientTime=new Date(1900,1,1); } var that=this; var lastConvrs=[]; var tobj=this; thenjs() .then(function(cont){ //先查看是否已载入过用户会话列表 if(that.list) return cont(null,that.list); var clientId=that.user.users.client.id; var userid=that.user.id; //没有就去取出最新有更新100条 //此处限定了100条是为了避免一次载入大量的用户会话使服务内存爆了。 UserConversationModel.getLatest(clientId,userid,100,function(error,objs){ if(that.list) return cont(null,that.list); that.list=[]; for(var i=0;i<objs.length;i++){ that.list.push(new="" userconversation(that,objs[i]));="" }="" cont(null,that.list);="" });="" })="" 找出一段时间(配置里默认设定为1小时)内有更新的会话="" .then(function(cont){="" var="" timeslip="new" date();="" timeslip.sethours(timeslip.gethours()-config.session.userconvrkeepalive);="" tobj.timeslip="timeslip;" for(var="" i="0;i<that.list.length;i++){" obj="that.list[i];" if(obj.updatedat="">clientTime) lastConvrs.push(obj); } cont(); }) //更新每一个用户会话 .each(lastConvrs,function(cont,uc){ if(uc.updatedAt>tobj.timeslip || !uc.lastMessage) return uc.refresh(cont); cont(); }) //排序返回 .then(function(cont,list){ lastConvrs.sort(function(a,b

转载于:https://www.cnblogs.com/yun2win/p/5761910.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值