「实战」搭建完整的IM(即时通信)应用(1)

介绍

即时通信应用服务,整套包含服务端管理端客户端javascript

预计3篇分享:此次是第一篇,项目的总体介绍和实体关系的梳理前端

现已部署上线,客户端管理端,欢迎体验vue

能够注册客户端帐号,也可使用初始默认帐号,现有初始帐号说明:java

帐号 密码 说明
admin 123456 管理端帐号
user 123456 客户端普通用户帐号
muteuser 123456 客户端被禁言用户帐号
disabled 123456 客户端被封禁用户帐号
member1 123456 客户端普通用户帐号
member2 123456 客户端普通用户帐号
... 123456 客户端普通用户帐号
member30 123456 客户端普通用户帐号

<img width="300" src="https://i.loli.net/2020/07/15/fO2naUmPluYRsBd.png">node

功能简介

  1. 注册,登陆,我的、群组聊天,我的信息编辑等基础功能
  2. 申请添加好友和申请入群
  3. 表情,图片,视频,定位信息支持
  4. 聊天会话列表记录
  5. 消息记录(微信的消息记录真实一言难尽)
  6. 支持多点同时登陆
  7. 百度 UNIT 机器人自动回复(todo)
  8. 管理端,进行角色和权限的管理,群状态管理(我也当一回马化腾)

需求简介

移动互联网发展至今,以微信为首的即时通信服务已经融入了咱们生活中的各个角落,在公司的一些业务中也扮演着重要的角色,对于即时通信咱们公司原来是使用的环信的服务,可是有不少定制化的需求没法实现,因此后来决定内部开发一个知足定制化需求的即时通信微服务。mysql

使用socket.io框架是由于当时后端缺人,加上看了一些例子后以为使用起来真的很方便,并且全平台支持,因此这个微服务就在前端团队进行落地实践,目前效果还不错。git

社区目前这方面的内容比较少或者太简陋(只有一个公共的聊天室这种)。另外就是在业务开发过程当中被 PM 搞得很难受,因此想脱离一些特有的业务上的东西,实现一个功能简单五脏俱全的不掺杂公司业务的 IM 应用,包含服务端,管理端和客户端。客户端的模仿对象是微信,由于我很熟悉,不用在产品上面思考太多,另外就是试用的人很熟悉,不须要太多的沟通成本。github

框架简介

要开发一套完整的即时通信服务,须要如下部分:web

  1. 服务端:用来实现基础的服务接口和数据持久化
  2. 客户端:完成登陆、聊天等基础功能,相似微信
  3. 管理端:管理群组、用户和角色权限

server

为企业级框架和应用而生

选用阿里的 egg.js 框架作支撑,看中的缘由是他们内部大规模的落地和安全方面作得比较好,没有选择 nest 的缘由是集成 socket.io 比较麻烦,ORM 选用 sequelize,数据库是 mysql ,以前一块儿使用过,上手难度小sql

admin

开箱即用的中台前端/设计解决方案

选择 Ant Design Pro 做为模板开发管理端,选用的缘由是我对 Vue 全家桶比较熟悉,想借着这个机会熟悉下整套 React 生态 的开发流程,感觉下目前国内两大开发框架的本质区别和异曲同工,Ant Design Pro 已经发布了好几年了,也的确给中小型企业带来效率的提高,也正好适合我这的需求。

client

🛠️ Vue.js 开发的标准工具

使用 @vue/cli 搭建 IM 服务的客户端,一个移动端的 H5 项目,UI 框架使用的有赞 vant,集成了个人开源组件vue-page-stack和黄老师的better-scroll,实现 IM 的基础功能

实体关系

做为一个前端工程师,大多数的平常工做是不须要思考实体关系的。可是,就个人实际体验来看,懂得实体关系能够帮助咱们更好的理解业务模型。而对产品和业务理解的提高对咱们的帮助是很是大的,能够在需求评审的时候发现不少不符合逻辑的地方(怎么又要吐槽产品经理了),这时候能提出来就会主动避免咱们在后续的过程当中进行反复开发,同时能够和产品侧的同窗造成比较良好的互动(而不是互怼)。下面简单罗列下比较重要的实体关系:

<img width="600" src="https://i.loli.net/2020/07/14/Zhz85V2ptOylDcj.png">

经过上图能够看到 user 是整个关系图中的核心,下面介绍下各个实体之间的关系:

  1. user 和 user_info(用户信息) 是一对一的关系
  2. user 和 role(角色)是多对多的关系
  3. role 和 right(权限)是多对多的关系
  4. user 和 apply(申请)是多对多的关系,申请都是涉及到两个 user(申请人和被申请人)
  5. user 和 group(群组)是多对多的关系
  6. group 和 conversation(会话) 是一对一的关系
  7. friend 和 conversation(会话) 是一对一的关系
  8. conversation 和 message(消息)是 1 对多的关系
  9. friend(好友关系) 和 user 没有直接关系,friend 由两个 user 肯定

下面详细介绍下会话、角色与权限:

会话

完成一个即时通信应用,须要考虑的第一个事情就是会话,就是咱们微信里面的对话窗口。思考会话和消息、用户、群组之间的关系花费了很多的精力,最终造成如下的基本关系:

  1. 2 个用户参与的聊天属于创建了 Friend 关系(互为好友)
  2. 多个用户参与的聊天组成了群组关系
  3. Friend 和会话之间的关系是 1 对 1 的关系,能够经过 Friend 找到此 Friend 的会话,也能够经过会话肯定 Friend
  4. 群组和会话之间的关系是 1 对 1 的关系,能够经过群组找到此群组的会话,也能够经过会话肯定群组
  5. 消息属于某个会话,能够根据会话查看对应的消息列表
  6. 保存消息的时候更新会话的激活时间,用户的会话列表根据激活时间排序,也就是最近的会话再最前面

