# rabbit-im
**Repository Path**: smallkingfisher/rabbit-im
## Basic Information
- **Project Name**: rabbit-im
- **Description**: rabbit-im是一款开源聊天软件
- **Primary Language**: Unknown
- **License**: GPL-3.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2022-06-07
- **Last Updated**: 2024-01-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: Go语言
## README
## 开源im: rabbit-im
写一款类似**qq**这样的通讯工具,是一件颇有成就感的事情。
与实验性的im不同,rabbit-im是一个一开始就使用微服务理念设计的即时通讯工具,有利于在云原生生产环境大规模部署。 至于如何商业化,我尚未去想过这些,我不认为在即时通讯领域后来者还能拿下微信和qq的市场,时机不同了。 写im是因为这种产品的后端框架是比较全面的,很容易转化成其它形式的产品。 张一鸣在做今日头条和抖音之前,做过yy语音直播和安居客这样的产品。 王兴在做成美团之前,做过校园网,人人网等产品。 程序员想要崛起,可能要做很多产品且未必有任何成功的机会,总归要有一些自己的代表作品。
$\color{#222514}{-}\color{#222514}{-}\color{#222514}{-}\color{#222514}{-}\color{#4285f4}{T}\color{#ea4335}{a}\color{#fbbc05}{n}\color{#4285f4}{g}\color{#34a853}{s}\color{#ea4335}{h}\color{#4285f4}{u}\color{#fbbc05}{n}\color{#34a853}{c}\color{#ea4335}{a}\color{#fbbc05}{i}$
**说明:**
从代码上面看,因为开发投入的人力有限,测试机器也有限,为了更快的开发出第一版本,目前实现的方式不是微服务,但留出了微服务的接口。版本说明:
- v0.0.1 实现功能和可用性
- v0.0.2 优化系统架构
- v0.0.3 移动客户端适配
- v0.0.4 安全和加密
- v1.0.0-beta 优化数据编码、压缩,提升复杂网络下数据传输成功率
- v1.0.1-beta k8s 部署
- v1.1 Stable 提升数据库查询速度、减小消息延迟时间、事件不丢失、支撑2000万用户在线
### IM架构
#### rabbit-im 拆分为4个子系统:
- 信令系统
- IM业务系统
- 推送系统
- 存储系统
```mermaid
graph LR
系统拆分 --> 信令系统:用户注册/登录,用户信息查询,用户在线/离线统计;
系统拆分 --> IM业务系统:好友关系,群关系,消息推送,事件推送;
系统拆分 --> 推送系统:在线消息的推送,离线消息的推送;
系统拆分 --> 存储系统:mongodb集群,ceph集群分别负责消息和文件的存储和读取;
```
信令系统:
- 用户注册/登录/更新用户信息,维护用户在线状态
- 下行消息推送
IM业务:
- 好友添加、好友列表、好友信息查看
- 创建群、邀请进群、解散群、剔除群成员、禁言、撤回群成员消息
- 聊天消息收发
- 离线消息拉取
- 系统(新闻/广告)推送
- 业务分发
推送系统:
```mermaid
graph LR
推送系统 --> PushProxy代理用户的消息写入请求;
推送系统 --> Kafka消息队列;
推送系统 --> route路由到目标IM服务器;
```
存储系统:
- mongodb 集群
- ceph/minio/fastdfs存储集群
考虑性能问题,聊天消息按照冷热数据进行分离存储:
10天以内的数据,缓存在redis中
10~100天以内的数据存储在mysql中
100天以上的数据,按照时间戳分库分表(100天一个库)
图片存储缩略图、高清原图2种规格。客户端默认收到的是缩略图,点击后下载高清图
客户端定期(或缓存命中失败)从信令服务拉取好友在线状态,并缓存
**系统架构图:**

**部署方式:** k8s部署。
### 长连接、短连接
rabbit-im最终的用户包含pc用户和移动客户端用户(安卓、ios),因此设计之初将网络连接考虑进去,设计原则如下:
im的场景是集中性的(聊天的需求是突发,集中性的在某个时间段内聊天),因此在无聊天消息时只发送http短连接(3s间隔保活在线状态,服务端返回好友上下线状态),在有聊天消息时在2min之内长连接。
转发服务器用asmq(kafka/rabbit)实现,事件推送服务用websocket实现
### 1 编译方法
```shell
git clone git@gitee.com:jacky6666/rabbit-im.git
cd rabbit-im
go mod tidy
make all
# 清理
make clean
```
### 2 数据表
- 用户信息表
- 用户关系表
- 聊天消息表
**用户信息表 UserInfo**
```plantuml
@startjson
#highlight "uid"
#highlight "Friends"
#highlight "gids"
#highlight "joingids"
{
"uid": 1,
"username": "jack",
"nickname": "画笔",
"password": "123456",
"facetype": 0,
"customface": "pony",
"customfacefmt": "fmt",
"gender":0,
"age":18,
"height":175,
"birthday":"2023-1-1",
"signature":"生死看淡,不服就干",
"address":"shen zhen",
"telephonenumber":"13637110255",
"mail":"001@qq.com",
"registertime":"2023-1-1",
"remark":"",
"updatetime":"2023-1-1 12:00:00",
"teaminfo":"同事",
"Friends": [
{
"fid":666,
"markname":"阿红",
"teamname":"升值加新群"
},
{
"fid":652,
"markname":"阿燕",
"teamname":"升值加新群"
}
],
"gids": [
1239,
6411,
78956
],
"joingids":[
123,9981,6556
]
}
@endjson
```
**用户关系表 UserRelationship**
```plantuml
@startjson
{
"uidsubmit":123,
"uidgrantee":986,
"fixed":true,
"uidsmall":123,
"uidbig":986,
"user_smallteamname": "朋友",
"user_smallmarkname": "如霞",
"user_bigteamname": "学校",
"user_bigmarkname": "班主任",
"updatetime":"2023-1-1",
"remark":"备注"
}
@endjson
```
**聊天消息表 ChatMessages**
```plantuml
@startjson
{
"senderuid":123,
"reseiveduid":961,
"msgcontent": "晚上去吃火锅吗?",
"createtime":"2023-12-31",
"remark":""
}
@endjson
```
#### 为mongodb数据库创建超级管理员用户
```shell
> use admin
switched to db admin
> db.createUser(
... {
... user: "adminUser",
... pwd: "admin123",
... roles: [{role: "userAdminAnyDatabase",db:"admin"}]
... }
... )
Successfully added user: {
"user" : "adminUser",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
>
```
#### 为某个数据库单独创建普通用户
*user rabbit数据库,如果存在则切换到该数据库,如果不存在则创建*
*为rabbit数据库创建用户,账号为user123,密码为123456*
```shell
> use rabbit
> db.createUser({user:"user123",pwd:"123456",roles:[{role:"readWrite",db:"rabbit"},{role:"dbAdmin",db:"rabbit"},{role:"userAdmin",db:"rabbit"}]})
```
#### 测试mongodb数据库写入

### 3 回包格式
**说明:**
- 信息(控制)流:用户注册、用户登录、加好友、加群、退群、解散群、剔除群成员、禁言、撤回群成员消息、设置头像、设置邮箱、获取好友列表
- 消息(数据)流:专指聊天消息(文字、表情、语音、视频、图片、文件、链接分享)
**回包统一格式:**
```json
{
"restapi" : "",
"cmdbody" : {},
"msgbody": {}
}
```
| 字段 | 类型 | 说明 |
| ---- | ---- | ---- |
| restapi | String | 客户端所请求的rest api,例如"register"、"login"、"userlist"、"grouplist" |
| cmdbody | Object | 信息元素的内容,不同的 restapi 有不同的 cmdbody 格式,具体参见下文。 |
#### 信息流 CmdBody 说明:
> cmdbody 中填写的字段是命令内容。rabbit IM 支持一条消息中包括多种消息元素类别。
#### 消息流 MsgBody 说明:
> msgbody 中所填写字段是消息内容。rabbit IM 支持一条消息中包括多种消息元素类别,例如一条消息中既包括文本消息元素,还包括表情消息元素。因此 MsgBody 定义为 Array 格式,可按照需求加入多类消息元素。消息元素名称为 RIMMsgElement,消息元素 RIMMsgElement 组成 MsgBody 的示例请参见 消息内容 MsgBody 实例。
消息元素 RBTMsgElement 的格式统一为:
```json
{
"msgtype": "",
"message": {}
}
```
| 字段 | 类型 | 说明 |
| ---- | ---- | ---- |
| msgtype | String | 消息元素类别;目前支持的消息对象包括:RIMTextElem(文本消息)、RIMLocationElem(位置消息)、RIMFaceElem(表情消息)、RIMCustomElem(自定义消息)、RIMSoundElem(语音消息)、RIMImageElem(图像消息)、RIMFileElem(文件消息)、RIMVideoFileElem(视频消息) |
| message | Object | 消息元素的内容,不同的 msgtype 有不同的 message 格式,具体参见下文。 |
目前支持消息类别 MsgType 见下表:
| msgtype的值 | 类型 |
| ---- | ---- |
| RIMTextElem | 文本消息 |
| RIMLocationElem | 地理位置消息 |
| RIMFaceElem | 表情消息 |
| RIMCustomElem | 自定义消息,当接收方为 iOS 系统且应用处在后台时,此消息类型可携带除文本以外的字段到 APNs。一条组合消息中只能包含一个 RIMCustomElem 自定义消息元素。 |
| RIMSoundElem | 语音消息 |
| RIMImageElem | 图像消息 |
| RIMFileElem | 文件消息 |
| RIMVideoFileElem | 视频消息 |
### 4 api测试
**1 注册新用户:**
请求:
```shell
curl -X POST http://127.0.0.1:8082/register -d '{"username":"jack1234","password":"123456"}' --header "Content-Type: application/json"
```
返回:
```json
{
"restapi":"register",
"cmdbody":{
"uid":10079,
"username":"jack1234",
"password":"123456",
"facetype":0,
"customface":"",
"customfacefmt":0,
"gender":0,
"birthday":"2000-02-04T10:30:00+08:00",
"Remark":"",
"updatetime":"2022-06-13T00:23:40.320148698+08:00"
}
}
```
**2 用户登录**
请求:
```shell
curl -X POST http://127.0.0.1:8082/login/jack/123456
```
返回:
```json
{
"restapi":"login",
"cmdbody":{
"statuscode":0,
"errmsg":"",
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTUwNTQzMDIsImlhdCI6MTY1NTA1MDcwMiwibmFtZSI6ImdnIn0.iuKHepSPM_5HhALcY8-TZckbdOKYda1E-KQzCLZuy94"
}
}
```