title | date |
---|---|
Gws的架构设计 |
2022-01-24 16:12:20 -0800 |
gotapi-ws 的架构设计
gotapi-ws 是一整套websocket im 实现,在最基础的websocket链接之上,实现了基于redis 的list的一个历史聊天记录的存档,以及消息撤回机制;其服务端由golang实现,客户端当然是brower端和nodejs端的实现。 现在在https://ws.404.ms 上已经部署了一套服务端,大家可以直接使用。(在ws.404.ms上http的链接已经重定向到Https了,所以请使用https和wss)。
groupName的概念
GroupName 可以简单的理解为房间,连接时配置不同的groupName,就是不在同的房间聊天。 怎么配置不同的房间呢? 很简单,连接服务端时,websocket的地址的URL PATH部分就是groupName;如下面这个:
const channel = "/note/shifen/me7pb5s6a3shifen.de"
const wsHost = "ws.404.ms"
let socketBus = new SocketBus(`wss://${wsHost}${channel}`);
/note/shifen/me7pb5s6a3shifen.de 就是groupName。
server-side 支持两个层级的操作
- low level : 就是最基础的websocket操作,服务端收到数据后,即将数据广播出去。
- high level: 如果数据是被json编码的,且编码后识别是一个数据类型的包,则数据会被存进redis,再广播出去;存入redis的数据可以通过历史数据接口取回,也可以按uuid进行撤回。 low-level 和high-level的区别就是,high-level是按gotapi指定的格式封好的包,支持ack确认,支持历史消息,支持撤回。
high-level的消息包的结构
一条high-level的典型的数据类型的消息如下:
{
"body":{
"sent":false,
"data":"hello world",
"hash":"eb2ef7838a7a57d"
},
"type":2, //2表示是一条数据;1表示是一条命令。
"uuid":"02108001177667145695",
}
一条high-level的典型的命令类型的消息如下:
{
"type":1,
"command":1 //1表示是一条server side的ack消息,5表示是一条pingpong消息;
}
nodejs端的 API
下面是一个简单的使用node-gotapi-ws包的示例,演示了如何利用gotapi-ws的high-level api进行一个简单的聊天系统:
import {Direction, MessageBus, SocketBus} from "node-gotapi-ws";
const channel = "/note/shifen/me7pb5s6a3shifen.de"
const wsHost = "ws.404.ms"
let socketBus = new SocketBus(`wss://${wsHost}${channel}`);
let messageBus = new MessageBus(Direction.Customer, socketBus, `https://${wsHost}/__/history/`,
`${channel}`, 100, 0)
//设置一个回调,在有新消息到达时,会被触发。
messageBus.setNewMessageCallback(
(newMsg, uuid) => {
console.log("new msg arrived")
console.log(newMsg.data)
}
);
setTimeout(()=>{
//这里演示如何发送一条消息出去;发送消息有两种方式,这里是用的websocket链接来发送的,另一种方式是用http api来发送;
messageBus.pushMessage("god bless u");
},1000)
使用http api来发消息
发送一条消息,可以使用websocket链接,也可以使用http 接口来发送;不论是low-level还是high-level,都支持用这两种方式来发送;下面演示一下如何用http 接口来发消息:
curl -X POST -d "{\"type\":2,\"uuid\":\"thisisuuid\",\"body\":{\"hash\":\"hello1234\",\"data\":\"hello world\",\"sent\":false}}" https://ws.404.ms/room/9527/
虽然在websocket链接里可以发消息,但是我们推荐用http api来发消息。在以往的实践中,我们是在应用系统中通过http api 往这个聊天服务器发消息的,因为我们还要实现额外的会话存档、检索、合规等业务。
使用http api来拉取历史消息
提醒:历史消息只针对high-level的消息有用;
可以按这样访问/__/history/来调取历史消息:
curl -X POST -d "groupName=/room/9527/&position=-50&size=50" https://ws.404.ms/__/history
在gotapi-ws node-gotapi-ws 的npm包里,已经处理好了,在创建messageBus时,有一个参数是指定history 大小的,MessageBus的构造函数如下:
class MessageBus {
constructor(direction: Direction, socketBus: SocketBus, historyUrl: string, groupName: string, historySize: number, position:number){
...
if(self.historySize>0){
self.pullHistory();
}
}
}
这里的historySize,是指定当聊天在初始化的时候,从服务器上拉回多少条历史消息;
消息的撤回
golang 服务器提供了一个撤回接口:
curl -X POST -d "groupName=/room/9527/&uuid=some-uuid" https://ws.404.ms/__/cancel
撤回时,提交两个参数,一个是groupName,一个是uuid;groupName前文解释过;uuid是每条消息的唯一辨识码。