<commit_before>---
layout: post
title: "飞享-即时聊天系统技术文档"
description: IM TECH
category: IM
---

本文档主要说明飞享即时聊天系统的技术相关文档,用于支持其他多端开发.说明系统的整体架构与后续技术`发展规划`,`技术愿景`,`未来商业化支持`


[![Build Status](https://travis-ci.org/comsince/universe_push.svg?branch=master)](https://travis-ci.org/comsince/universe_push)
[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/comsince/universe_push/blob/master/LICENCE)
[![Gitee stars](https://gitee.com/comsince/universe_push/badge/star.svg?theme=white)](https://gitee.com/comsince/universe_push)
[![GitHub stars](https://img.shields.io/github/stars/comsince/universe_push?style=social)](https://github.com/comsince/universe_push)

# 概述
飞享是一个即时聊天系统整体解决方案,更像一个开箱即用的即时通讯产品化解决方案.在设计之初,尽量遵照平台原生开发的要求进行,因为我们始终觉得原生的体验是达到一个优秀即时通讯的基本要求.在对客户端,服务端设计的过程中,尽量采用业界通用的方案进行.不用过于依赖某项技术,因为我们任何只有合适的技术用在合适的系统上才能发挥它固有的价值.

初衷开始这个项目只是对即时通讯的喜爱,慢慢不断的发展成为一个即时通讯类产品,在功能的不断迭代中,需要我们停下脚本思考一些问题.更希望这个一个技术解决方案,而不是基于某种语言或者框架的解决方案.也是服务端通信框架是基于`t-io`(基于AIO的网络编程框架,提供便捷的API,方便管理,快速使用),或者是基于`Netty`(基于NIO的异步网络编程框架).也是服务端编程语言是基于`Java`或者是基于`Go`.技术本身是为了解决实际问题,不应该是限制具体某个领域的发展.在编写客户端应用时,可以支持`Android`,也可以支持`iOS`,可以支持`Web`.支持我们遵循我们设计的交互协议规范,这些都可以迎刃而解,不管你是采用Android或者iOS原生开发,还是跨平台开发,使用Js框架Vue,React.


# 系统架构

系统架构在以后更多的是解决用户不断增多进而导致的,硬件支持,软件支持.更多的用户带来的挑战包括不断增长的数据,需要不断优化的用户体验.功能的迭代带来系统复杂度不断增大,给软件架构带来更多的挑战.所以基于我们现在的简单分布式架构,解决小部分用户使用尚可,后续需要考虑更多的用户,更优的用户体验,因此需要不断的优化软件架构

**NOTE:** 如下为简要的系统部署图

![image](/images/im/push-universe-deploy.png)


# 系统流程图

![image](/images/im/push-universe-flow.png)

重点关注核心要点:`登录实现`,`消息不丢失设计`

## 登录设计
系统登录是进行用户管理的关键,现行设计采用`手机号`+`验证码`的方式进行,登录的目地是生成会话,以支持同一帐号不同设备登录的功能

### 用户token生成
**NOTE:** 每一个用户Id登录不同设备,采用不同的cid,即是采用uid(用户id)+cid(设备唯一id)生成session,token中间分隔符为`|`

#### token规则

usertoken | session secret | db secret

#### usertoken规则

testim | 时间戳 | 用户名

* 核心代码

```java
    public static String getToken(String username) {
        String signKey = KEY + "|" + (System.currentTimeMillis()) + "|" + username;
        try {
            return DES.encryptDES(signKey);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
```


* 返回的token是经过AES加密然后Base64编码

### 客户端接入方式

**NOTE:** 用户登录成功后,会成功获取到上面生成的token,例如web端在获取到这个`token`保存在浏览器的`localstorage`里面.这个toekn将作为后续发送验证请求的关键.登录成功后要发送`connect`信令进行链接验证,关于信令的传输将会在下面介绍

![image](/images/im/login.png)

### 解密分离token

上面已经知道token是三部分加密组成,因此这里需要解密token,得到如下三部分内容
* usertoken
* session secret
* db secret

### 生成密码

**NOTE:** 以下是发送`connect`信令携带的消息体

```js
{
    userName: LocalStore.getUserId(), //用户id
    password: <PASSWORD>, //生成的用户密码
    clientIdentifier: localStorage.getItem(KEY_VUE_DEVICE_ID) //当前用户登录设备唯一id
}
```

### 生成规则

password 为 usertoken使用session secret经过AES加密得出的.

### 服务端认证

客户端在传入上述的`connect`消息后,需要经过消息认证才算接入成功,每次用户会话都有一个session,利用session secret
对`password`字段进行AES解密,如果能够解密成功,则表示登录验证成功



# 系统接口文档

系统的接入方式多种多样,带来的挑战是需要支持多种接入方式.对于Android,ios需要基于TCP实现用户长链接,保证消息即时可达.因此需要设计私有协议,
对于web端,可以采用websocket协议,只需要在消息体中设计我们的消息格式即可.

## 私有二进制协议

```
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
+---------------+---------------+---------------+---------------+
|      magic(8) |   version(8)  |   signal(8)   |               |
+---------------+---------------+---------------+---------------+
|                          length(32)                           | 
+---------------+---------------+---------------+---------------+
|   subsignal(8)|       messageId(16)           |  paload data  :
+---------------+---------------+---------------+---------------+
:             payload data                                      |
+---------------+---------------+---------------+---------------+
```

**NOTE:** 参数说明如下

* __magic__ 魔数,用于标记消息的起始位置
* __version__  协议版本号
* __signal__   主消息信令
* __length__   消息体长度
* __subsignal__ 消息子信令
* __messageId__ 消息ID，用于标记当前消息，可用作消息确认
* __payload data__ 消息体,长度由`length`定义

### 信令定义说明
<commit_msg>修改二进制协议定义<commit_after>---
layout: post
title: "飞享-即时聊天系统技术文档"
description: IM TECH
category: IM
---

本文档主要说明飞享即时聊天系统的技术相关文档,用于支持其他多端开发.说明系统的整体架构与后续技术`发展规划`,`技术愿景`,`未来商业化支持`


[![Build Status](https://travis-ci.org/comsince/universe_push.svg?branch=master)](https://travis-ci.org/comsince/universe_push)
[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/comsince/universe_push/blob/master/LICENCE)
[![Gitee stars](https://gitee.com/comsince/universe_push/badge/star.svg?theme=white)](https://gitee.com/comsince/universe_push)
[![GitHub stars](https://img.shields.io/github/stars/comsince/universe_push?style=social)](https://github.com/comsince/universe_push)

# 概述
飞享是一个即时聊天系统整体解决方案,更像一个开箱即用的即时通讯产品化解决方案.在设计之初,尽量遵照平台原生开发的要求进行,因为我们始终觉得原生的体验是达到一个优秀即时通讯的基本要求.在对客户端,服务端设计的过程中,尽量采用业界通用的方案进行.不用过于依赖某项技术,因为我们任何只有合适的技术用在合适的系统上才能发挥它固有的价值.

初衷开始这个项目只是对即时通讯的喜爱,慢慢不断的发展成为一个即时通讯类产品,在功能的不断迭代中,需要我们停下脚本思考一些问题.更希望这个一个技术解决方案,而不是基于某种语言或者框架的解决方案.也是服务端通信框架是基于`t-io`(基于AIO的网络编程框架,提供便捷的API,方便管理,快速使用),或者是基于`Netty`(基于NIO的异步网络编程框架).也是服务端编程语言是基于`Java`或者是基于`Go`.技术本身是为了解决实际问题,不应该是限制具体某个领域的发展.在编写客户端应用时,可以支持`Android`,也可以支持`iOS`,可以支持`Web`.支持我们遵循我们设计的交互协议规范,这些都可以迎刃而解,不管你是采用Android或者iOS原生开发,还是跨平台开发,使用Js框架Vue,React.


# 系统架构

系统架构在以后更多的是解决用户不断增多进而导致的,硬件支持,软件支持.更多的用户带来的挑战包括不断增长的数据,需要不断优化的用户体验.功能的迭代带来系统复杂度不断增大,给软件架构带来更多的挑战.所以基于我们现在的简单分布式架构,解决小部分用户使用尚可,后续需要考虑更多的用户,更优的用户体验,因此需要不断的优化软件架构

**NOTE:** 如下为简要的系统部署图

![image](/images/im/push-universe-deploy.png)


# 系统流程图

![image](/images/im/push-universe-flow.png)

重点关注核心要点:`登录实现`,`消息不丢失设计`

## 登录设计
系统登录是进行用户管理的关键,现行设计采用`手机号`+`验证码`的方式进行,登录的目地是生成会话,以支持同一帐号不同设备登录的功能

### 用户token生成
**NOTE:** 每一个用户Id登录不同设备,采用不同的cid,即是采用uid(用户id)+cid(设备唯一id)生成session,token中间分隔符为`|`

#### token规则

usertoken | session secret | db secret

#### usertoken规则

testim | 时间戳 | 用户名

* 核心代码

```java
    public static String getToken(String username) {
        String signKey = KEY + "|" + (System.currentTimeMillis()) + "|" + username;
        try {
            return DES.encryptDES(signKey);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
```


* 返回的token是经过AES加密然后Base64编码

### 客户端接入方式

**NOTE:** 用户登录成功后,会成功获取到上面生成的token,例如web端在获取到这个`token`保存在浏览器的`localstorage`里面.这个toekn将作为后续发送验证请求的关键.登录成功后要发送`connect`信令进行链接验证,关于信令的传输将会在下面介绍

![image](/images/im/login.png)

### 解密分离token

上面已经知道token是三部分加密组成,因此这里需要解密token,得到如下三部分内容
* usertoken
* session secret
* db secret

### 生成密码

**NOTE:** 以下是发送`connect`信令携带的消息体

```js
{
    userName: LocalStore.getUserId(), //用户id
    password: <PASSWORD>, //生成的用户密码
    clientIdentifier: localStorage.getItem(KEY_VUE_DEVICE_ID) //当前用户登录设备唯一id
}
```

### 生成规则

password 为 usertoken使用session secret经过AES加密得出的.

### 服务端认证

客户端在传入上述的`connect`消息后,需要经过消息认证才算接入成功,每次用户会话都有一个session,利用session secret
对`password`字段进行AES解密,如果能够解密成功,则表示登录验证成功



# 系统接口文档

系统的接入方式多种多样,带来的挑战是需要支持多种接入方式.对于Android,ios需要基于TCP实现用户长链接,保证消息即时可达.因此需要设计私有协议,
对于web端,可以采用websocket协议,只需要在消息体中设计我们的消息格式即可.

## 私有二进制协议

```
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
+---------------+---------------+---------------+---------------+
|      magic(8) |   version(8)  |   signal(8)   |               |
+---------------+---------------+---------------+---------------+
|                          length(32)                           | 
+---------------+---------------+---------------+---------------+
|   subsignal(8)|       messageId(16)           |  paload data  :
+---------------+---------------+---------------+---------------+
:             payload data(length)                              :
+---------------+---------------+---------------+---------------+
```

**NOTE:** 参数说明如下

* __magic__ 魔数,用于标记消息的起始位置
* __version__  协议版本号
* __signal__   主消息信令
* __length__   消息体长度
* __subsignal__ 消息子信令
* __messageId__ 消息ID，用于标记当前消息，可用作消息确认
* __payload data__ 消息体,长度由`length`定义

### 信令定义说明

{'fraction_non_alphanumeric': 0.20248352762290928, 'fraction_numerical': 0.010897110998479472, 'mean_word_length': 3.1872679045092838, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 16, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 9, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4255266', 'n_tokens_mistral': 4497, 'n_tokens_neox': 5075, 'n_words': 338}