feat: init

This commit is contained in:
tangtaoit 2023-05-21 17:37:50 +08:00
commit b10a32dc37
47 changed files with 13494 additions and 0 deletions

9
.dumirc.ts Normal file
View File

@ -0,0 +1,9 @@
import { defineConfig } from 'dumi';
export default defineConfig({
themeConfig: {
logo: '/logo.png',
name: '悟空IM',
footer: "Copyright © 2023 | Powered by 悟空IM"
},
});

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
node_modules
/dist
.dumi/tmp
.dumi/tmp-production
.DS_Store

4
.husky/commit-msg Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx commitlint --edit "${1}"

4
.husky/pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged

3
.prettierignore Normal file
View File

@ -0,0 +1,3 @@
.dumi/tmp
.dumi/tmp-production
*.yaml

14
.prettierrc.js Normal file
View File

@ -0,0 +1,14 @@
module.exports = {
printWidth: 80,
proseWrap: 'never',
singleQuote: true,
trailingComma: 'all',
overrides: [
{
files: '*.md',
options: {
proseWrap: 'preserve',
},
},
],
};

15
Dockerfile Normal file
View File

@ -0,0 +1,15 @@
FROM node:18.0.0 as builder
WORKDIR /app
RUN curl -o- -L https://yarnpkg.com/install.sh | bash
COPY package.json .
COPY yarn.lock .
# https://registry.npmjs.org/ https://registry.npm.taobao.org
# RUN yarn config set registry https://registry.npm.taobao.org -g
# RUN yarn config set disturl https://npm.taobao.org/dist
RUN yarn install
COPY . .
RUN yarn build
FROM nginx:latest
COPY --from=builder /app/dist /usr/share/nginx/html
CMD ["nginx","-g","daemon off;"]

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) tt@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

6
Makefile Normal file
View File