也就是说,用户和会话没有直接的关系,只能经过用户对应的单聊和群聊去获取会话,这样作能够有如下的好处:

  1. 不管是单聊仍是群聊,链接上的用户只要 join 进对应的会话 room 里面就能够,消息也是在对应的 room 里面发布
  2. 不管是单聊仍是群聊,消息的保存和查询都比较简单,都是只针对这个会话
  3. 获取我的的会话列表也变得很简单,用户的会话列表经过查询用户『全部的 Friend 和群组』->『全部的会话』->『排序会话(根据激活时间)』,就能够获取

角色和权限

为了设计一个灵活、通用、方便的权限管理系统,本系统采用 RBAC(基于角色的访问控制)控制,来设计一个通用的『用户角色权限』平台,方便后期扩展。

RBAC

RBAC(基于角色的访问控制)是指用户经过角色与权限进行关联。即一个用户拥有若干角色,每个角色拥有若干权限(固然了,别把冲突的角色和权限配在一块儿)。这样,就构形成“用户—角色—权限”的受权模型。在这种模型中,用户与角色之间、角色与权限之间,通常是多对多的关系。

本系统默认的角色和权限

本系统默认有管理员、通常用户、禁言用户和封禁用户这几种角色,给不一样的角色分配不一样的权限,因此须要针对管理和发言等接口路由作一下统一的鉴权(经过中间件的方式)处理,具体方式和方法在后端项目中会详细说明。本系统暂时采用预先定义了角色和权限的方式,后续想要扩展的话能够编辑角色和权限。

管理员

没见过微信的管理端,可是能够想象一下,管理员能够配置用户的角色和权限,能够编辑群组的状态:

  1. 登陆的权限
  2. 群组状态的编辑
  3. 针对用户的角色和权限的编辑

普通用户

注册登陆后,能够正常的添加好友和加入群组,能够修改我的基础信息和处理申请

  1. 注册登陆
  2. 编辑我的基础信息
  3. 添加好友,申请入群
  4. 处理好友申请和入群申请
  5. 聊天

禁言用户

  1. 注册登陆
  2. 编辑我的基础信息
  3. 添加好友,申请入群
  4. 处理好友申请和入群申请

封禁用户

没法登陆

角色的组合

举个例子:如今有一个新版的我的中心须要上线测试,首先新建一个角色『测试我的中心』,再给这个角色分配对应的权限;而后给普通用户作个分组,选出一些人配置上这个角色,这样就能够进行测试了。

即时通信原理

下面说下即时通信服务的核心通信原理,和通常的 http 服务同样,有一个服务端和客户端进行通信,只不过详细的协议和处理方式不同。

WebSocket

因为历史缘由,如今主流的 http 协议是无状态协议(HTTP2 暂时应用不普遍),通常状况是由客户端主动发起请求,而后服务端去响应。那么为了实现服务端向客户端推送信息,就须要前端主动向后端去轮询,这种方式低效且容易出错,在以前咱们的管理端首页确实是这么作的(5s 一次)。

为了实现这种服务端主动推送信息的需求, HTML5 开始提供一种在单个 TCP 链接上进行全双工通信的协议,也就是 WebSocket。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,容许服务端主动向客户端推送数据。WebSocket 协议在 2008 年诞生,2011 年成为国际标准,目前绝大部分浏览器都已经支持了。

WebSocket 的用法至关简单:

var ws = new WebSocket("wss://echo.websocket.org");

ws.onopen = function(evt) {
  console.log("Connection open ...");
  ws.send("Hello WebSockets!");
};

ws.onmessage = function(evt) {
  console.log( "Received Message: " + evt.data);
  ws.close();
};

ws.onclose = function(evt) {
  console.log("Connection closed.");
};

有了 WebSocket 协议让服务端主动推送信息有了先进的武器,那么有没有什么方式能够兼容新旧浏览器呢?其实不少人想到了这点,答案就是socket.io

socket.io

socket.io进一步封装了WebSocket的接口,并且能够在旧版本浏览器中自主切换到使用轮询的方式进行通信(咱们使用者是不会感知的),造成了一套统一的接口,大大减轻了开发的负担。主要具备如下优势:

  1. 封装出了一套很是易用的接口,先后端统一,使用很是简单
  2. 全平台支持(原生和 H5,微信小程序中也有对应的实现)
  3. 自适应浏览器,在比较老的浏览器中主动切换使用轮询的方式,不须要咱们本身搞轮询

这是 socket.io 主页

最快,最可靠的即时通信引擎(FEATURING THE FASTEST AND MOST RELIABLE REAL-TIME ENGINE)

使用起来真的很简单:

var io = require('socket.io')(80);
var cfg = require('./config.json');
var tw = require('node-tweet-stream')(cfg);
tw.track('socket.io');
tw.track('javascript');
tw.on('tweet', function(tweet){
  io.emit('tweet', tweet);
});

总结

有了以上的基础,咱们就基本完成了开始写代码以前的准备:明确了这个应用的基础功能和实体之间的关系,也明确了基础的技术方案选型,划分了3个项目的各自任务。下面就开始完成 server 端吧

未完待续:下一篇介绍 server 端

相关文章
相关标签/搜索