@ -0,0 +1,6 @@
build:
docker build -t wukongimdocs .
deploy:
docker build -t wukongimdocs .
docker tag wukongimdocs wukongim/wukongimdocs:latest
docker push wukongim/wukongimdocs:latest

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# WuKongIMDocs
A static site base on [dumi](https://d.umijs.org).
## Development
```bash
# install dependencies
$ yarn install
# start dev server
$ yarn start
# build docs
$ yarn run build
```
## LICENSE
MIT

BIN
WKJSSDK.xmind Normal file

Binary file not shown.

BIN
WKiOSSDK.xmind Normal file

Binary file not shown.

228
docs/api/channel.md Normal file
View File

@ -0,0 +1,228 @@
---
title: 频道
order: 200
---
# 频道
频道是**悟空 IM**里最重要的一个概念,如果还不知道什么是频道请查看[什么是频道?](/guide/initialize#频道)
## 创建或更新频道
创建一个频道,如果系统中存在则更新(`个人与个人聊天不需要创建频道,系统将自动创建`
> POST /channel
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID如果是群聊频道建议使用群聊ID
"channel_type": 2, // 频道的类型 1.个人频道 2.群聊频道(个人与个人聊天不需要创建频道,系统将自动创建)
"large": 0, // 是否是超大群0.否 1.是 一般建议500成员以上设置为超大群注意超大群不会维护最近会话数据。
"ban": 0, // 是否封禁此频道0.否 1.是 (被封后 任何人都不能发消息,包括创建者)
"subscribers": [uid1,uid2,...], // 订阅者集合
}
```
成功响应
```
http status为200
```
## 删除频道
删除一个频道(注意:如果配置了[datasource](/guide/datasource)记得不要返回删除了频道的数据,要不然重启又会恢复回来)
> /channel/delete
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID
"channel_type": 2 // 频道的类型 1.个人频道 2.群聊频道
}
```
成功响应
```
http status为200
```
## 添加订阅者
向一个已存在的频道内添加订阅者
> POST /channel/subscriber_add
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID
"channel_type": 2, // 频道的类型 1.个人频道 2.群聊频道
"reset": 0, // // 是否重置订阅者 0.不重置 1.重置),选择重置,则删除旧的订阅者,选择不重置则保留旧的订阅者
"subscribers": [uid1,uid2,...], // 订阅者集合
}
```
成功响应
```
http status为200
```
## 移除订阅者
向一个已存在的频道内移除订阅者
> POST /channel/subscriber_remove
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID
"channel_type": 2, // 频道的类型 1.个人频道 2.群聊频道
"subscribers": [uid1,uid2,...], // 订阅者集合
}
```
成功响应
```
http status为200
```
## 添加黑名单
将某个用户添加到频道黑名单内,在频道黑名单内的用户将不能在此频道发送消息,可以通过此接口实现,群拉黑群成员的功能
> POST /channel/blacklist_add
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID
"channel_type": 2, // 频道的类型 1.个人频道 2.群聊频道
"uids": [uid1,uid2,...], // 要拉黑的用户uid集合
}
```
成功响应
```
http status为200
```
## 移除黑名单
> POST /channel/blacklist_remove
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID
"channel_type": 2, // 频道的类型 1.个人频道 2.群聊频道
"uids": [uid1,uid2,...], // 用户uid集合
}
```
成功响应
```
http status为200
```
## 设置黑名单
设置黑名单(覆盖原来的黑名单数据)
> POST /channel/blacklist_set
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID
"channel_type": 2, // 频道的类型 1.个人频道 2.群聊频道
"uids": [uid1,uid2,...], // 用户uid集合
}
```
成功响应
```
http status为200
```
## 添加白名单
如果设置了白名单,则只允许白名单内的订阅者发送消息。可以通过白名单机制实现“群禁言功能”。
> POST /channel/whitelist_add
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID
"channel_type": 2, // 频道的类型 1.个人频道 2.群聊频道
"uids": [uid1,uid2,...], // 用户uid集合
}
```
成功响应
```
http status为200
```
## 移除白名单
将用户从频道白名单内移除
> /channel/whitelist_remove
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID
"channel_type": 2, // 频道的类型 1.个人频道 2.群聊频道
"uids": [uid1,uid2,...], // 用户uid集合
}
```
成功响应
```
http status为200
```
## 设置白名单
设置白名单(覆盖原来的白名单数据)
> POST /channel/whitelist_set
请求参数:
```json
{
"channel_id": "xxxx", // 频道的唯一ID
"channel_type": 2, // 频道的类型 1.个人频道 2.群聊频道
"uids": [uid1,uid2,...], // 用户uid集合
}
```
成功响应
```
http status为200
```

110
docs/api/conversation.md Normal file
View File

@ -0,0 +1,110 @@
---
title: 最近会话
order: 300
---
# 最近会话
如果不明白什么是最近会话,请查看[最近会话](/guide/initialize#最近会话)。
`默认最近会话是关闭的,如果需要开启最近会话,请在配置里配置 conversation.on=true`详情查看[完整配置](/guide/fullconfig)
## 同步最近会话
客户端离线后每次进来需要同步一次最近会话(包含离线的最新的消息)
> POST /conversation/sync
请求参数:
```json
{
"uid": "xxxx", // 当前登录用户uid
"version": 1234, // 当前客户端的会话最大版本号(从保存的结果里取最大的version如果本地没有数据则传0)
"last_msg_seqs": "xxx:2:123|xxx:1:3434", // 客户端所有频道会话的最后一条消息序列号拼接出来的同步串 格式: channelID:channelType:last_msg_seq|channelID:channelType:last_msg_seq
"msg_count": 20 // 每个会话获取最大的消息数量一般为app点进去第一屏的数据
}
```
成功响应
```json
[
{
"channel_id": "xxxx111", // 频道ID
"channel_type": 2, // 频道类型 1.单聊 2.群聊 3.客服
"unread": 1, // 消息未读数量
"timestamp": 1657615272, // 10位到秒的时间戳
"last_msg_seq": 0, // 最后一条消息的message_seq
"last_client_msg_no": "xxxx", // 最后一条消息的客户端消息编号
"version": 123, // 数据版本编号
"recents":[ // 最近N条消息
{
"header": { // 消息头
"no_persist": 0, // 是否不存储消息 0.存储 1.不存储
"red_dot": 1, // 是否显示红点计数0.不显示 1.显示
"sync_once": 0 // 是否是写扩散这里一般是0只有cmd消息才是1 cmd消息在这里也不可能查的到因为cmd消息不会存储到最近会话里
},
"setting": 0, // 消息设置 消息设置是一个 uint8的数字类型 为1个字节完全由第三方自定义 比如定义第8位为已读未读回执标记开启则为0000 0001 = 1
"message_id": 122323343445, // 消息全局唯一ID
"client_msg_no": "xxxxx", // 客户端定义的消息编号(一般为32位的uuid),可用此字段去重
"message_seq": 1, // 消息序列号 (频道唯一,有序递增)
"from_uid": "xxxx", // 发送者用户id
"channel_id": "xxxx", // 频道ID
"channel_type": 2, // 频道类型 1.个人频道 2.群频道
"timestamp": 1657611272, // 消息10位到秒的时间戳
"payload": "xxxx", // base64编码的消息内容
},
...
]
},
...
]
```
## 设置最近会话未读数量
设置某个频道的最近会话未读消息数量
> POST /conversations/setUnread
请求参数:
```json
{
"uid": "xxxx", // 当前登录用户uid
"channel_id": "xxxx", // 频道ID
"channel_type": 1, // 频道类型
"unread": 0 // 未读消息数量
}
```
成功响应
```
http status为200
```
## 删除最近会话
删除某个频道的最近会话
> POST /conversations/delete
请求参数:
```json
{
"uid": "xxxx", // 当前登录用户uid
"channel_id": "xxxx", // 频道ID
"channel_type": 1 // 频道类型
}
```
成功响应
```
http status为200
```

109
docs/api/datasource.md Normal file
View File

@ -0,0 +1,109 @@
---
title: Datasource
order: 500
---
# Datasource
数据源解决的问题主要是一些现有系统里已有群成员和一些其他数据,需要无缝对接到**悟空 IM**通讯里,那么就可以通过数据源的形式对接
`数据源只有在重启后第一次启动时才会加载,如果需要重新加载数据源,需要重启服务`
**悟空 IM**会调用 datasource 配置的 api 地址,通过 POST 的方式进行请求
请求数据格式如下:
```json
{
"cmd": "xxx", // 请求指令
"data": {} // 请求参数
}
```
详情如下:
### 获取订阅者(群成员)
当**悟空 IM**通讯端需要获取订阅者列表的时候就会调用此 cmd 进行获取
请求参数
```json
{
"cmd": "getSubscribers",
"data": {
"channel_id": "xxx", // 频道ID群ID
"channel_type": 2 // 默认为2 2表示群聊
}
}
```
返回结果
```json
[uid1,uid2,...] // 当前频道的成员用户id列表
```
### 获取黑名单
如果不允许频道成员内某个人收不到消息,可以返回黑名单
请求参数
```json
{
"cmd": "getBlacklist",
"data": {
"channel_id": "xxx", // 频道ID群ID
"channel_type": 1 // 频道类型 1.单聊 2.群聊
}
}
```
返回结果
```json
[uid1,uid2,...] // 黑明单成员用户id集合
```
### 获取白名单
如果只允许频道内某些人收到消息,则返回收到消息的成员用户 id 列表。
比如实现群禁言,那么可以返回群主和管理员的 uid这样其他群成员将无法发送消息只有群主和管理能发送消息
比如实现只有好友才能发送消息,那么返回用户的好友列表则不是好友将无法发送消息
请求参数
```json
{
"cmd": "getWhitelist",
"data": {
"channel_id": "xxx", // 频道ID群ID
"channel_type": 1 // 频道类型 1.单聊 2.群聊
}
}
```
返回结果
```json
[uid1,uid2,...] // 白名单成员用户id集合
```
### 获系统账号
系统账号不受黑名单白名单限制,而且系统账号不在某个频道内也可以发送消息,也就是对发送消息无如何限制
请求参数
```json
{
"cmd": "getSystemUIDs"
}
```
返回结果
```json
[uid1,uid2,...] // 系统账号用户id集合
```

75
docs/api/index.md Normal file
View File

@ -0,0 +1,75 @@
---
title: 基础
order: -1
nav:
title: API文档
order: 1
---
# 基础
API 规则:
所有 API http 状态码 200 为一定执行成功了(`所以有些不需要返回json的接口只需要判断http状态为200即认为成功`其他为失败400 为参数错误500 为服务器错误
如果是 400, 会返回错误信息,格式如下:
```json
{
"msg": "错误信息", // 错误的提示
"status": 400 // 业务错误的状态码
}
```
所以文档只列出成功的响应参数。
## 长连接地址获取
获取客户端连接**悟空 IM**的地址
> GET /route?uid=xxxx // uid 为用户 ID
成功响应
```json
{
"tcp_addr": "xx.xx.xx.xxx:xx", // tcp连接地址
"ws_addr": "xx.xx.xx.xxx:xx" // websocket连接地址
}
```
## 批量获取连接地址
获取一批用户的连接地址
> POST /route/batch
请求参数:
```json
[uid123,uid32323,....] // 用户uid集合
```
成功响应
```json
[
{
"tcp_addr": "IP:PORT", // tcp连接地址
"ws_addr": "IP:PORT", // websocket连接地址
"uids":[], // 用户uid集合
},
{
"tcp_addr": "IP:PORT", // tcp连接地址
"ws_addr": "IP:PORT", // websocket连接地址
"uids":[], // 用户uid集合
},
...
]
```

201
docs/api/message.md Normal file
View File

@ -0,0 +1,201 @@
---
title: 消息
order: 200
---
# 消息
## 发送消息
服务端调用发送消息接口可以主要用来发送系统类的消息,比如群成员进群通知,消息撤回通知等等
> POST /message/send
请求参数:
```json
{
"header": { // 消息头
"no_persist": 0, // 是否不存储消息 0.存储 1.不存储
"red_dot": 1, // 是否显示红点计数0.不显示 1.显示
"sync_once": 0, // 是否是写扩散这里一般是0只有cmd消息才是1
},
"from_uid": "xxxx", // 发送者uid
"channel_id": "xxxx", // 接收频道ID 如果channel_type=1 channel_id为个人uid 如果channel_type=2 channel_id为群id
"channel_type": 2, // 接收频道类型 1.个人频道 2.群聊频道
"payload": "xxxxx", // 消息内容base64编码
"subscribers": [uid123,uid234,...] // 订阅者 如果此字段有值,表示消息只发给指定的订阅者,没有值则发给频道内所有订阅者
}
```
成功响应
```
http status为200
```
## 批量发送消息
批量发送消息,可以用于后端发送全局通知之类的消息,需要通知到全部用户的消息,可以每次指定一批(通过 subscribers 指定)接收用户,分批推送。
> POST /message/sendbatch
请求参数:
```json
{
"header": { // 消息头
"no_persist": 0, // 是否不存储消息 0.存储 1.不存储
"red_dot": 1, // 是否显示红点计数0.不显示 1.显示
"sync_once": 0, // 是否是写扩散这里一般是0只有cmd消息才是1
},
"from_uid": "xxxx", // 发送者uid
"payload": "xxxxx", // 消息内容base64编码
"subscribers": [uid123,uid234,...] // 接收者的uid分批指定每次建议 1000-10000之间视系统情况而定
}
```
成功响应
```json
{
"fail_uids": [uid123,uid234,...], // 返回发送失败的用户列表
"reason": ["发送失败","不存在用户",...], // 发送失败用户列表对应的失败原因列表与fail_uids一一对应
}
```
## 获取某频道消息
获取某个频道的消息列表
> POST /channel/messagesync
请求参数:
```json
{
"login_uid": "xxxx", // 当前登录用户uid
"channel_id": "xxxx", // 频道ID
"channel_type": 2, // 频道类型
"start_message_seq": 0, // 开始消息列号结果包含start_message_seq的消息
"end_message_seq": 0, // 结束消息列号结果不包含end_message_seq的消息
"limit": 100, // 消息数量限制
"pull_mode": 1 // 拉取模式 0:向下拉取 1:向上拉取
}
```
```
pull_mode为1 表示向上拉,逻辑如下:
消息以start_message_seq为起点加载大于或等于start_message_seq的消息加载到超过end_message_seq结果不包含end_message_seq或超过limit为止如果end_message_seq为0则以limit为准
例如:
start_message_seq=100 end_message_seq=200 limit=10 以limit为准则返回的messageSeq为100-110的消息.
start_message_seq=100 end_message_seq=105 limit=10 以end_message_seq为准则返回的messageSeq为100-104的消息
start_message_seq=100 end_message_seq=0 limit=10 以limit为准则返回的messageSeq为100-110的消息
pull_mode为0 表示向下拉,逻辑如下:
消息以start_message_seq为起点加载小于或等于start_message_seq的消息加载到超过end_message_seq结果不包含end_message_seq或超过limit为止如果end_message_seq为0则以limit为准
例如:
start_message_seq=100 end_message_seq=50 limit=10 以limit为准则返回的messageSeq为100-91的消息.
start_message_seq=100 end_message_seq=95 limit=10 以end_message_seq为准则返回的messageSeq为100-96的消息
start_message_seq=100 end_message_seq=0 limit=10 以limit为准则返回的messageSeq为100-91的消息
如果start_message_seq和end_message_seq都为0则不管pull_mode为那种都加载最新的limit条消息。
```
成功响应
```json
{
"start_message_seq": 0, // 查询的start_message_seq
"end_message_seq": 0, // 查询的end_message_seq
"more": 0, // 是否有更多 0.无 1.有
"messages": [
{
"header": {
// 消息头
"no_persist": 0, // 是否不存储消息 0.存储 1.不存储
"red_dot": 1, // 是否显示红点计数0.不显示 1.显示
"sync_once": 0 // 是否是写扩散这里一般是0只有cmd消息才是1
},
"setting": 0, // 消息设置 消息设置是一个 uint8的数字类型 为1个字节完全由第三方自定义 比如定义第8位为已读未读回执标记开启则为0000 0001 = 1
"message_id": 122323343445, // 消息全局唯一ID
"client_msg_no": "xxxxx", // 客户端消息编号,可用此字段去重
"message_seq": 1, // 消息序列号 (用户唯一,有序递增)
"from_uid": "xxxx", // 发送者用户id
"channel_id": "xxxx", // 频道ID
"channel_type": 2, // 频道类型 1.个人频道 2.群频道
"timestamp": 1223434512, // 消息10位到秒的时间戳
"payload": "xxxx" // base64编码的消息内容
}
]
}
```
## 同步离线命令消息
如果消息 header.sync_once 设置为 1 则离线命令消息就会走此接口,否则走读扩散模式(<label style="color:red">建议只有 CMD 消息才走写扩散</label>
> POST /message/sync
请求参数:
```json
{
"uid": "xxxx", // 当前登录用户uid
"limit": 100 // 消息数量限制
}
```
成功响应
```json
[
{
"header": { // 消息头
"no_persist": 0, // 是否不存储消息 0.存储 1.不存储
"red_dot": 1, // 是否显示红点计数0.不显示 1.显示
"sync_once": 0 // 是否是写扩散这里一般是0只有cmd消息才是1
},
"setting": 0, // 消息设置 消息设置是一个 uint8的数字类型 为1个字节完全由第三方自定义 比如定义第8位为已读未读回执标记开启则为0000 0001 = 1
"message_id": 122323343445, // 消息全局唯一ID
"client_msg_no": "xxxxx", // 客户端消息编号,可用此字段去重
"message_seq": 1, // 消息序列号 (用户唯一,有序递增)
"from_uid": "xxxx", // 发送者用户id
"channel_id": "xxxx", // 频道ID
"channel_type": 2, // 频道类型 1.个人频道 2.群频道
"timestamp": 1223434512, // 消息10位到秒的时间戳
"payload": "xxxx", // base64编码的消息内容
},
...
]
```
## 回执离线命令消息
当客户端获取完离线命令消息后,需要调用此接口做回执,告诉服务端离线消息已获取完毕,这样下次就不会再返回
> POST /message/syncack
请求参数:
```json
{
"uid": "xxxx", // 当前登录用户uid
"last_message_seq": 0 // 客户端本地最后一条命令消息的messageSeq如果本地没有命令消息则为0
}
```
成功响应
```
http status为200
```

108
docs/api/user.md Normal file
View File

@ -0,0 +1,108 @@
---
title: 用户
order: 1
---
# 用户
## 注册或登录
将用户信息注册到狸猫 IM 通讯端,如果存在则更新
> POST /user/token
请求参数:
```json
{
"uid": "xxxx", // 第三方服务端的用户唯一uid
"token": "xxxxx", // 第三方服务端的用户的token
"device_flag": 0, // 设备标识 0.app 1.web (相同用户相同设备标记的主设备登录会互相踢,从设备将共存)
"device_level": 1 // 设备等级 0.为从设备 1.为主设备
}
```
成功响应
```
http status为200
```
## 用户在线状态
查询一批用户的在线状态。
> POST /user/onlinestatus
请求参数:
```json
[uid123,uid345,uid456...] // 需要查询在线状态的用户uid列表
```
成功响应
```json
[uid123,uid456...] // 返回在线的用户uid集合
```
## 添加系统账号
系统账号将有发送消息的全部权限,不受黑名单限制,无需在订阅列表里,比如“系统通知”,“客服”等这种类似账号可以设置系统账号
> POST /user/systemuids_add
请求参数:
```json
{
"uids": [uid123,uid345,uid456...] // 需要加入系统账号的用户uid集合列表
}
```
成功响应
```
http status 200
```
## 移除系统账号
将系统账号移除
> POST /user/systemuids_remove
请求参数:
```json
{
"uids": [uid123,uid345,uid456...] // 系统账号的用户uid集合列表
}
```
成功响应
```
http status 200
```
## 踢出用户的设备登录
将用户的设备踢出登录,(可以实现类似微信的 app 可以踢出 pc 登录)
请求参数:
```json
{
"uid": "xxxx", // 需要踢出的用户uid
"device_flag": 1 // 需要踢出的设备标记 -1: 当前用户下所有设备 0. 当前用户下的app 1. 当前用户下的web 2. 当前用户下的pc
}
```
成功响应
```
http status 200
```

89
docs/api/webhook.md Normal file
View File

@ -0,0 +1,89 @@
---
title: Webhook
order: 400
---
# Webhook
**悟空 IM**的一些数据将通过 webhook 的形式回调给第三方应用服务,比如用户在线状态,需要推送的消息,所有消息等等,所有 webhook 都是 POST 请求,事件名通过 query 参数传入,
比如 第三方的服务器提供的 webhook 地址为 http://example/webhook 那么在线状态的 webhook 为
```
http://example/webhook?event=user.onlinestatus
body的数据类似为 [uid1-0-1,uid2-1-0]
```
以下为具体 webhook 详情
## 用户在线状态通知
每个用户的上线和下线都会通过此 webhook 通知给第三方服务器
`事件名user.onlinestatus`
事件数据:[用户 UID-设备标识-在线状态-连接 ID-设备标识对应的设备在线数量-用户总个设备在线数量] 例如 [uid1-1-0-1001-2-4,uid2-0-0-1001-1-2]
数据说明:
```
设备标识: 0.为app 1.为web端
在线状态: 0.离线 1.在线
连接ID为当前设备在服务器的建立连接的ID
设备标识对应的设备在线数量: 比如web端同一个用户uid有4个web设备同时在线那么这个值就是4
用户总个设备在线数量: 一个用户下所有在线设备的数量 比如web设备4个app设备2个 那么这个值就是6
```
## 离线消息通知
离线消息通知主要是将需要通过离线推送的消息通知给第三方服务器,第三方服务器收到此 webhook 后需要将此消息内容调用手机厂商推送接口,将消息推给 ToUIDs 列表的用户
`事件名msg.offline`
事件数据:消息数组
```go
type MessageResp struct {
Header MessageHeader `json:"header"` // 消息头
Setting uint8 `json:"setting"` // 设置
MessageID int64 `json:"message_id"` // 服务端的消息ID(全局唯一)
MessageIDStr string `json:"message_idstr"` // 字符串类型服务端的消息ID(全局唯一)
ClientMsgNo string `json:"client_msg_no"` // 客户端消息唯一编号
MessageSeq uint32 `json:"message_seq"` // 消息序列号 (用户唯一,有序递增)
FromUID string `json:"from_uid"` // 发送者UID
ChannelID string `json:"channel_id"` // 频道ID
ChannelType uint8 `json:"channel_type"` // 频道类型
Timestamp int32 `json:"timestamp"` // 服务器消息时间戳(10位到秒)
Payload []byte `json:"payload"` // base64消息内容
ToUIDs []string `json:"to_uids"` // 接收用户列表
}
```
## 所有消息通知
**悟空 IM**服务端会将所有消息推送给第三方服务器(为了降低第三方服务器的压力,并不是一条一条推送,做了延迟处理,默认是 500 毫秒(`webhook.msgNotifyEventPushInterval`)批量推送一次,这个可自己视情况配置),第三方服务器可视情况保存或不保存(有一些业务需要保存,比如将消息存入 ElasticSearch给客户端做搜索使用不管保不保存**悟空 IM**服务端都会保存用户的消息。
`事件名msg.notify`
数据说明: 消息数组
```go
type MessageResp struct {
Header MessageHeader `json:"header"` // 消息头
Setting uint8 `json:"setting"` // 设置
MessageID int64 `json:"message_id"` // 服务端的消息ID(全局唯一)
MessageIDStr string `json:"message_idstr"` // 字符串类型服务端的消息ID(全局唯一)
ClientMsgNo string `json:"client_msg_no"` // 客户端消息唯一编号
MessageSeq uint32 `json:"message_seq"` // 消息序列号 (用户唯一,有序递增)
FromUID string `json:"from_uid"` // 发送者UID
ChannelID string `json:"channel_id"` // 频道ID
ChannelType uint8 `json:"channel_type"` // 频道类型
Timestamp int32 `json:"timestamp"` // 服务器消息时间戳(10位到秒)
Payload []byte `json:"payload"` // base64消息内容
}
```

7
docs/guide/advanced.md Normal file
View File

@ -0,0 +1,7 @@
---
group:
title: 进阶
order: 300
order: 300
title: 命令行工具
---

9
docs/guide/datasource.md Normal file
View File

@ -0,0 +1,9 @@
---
title: Datasource
group:
title: 进阶
order: 100
order: 400
---
待完善

9
docs/guide/demo.md Normal file
View File

@ -0,0 +1,9 @@
---
group:
title: 介绍
order: -1
order: 300
title: Demo演示
---
待完善

58
docs/guide/fullconfig.md Normal file
View File

@ -0,0 +1,58 @@
---
title: 配置说明
group:
title: 进阶
order: 100
order: 200
---
wk.yaml
```yaml
mode: 'debug' # 运行模式 模式 debug 测试 release 正式 bench 压力测试
Addr: 'tcp://0.0.0.0:7677' # tcp监听地址
httpAddr: '0.0.0.0:1516' # http api的监听地址 默认0.0.0.0:1516
dataDir: ~/wukongimdata # 数据存储目录
tokenAuthOn: true # 是否开启token验证 不配置将根据mode属性判断 debug模式下默认为false release模式为true
logger:
level: 0 # 日志级别 0:未配置,将根据mode属性判断 1:debug 2:info 3:warn 4:error
dir: './logs' # 日志目录
lineNum: false # 是否打印行号
wss:
on: true # 是否开启wss
addr: '0.0.0.0:2122' # // websocket 监听地址 默认0.0.0.0:2122
monitor:
on: true # 是否开启监控
addr: '0.0.0.0:1101' # 监控监听地址 默认为 0.0.0.0:1101
external:
ip: '' # 外网IP 如果没配置将通过ifconfig.io获取
tcpAddr: '' # 默认自动获取, 节点的TCP地址 对外公开APP端长连接通讯 格式: ip:port
wssAddr: '' # 默认自动获取, 节点的wsAdd地址 对外公开 WEB端长连接通讯 格式: ip:port
channel:
cacheCount: 1000 # 频道缓存数量 频道被加载后会缓存到内存中,如果频道数量过多,会占用大量内存,可以通过此配置限制缓存数量
createIfNoExist: true # 频道不存在时是否自动创建 默认为true
subscriberCompressOfCount: 0 # 订阅者数多大开始压缩,如果开启默认采用gzip压缩离线推送的时候订阅者数组太大 可以设置此参数进行压缩 默认为0 表示不压缩
tmpChannel:
suffix: '@tmp' # 临时频道后缀 带有此后缀的频道将被认为是临时频道,临时频道不会被持久化
cacheCount: 500 # 临时频道缓存数量
webhook: # 两者配其一即可 webhook配置 用于接收消息通知事件,详情请查看文档
httpAddr: '' # webhook的http地址 通过此地址通知数据给第三方 格式为 http://xxxxx
grpcAddr: '' # webhook的grpc地址 当前httpAddr成为瓶颈的时候可以用grpc进行推送 如果此地址有值 则不会再调用httpAddr配置的地址,格式为 ip:port通讯协议请查看文档
msgNotifyEventPushInterval: 500ms # 消息通知事件推送间隔默认500毫秒发起一次推送
msgNotifyEventRetryMaxCount: 5 # 消息通知事件消息推送失败最大重试次数 默认为5次超过将丢弃
msgNotifyEventCountPerPush: 100 # 每次webhook消息通知事件推送消息数量限制 默认一次请求最多推送100条
datasource: # 数据源配置,不填写则使用自身数据存储逻辑,如果填写则使用第三方数据源,数据格式请查看文档
addr: '' # 数据源地址
channelInfoOn: false # 是否开启频道信息数据源的获取
conversation: # 最近会话配置
on: false # 是否开启最近会话
cacheExpire: 1d # 最近会话缓存过期时间 默认为1天
syncInterval: 5m # 最近会话保存间隔,每隔指定的时间进行保存一次 默认为5分钟
syncOnce: 100 # 最近会话同步保存一次的数量 超过指定未保存的数量 将进行保存 默认为100
userMaxCount: 1000 # 用户最近会话最大数量,超过此数量的最近会话后最旧的那条将被覆盖掉 默认为1000
messageRetry: # 消息重试配置
interval: 60s # 重试间隔 默认为60秒
scanInterval: 5s # 每隔多久扫描一次超时队列,看超时队列里是否有需要重试的消息
maxCount: 5 # 消息最大重试次数, 服务端持有用户的连接但是给此用户发送消息后在指定的间隔内没有收到ack将会重新发送直到超过maxCount配置的数量后将不再发送这种情况很少出现如果出现这种情况此消息只能去离线接口去拉取
userMsgQueueMaxSize: 0 # 用户消息队列最大大小超过此大小此用户将被限速0为不限制
```

29
docs/guide/index.md Normal file
View File

@ -0,0 +1,29 @@
---
group:
title: 介绍
order: -1
order: 1
title: 什么是悟空IM
nav:
title: 指南
order: 1
---
# 什么是悟空 IM
高性能通用即时通讯服务支持聊天应用消息推送物联网通讯音视频信令直播弹幕客服系统AI 通讯,即时社区等场景。
## 特性
悟空 IM 具备以下特性:
- 0⃣ **零依赖**:没有依赖任何第三方组件,部署简单,一条命令即可启动
- 📚 **完全自研**:自研消息数据库,消息分区永久存储,自研二进制协议,支持自定义协议
- 🔐 **安全**:消息通道和消息内容全程加密,防中间人攻击和串改消息内容。
- 🚀 **性能强劲**性能强劲MAC 笔记本单机测试 16w 多/秒的消息(包含存储)吞吐量,频道支持万人同时订阅。
- 🧱 **扩展性强**:采用频道设计理念,目前支持群组频道,点对点频道,后续可以根据自己业务自定义频道可实现机器人频道,客服频道等等。
- 🔗 **兼容性强**:同时无差别支持 tcpwebsocket。
## 问题反馈
如果在使用过程中发现任何问题、或者有改善建议,欢迎在 GitHub Issues 进行反馈https://github.com/WuKongIM/WuKongIM/issues

35
docs/guide/initialize.md Normal file
View File

@ -0,0 +1,35 @@
---
group:
title: 介绍
order: -1
order: 1
title: 基础概念
---
# 基础概念
### 频道
频道是消息投递的载体。
频道有频道 ID 和频道类型两个重要字段,当消息投递给频道后,不同类型的频道会有不同的处理逻辑。逻辑处理完毕后,频道会将消息投递给订阅者。
### 订阅者
用户可以订阅频道,频道里的用户称为订阅者。
订阅者可以是用户,也可以是第三方服务器。
### 消息
发送的消息内容会被编码成一条消息,消息内容为此消息的 payload消息包含唯一 ID消息序号消息类型消息内容消息发送者消息接收者消息发送时间消息接收时间等字段。
### 用户
连接到**悟空 IM**服务的客户端称为用户。
用户有 uid 和 token 两个重要字段uid 是用户的唯一标识token 是用户的身份凭证,进行长连接到**悟空 IM**服务时,需要携带 token 进行身份验证。
### 最近会话
最近会话是用户与用户或用户与群之间的一次会话,最近会话包含会话 ID会话类型会话名称会话头像会话最后一条消息会话最后一条消息发送时间等字段。

11
docs/guide/others.md Normal file
View File

@ -0,0 +1,11 @@
---
title: 常见问题
group:
title: 其他
order: 100
order: 100
---
# 常见问题
待收集

75
docs/guide/quickstart.md Normal file
View File

@ -0,0 +1,75 @@
---
title: 部署
group:
title: 快速开始
order: -1
order: 100
---
# 部署
## 一键部署(推荐)
```shell
sudo curl -L "https://github.com/WuKongIM/WuKongIMCli/releases/download/v1.0.0/wukongimcli-$(uname -s)-$(uname -m)" -o /usr/local/bin/wk
sudo chmod +x /usr/local/bin/wk
# 启动
wk start
# 停止
# wk stop
```
## 源码部署
```shell
git clone https://github.com/WuKongIM/WuKongIM.git
cd WuKongIM
go build -o wkim main.go
# 启动
./wkim
```
## Docker 部署
```shell
docker run -p 7676:7676 -p 2122:2122 -p 1516:1516 --name wukongim -v ./wukongimdata:/home/wukongimdata wukongim/wukongim:latest
```
## Docker Compose 部署
```shell
git clone https://github.com/WuKongIM/WuKongIM.git
cd WuKongIM
docker-compose up -d
```
## 配置
配置文件为当前目录下的 wk.yaml默认为~/wukongimdata/wk.yaml文件如果没有此文件则使用系统的默认最优配置。
完整配置请查看[完整配置](/guide/fullconfig)
## 验证部署
```shell
sudo curl -L "https://github.com/WuKongIM/WuKongIMCli/releases/download/v1.0.0/wukongimcli-$(uname -s)-$(uname -m)" -o /usr/local/bin/wk
sudo chmod +x /usr/local/bin/wk
wk doctor
```
```
HTTP listener 1516 port is ok
TCP listener 7676 port is ok
Websocket listener 2122 port is ok
MQTT listener 5255 port is ok
```

53
docs/guide/scene.md Normal file
View File

@ -0,0 +1,53 @@
---
group:
title: 介绍
order: -1
order: 1
title: 适用场景
---
### 即时通讯
- 群频道支持
- 个人频道支持
- 消息永久存储
- 离线消息推送支持
- 最近会话维护
### 消息推送/站内消息
- 群频道支持
- 个人频道支持
- 离线消息推送支持
### 物联网通讯
- mqtt 协议支持(待开发)
- 支持发布与订阅
### 音视频信令服务器
- 支持临时指令消息投递
### 直播弹幕
- 临时消息投递
- 临时订阅者支持
### 客服系统
- 客服频道支持
- 消息支持投递给第三方服务器
- 第三方服务器可决定分配指定的订阅者成组投递
### 实时 AI 反馈
- 支持客户端发的消息推送给第三方服务器,第三方服务器反馈给 AI 后返回的结果再推送给客户端
### 即时社区
- 社区频道支持
- 支持 topic 模式的消息投递

View File

@ -0,0 +1,9 @@
---
title: 常用配置
group:
title: 快速开始
order: -1
order: 200
---
待完善

13
docs/guide/stress.md Normal file
View File

@ -0,0 +1,13 @@
---
group:
title: 进阶
order: 300
order: 600
title: 测试
---
# 测试
## 性能测试
## 模拟测试

9
docs/guide/webhook.md Normal file
View File

@ -0,0 +1,9 @@
---
title: Webhook
group:
title: 进阶
order: 100
order: 300
---
待完善

25
docs/index.md Normal file
View File

@ -0,0 +1,25 @@
---
title: 悟空IM
hero:
title: 悟空IM
description: 让信息传递更简单
actions:
- text: 立即上手
link: /guide
- text: Github
link: https://github.com/WuKongIM/WuKongIM
# features:
# - title: Hello
# emoji: 💎
# description: Put hello description here
# - title: World
# emoji: 🌈
# description: Put world description here
# - title: '!'
# emoji: 🚀
# description: Put ! description here
# - title: 'zz'
# emoji: 🚀
# description: Put ! description here
footer: Open-source Apache 2.0 Licensed | Copyright © 2020<br />Powered by 上海信必达网络科技
---

View File

@ -0,0 +1,8 @@
---
title: Android
order: 200
---
## 设计理念
## 结构说明

6
docs/sdk/C/index.md Normal file
View File

@ -0,0 +1,6 @@
---
order: 500
title: C
---
待开发

View File

@ -0,0 +1,8 @@
---
title: Flutter
order: 400
---
## 设计理念
## 结构说明

View File

@ -0,0 +1,625 @@
---
title: Javascript
order: 300
---
# Javascript
## 介绍
### 设计理念
像设计书的目录一样设计 api, 通过 WKSDK.shared().xxxManager 我们可以访问到所有需要的功能,例如发送消息 `WKSDK.shared().chatManager.send(xxx)`
### 结构说明
![sdk结构图](./wksdk.png)
```ts
// 聊天管理者
// 负责消息相关的增删改查操作 比如发送消息,删除消息,撤回消息,聊天消息的监听等等
WKSDK.shared().chatManager;
// 连接管理者
// 负责与IM建立连接或断开连接 监听IM连接状态等等
WKSDK.shared().connectionManager;
// 频道管理者
// 负责频道数据的获取和缓存和一些频道的设置,比如置顶,免打扰,禁言等等
WKSDK.shared().channelManager;
// 最近会话管理者
// 负责维护最近会话的相关数据,比如未读数量,草稿,@我,最后一条消息等等
WKSDK.shared().conversationManager;
// 提醒管理者
// 负责最近会话的提醒事项维护
WKSDK.shared().reminderManager;
```
## 集成
### npm 或 yarn 引入
```
$ npm i wukongimjssdk
```
或者
```
$ yarn add wukongimjssdk
```
### 引入
import { WKSDK } from "wukongimjssdk/lib/sdk"
### 初始化
```ts
// 集群模式通过此方法获取连接地址
// WKSDK.shared().config.provider.connectAddrCallback = async (callback: ConnectAddrCallback) => {
// const addr = await xxxx // addr 格式为 ip:port
// callback(addr)
// }
// 单机模式可以直接设置地址
WKSDK.shared().config.addr = 'IP:PORT'; // 默认端口为2122
// 认证信息
WKSDK.shared().config.uid = 'xxxx'; // 用户uid需要在悟空通讯端注册过
WKSDK.shared().config.token = 'xxxx'; // 用户token (需要在悟空通讯端注册过)
// 更多配置,查看:
WKSDK.shared().config;
```
## 连接与断开
```ts
// 连接
WKSDK.shared().connectManager.connect();
// 断开
WKSDK.shared().connectManager.disconnect();
// 连接状态监听
WKSDK.shared().connectManager.addConnectStatusListener(
(status: ConnectStatus, reasonCode?: number) => {
if (status === ConnectStatus.Connected) {
console.log('连接成功');
} else {
console.log('连接失败', reasonCode); // reasonCode: 2表示认证失败uid或token错误
}
},
);
```
## 在线消息收发
#### 数据操作
```ts
/**
* 发送消息
* @param content 消息内容
* @param channel 频道对象 个人频道,群频道
* @param setting 发送设置 比如:已读未读回执,端对端加密
* @returns 完整消息对象
*/
WKSDK.shared().chatManager.send(content: MessageContent, channel: Channel, setting?: Setting)
// 例如发送文本消息hello给用户A
const text = new MessageText("hello")
WKSDK.shared().chatManager.send(text,new Channel("A",ChannelTypePerson))
```
#### 数据监听
```ts
// 消息发送状态监听
WKSDK.shared().chatManager.addMessageStatusListener((packet: SendackPacket) => {
console.log('消息clientSeq->', packet.clientSeq); // 客户端序号用来匹配对应的发送的消息
if (packet.reasonCode === 1) {
// 发送成功
} else {
// 发送失败
}
});
// 消息监听
WKSDK.shared().chatManager.addMessageListener((message: Message) => {});
```
## 离线消息接收
在**悟空 IM**中为了应付海量离线消息,采用了按需拉取的机制,比如 10 个会话一个会话 10 万条消息,\**悟空 IM 不会把这个 10*10 万=100 万条消息都拉取到本地。 而是采用拉取这 10 个会话的信息和对应的最新 20 条消息,也就是实际只拉取了 200 条消息 相对 100 万条消息来说大大提高了离线拉取速度。用户点进对应的会话才会去按需拉取这个会话的消息。 这些机制 SDK 内部都已做好了封装,使用者其实不需要关心。使用者只需要关心最近会话的变化
#### 数据源设置
```ts
// 提供最近会话同步的数据源
WKSDK.shared().config.provider.syncConversationsCallback = async (): Promise<Array<Conversation>> => {
// 后端提供的获取最近会话列表的接口数据 然后构建成 Conversation对象数组返回
let conversations = new Array<Conversation>();
conversations = await request(...)
return conversations
})
// 提供频道内消息同步的数据源
WKSDK.shared().config.provider.syncMessagesCallback = async(channel:Channel,opts:SyncOptions):Promise<Array<Message>>=> {
// 后端提供的获取某个频道的消息列表的接口数据然后构建成Message对象数组返回
let messages = new Array<Message>();
messages = await request(...)
return messages
}
```
##### 数据操作
```ts
// 同步最近会话会触发WKSDK.shared().config.provider.syncConversationsCallback
const conversations = await WKSDK.shared().conversationManager.sync({});
// 同步频道的消息会触发WKSDK.shared().config.provider.syncMessagesCallback
const messages = WKSDK.shared().chatManager.syncMessages(channel, opts);
```
##### 数据监听
```ts
// 监听最近会话数据
WKSDK.shared().conversationManager.addConversationListener(
(conversation: Conversation, action: ConversationAction) => {
// conversation发送数据变化的最近会话对象
// action变化行为 add添加 update更新
},
);
```
## 文本消息
```ts
class MessageText extends MessageContent {
text?: string;
}
```
## 图片消息
```ts
class ImageContent extends MediaMessageContent {
width!: number; // 图片宽度
height!: number; // 图片高度
url!: string; // 图片远程地址
constructor(file?: File, width?: number, height?: number) {
super();
this.file = file;
this.width = width || 0;
this.height = height || 0;
}
}
```
## 语音消息
web 语音消息暂只支持收不支持发送
```ts
class VoiceContent extends MediaMessageContent {
url!: string; // 语音文件下载地址
timeTrad!: number; // 语音秒长
waveform!: string; // 语音波纹 base64编码
}
```
## 小视频消息
web 语小视频消息暂只支持收不支持发送
```ts
class VideoContent extends MessageContent {
url!: string; // 小视频下载地址
cover!: string; // 小视频封面图片下载地址
size: number = 0; // 小视频大小 单位byte
width!: number; // 小视频宽度
height!: number; // 小视频高度
second!: number; // 小视频秒长
}
```
## 名片消息
```ts
class Card extends MessageContent {
name!: string; // 好友名字
uid!: string; // 好友uid
vercode!: string; // 好友验证码
}
```
## 位置消息
```ts
class LocationContent extends MessageContent {
lng: number = 0; // 纬度
lat: number = 0; // 经度
title!: string; // 位置标题
address!: string; // 具体地址
img!: string; // 封面图远程地址
}
```
## CMD 消息
cmd 消息由服务端下发客户端解析执行。
```ts
class CMDContent extends MessageContent {
cmd!: string; // cmd的指令
param: any; // 指令对应的参数
}
```
## 最近会话
最近会话用于表示会话列表页的数据模型。当用户发送,收取及删除消息时,都会同时去修改最近会话。
当收到或者一条消息时,会自动生成这个消息对应的最近会话。但值得注意的是最近会话和会话并不是一一对应的关系,删除最近会话并不会影响会话
最近会话主要属性
```ts
class Conversation {
channel!: Channel; // 频道
unread!: number; // 未读消息
lastMessage?: Message; // 最后一条消息
extra?: any // 扩展数据(用户自定义的数据)
remoteExtra!: ConversationExtra // 远程扩展数据
reminders = new Array<Reminder>() // 提醒项
...
}
```
## 频道管理(置顶,免打扰等等)
[什么是频道](/guide/initialize#频道)
频道是**悟空 IM**里比较重要的一个抽象概念,发送消息都是先发送给频道,频道根据自己的配置规则进行投递消息,频道分频道和频道详情
频道的属性
```ts
// 频道
class Channel {
channelID!: string; // 频道ID 个人频道为用户uid群频道为群ID
channelType!: number; // 频道类型 1.个人频道 2.群聊频道
}
```
```ts
// 频道详情
class ChannelInfo {
channel!: Channel; // 频道
title!: string; // 频道标题
logo!: string; // 频道logo
mute!: boolean; // 是否免打扰
top!: boolean; // 是否置顶
online: boolean = false; // 是否在线
lastOffline: number = 0; // 最后一次离线时间
orgData: any; // 频道原始数据由第三方自定义
}
```
#### 数据源设置
```ts
// 频道详情获取数据源提供
WKSDK.shared().config.provider.channelInfoCallback = async function (channel: Channel): Promise<ChannelInfo> {
let channelInfo:ChannelInfo
channelInfo = await request(...)
return channelInfo
}
// 订阅者获取数据源提供者
WKSDK.shared().config.provider.syncSubscribersCallback = async function (channel: Channel, version: number): Promise<Array<Subscriber>> {
let subscribers:Subscriber[]
subscribers = await request(...)
return subscribers
}
```
#### 数据操作
```ts
// 获取频道详情(不会触发数据源的远程获取)
const channelInfo = WKSDK.shared().channelManager.getChannelInfo(channel);
// 获取频道的订阅者(不会触发数据源的远程获取)
const subscribes = WKSDK.shared().channelManager.getSubscribes(channel);
// 从远程提取频道详情(会触发数据源的远程获取和频道信息监听,是异步过程)
WKSDK.shared().channelManager.fetchChannelInfo(channel);
// 从远程提取频道列表(会触发数据源的远程获取和订阅者的监听,是异步过程)
WKSDK.shared().channelManager.syncSubscribes(channel);
```
#### 数据监听
```ts
// 监听频道详情
WKSDK.shared().channelManager.addListener((channelInfo: ChannelInfo) => {});
```
## 进阶使用
### 消息附件上传设置
所有带附件的消息的上传都会通过此任务上传
伪代码如下:
```ts
// 实现四个方法 initWithMessage resume cancel suspend
class MediaMessageUploadTask extends MessageTask {
- (instancetype)initWithMessage:(WKMessage *)message {
self = [super initWithMessage:message];
if(self) {
[self initTask];
}
return self;
}
async start(): Promise<void> {
const mediaContent = this.message.content as MediaMessageContent
const param = new FormData();
param.append("file", mediaContent.file);
const resp = await axios.post(uploadURL,param,{
headers: { "Content-Type": "multipart/form-data" },
cancelToken: new axios.CancelToken((c: Canceler) => {
this.canceler = c
}),
onUploadProgress: e => {
// 更新任务进度
var completeProgress = ((e.loaded / e.total) | 0);
this._progress = completeProgress
this.update()
}
}).catch(error => {
// 更新任务错误
console.log('文件上传失败!->', error);
this.status = TaskStatus.fail
this.update()
})
if(resp) {
if(resp.data.path) {
// 更新任务成功
const mediaContent = this.message.content as MediaMessageContent
mediaContent.remoteUrl = resp.data.path
this.status = TaskStatus.success
this.update()
}
}
}
// 任务取消
cancel(): void {
this.status = TaskStatus.cancel
if(this.canceler) {
this.canceler()
}
this.update()
}
// 任务进度
progress(): number {
return this._progress??0
}
@end
```
注册上传任务
```ts
WKSDK.shared().config.provider.messageUploadTaskCallback = (
message: Message,
): MessageTask => {
return new MediaMessageUploadTask(message);
};
```
### 自定义普通消息
我们以自定义一个 gif 消息为例。
#### 第一步继承 MessageContent 和定义 gif 消息的正文结构
```ts
class GifContent extends MessageContent {
width!: number; // gif宽度
height!: number; // gif高度
url!: string; // gif远程下载地址
}
```
#### 第二步 编码解码
```ts
最终传递的消息内容为 {"type":3,"url":"xxxx","width":xxx,"height":xxx}
class GifContent extends MessageContent {
width!: number // gif宽度
height!: number // gif高度
url!: string // gif远程下载地址
// 解码
decodeJSON(content: any) {
this.width = content["width"] || 0
this.height = content["height"] || 0
this.url = content["url"]
}
// 编码
encodeJSON() {
return { "width": this.width, "height": this.height, "url": this.url }
}
}
```
#### 第三步 注册
```ts
WKSDK.shared().register(MessageContentTypeConst.gif, () => new GifContent()); // gif动图
```
### 自定义附件消息
自定义附件消息的流程与普通消息差异不大,我们以图片消息为例
#### 第一步继承 MediaMessageContent
注意这里是继承 MediaMessageContent 不是 MessageContent当发送附件消息的时候sdk 会调用[上传任务](/web/onlysdk.html#消息附件上传设置),将本地的文件上传到服务器,然后再进行消息的编码和发送
最终传递的消息内容为 {"type":4,"url":"xxxx","width":xxx,"height":xxx}
```ts
class ImageContent : MediaMessageContent {
width!: number // gif宽度
height!: number // gif高度
url!: string // gif远程下载地址
}
```
#### 第二步编码解码
```ts
class ImageContent : MediaMessageContent {
width!: number // gif宽度
height!: number // gif高度
url!: string // gif远程下载地址
constructor(file?: File,width?:number,height?:number) {
super()
this.file = file // File为要上传的图片文件对象
this.width = width || 0
this.height = height || 0
}
// 附件file上传成功后会得到 this.remoteUrl这个远程下载地址这时可以将此地址编码到消息内
encodeJSON() {
return { "width": this.width || 0, "height": this.height || 0, "url": this.remoteUrl || "" }
}
// 解码消息
decodeJSON(content: any) {
this.width = content["width"] || 0
this.height = content["height"] || 0
this.url = content["url"] || ''
}
}
```
#### 第三步 注册
```ts
WKSDK.shared().register(
MessageContentTypeConst.image,
() => new ImageContent(),
);
```
### 消息扩展
待开发
### 消息编辑
待开发
### 消息回应(点赞)
待开发
### 已读未读管理
待开发
### 端对端加密
web 不支持端对端加密
### 会话提醒管理
会话提醒目前只支持服务端下发指令,客户端同步提醒然后显示提醒,会话提醒由 WKSDK.shared().reminderManager 管理
```ts
class Reminder {
channel!: Channel;
reminderID!: number; // 提醒ID
messageID!: string;
messageSeq!: number;
reminderType!: ReminderType; // 提醒类型
text?: string; // 文本提示
data?: any; // 提醒包含的自定义数据
isLocate: boolean = false; // 是否需要进行消息定位
version: number = 0; // 数据版本
done: boolean = false; // 用户是否完成提醒
}
```
###### 数据源设置
```ts
// 提供提醒项列表的数据源设置
WKSDK.shared().config.provider.syncRemindersCallback = async (version:number):Reminder[] => {
let reminders:Reminder[]
reminders = request(...)
return reminders
}
// 提供提醒项完成的数据源
WKSDK.shared().config.provider.reminderDoneCallback = async (ids: number[]) => {
request(...)
}
```
###### 数据操作
```ts
// 同步提醒
WKSDK.shared().reminderManager.sync();
// 提醒项已处理完成
WKSDK.shared().reminderManager.done(ids);
```
###### 数据监听
```ts
// 提醒项的更新会触发对应的最近会话的更新
WKSDK.shared().conversationManager.addConversationListener(
(conversation: Conversation, action: ConversationAction) => {
console.log('conversation.reminders-->', conversation.reminders);
},
);
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

1296
docs/sdk/iOS/index.md Normal file

File diff suppressed because it is too large Load Diff

BIN
docs/sdk/iOS/sdktoapp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
docs/sdk/iOS/wksdk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

33
package.json Normal file
View File

@ -0,0 +1,33 @@
{
"name": "WuKongIMDocs",
"version": "0.0.1",
"description": "Docs For WuKongIM",
"license": "MIT",
"scripts": {
"build": "dumi build",
"dev": "dumi dev",
"prepare": "husky install && dumi setup",
"start": "npm run dev"
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"lint-staged": {
"*.{md,json}": [
"prettier --write --no-error-on-unmatched-pattern"
]
},
"devDependencies": {
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.1.0",
"dumi": "^2.1.22",
"husky": "^8.0.1",
"lint-staged": "^13.0.3",
"prettier": "^2.7.1"
},
"authors": [
"tt@gmail.com"
]
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

12
tsconfig.json Normal file
View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"baseUrl": "./",
"paths": {
"@@/*": [".dumi/tmp/*"]
}
},
"include": [".dumi/**/*", ".dumirc.ts"]
}

10130
yarn.lock Normal file

File diff suppressed because it is too large Load Diff