需求分析
消息推送中台作为底层的消息推送服务,为服务器到设备端、设备端到服务器、设备端到设备端的实时消息安全传输提供便利的服务。目前该中台系统的需求如下:
- 多输入支持。支持Restful, MQTT,GRPC等接口作为输入方。
- 一对一,一对多消息推送支持。
- 多tenant,多project。
- 云中立,支持使用所有云厂商的底层产品。
架构框图
消息发送流程
- 设备通过MQTT、GRPC、Restful API等协议,把payload推送到服务器,服务器检查payload中的appId, projectId和projectKey是否合法。如合法,则服务器最终将payload转发到kafka。
- Worker从kafka中订阅到payload。Worker查看payload中是否有targetId字段,如果有,则跳到第3步进行单发消息。如果payload中有targetGroupId字段,则跳到第4步进行群发消息。否则报错退出。
- Worker检查sourceId是否有权限向targetId发送消息,如果没有,则报错退出。如果有,则推送MQTT消息给targetId指向的设备。
Worker检查sourceId是否有权限向targetGroupId发送消息,如果没有,则报错退出。如果有,服务器通过targetGroupId获取到targetId的列表,
当消息推送的payload中的subGroup与注册的回调函数返回的payload中的subGroup相等时,将消息复制成n条单发消息的payload,推送至kafka。
获取设备列表
推送中台群发消息的时候,需要使用targetGroupId去获取设备列表。推送中台需要用户注册一个获取设备列表的url,推送中台会把targetGroupId推给该url,
并期待该url的处理函数返回一个sn的列表。推送中台会传给url一个token给url,用户可以在url中自行鉴权。
Payload设计
- 消息推送的payload
{
appId, // 推送中台的appId, projectId和projectKey
appKey,
projectId,
projectKey,
timestamp, // 该消息的时间戳
targetId|targetGroupId, // 接收消息的设备sn或group Id
subGroup, //内分组
sourceId, // 发送消息的设备sn,0表示服务器
payload: {
…
},
signature: {
…
}
}
- 注册获取tragetId回调函数返回的payload
{
[
{
sn,
subGroup, //分组
},
…
]
}
安全设计
- 全链路TLS。
- 输入接口(MQTT、GRPC、Restful API等)独立鉴权。
- 消息签名。
- 消息鉴权。不同tenant之间应该做到消息隔离。隔离方案目前待定。在没有消息隔离的机制下,只要知道目标sn,就可以给该目标发送消息。
表结构
messagePushApp 表
- 字段
- sub
- appName
- password
- appDesc
- 唯一性
- sub + appName
project 表
- 字段
- appId(messagePushApp._id)
- projectName
- projectKey
- projectDesc
- 唯一性
- projectName
界面设计
- messagePush App列表,可以新增messagePush App,可以发送广播消息, 扫码发送点对点消息,websocket直连
- 新增app/project后,把链接地址, 用户名,密码 显示在app/project详情页
- 当外部项目使用推送时,需要选择PushApp和PushProject和填写设备查询URL
- topic根据SN生成,每一个设备对应一个独立的topic
- 生成QrCode时,浏览器创建一个websocket和服务器通信
服务端API前缀
/api/push/server
服务端API
messagePushApp API
- C
POST /app/v1
- R
GET /app/v1/:_id
- U
PUT /app/v1/:_id
- D
DELETE /app/v1/:_id
- List
GET /app/v1
project API
- C
POST /project/v1
- R
GET /project/v1/:_id
- U
PUT /project/v1/:_id
- D
DELETE /project/v1/:_id
- List
GET /project/v1
推送相关 API
- getDetail
GET /app/v1/detail/:appName
- pushMessage
POST /pushMessage/v1/externProjectId
- 说明: 查询externProjectId所在记录的deviceQueryUrl,分别推送给此URL查询出来的设备, 查询设备时使用externProjectId和externProjectKey鉴权
- getConntectionQrcode
GET /conntectionQrcode/v1
-
说明:服务端创建一个broker以及相应的principal、policy、两个可sub和pub的Topic debug1和debug2,
并且把与之对应的username,password,两个topic放入QrCode中。当浏览器断开
websoket 链接时,删除这个broker以及对应的principal和policy。
设备端订阅debug1, 在debug2上publish消息;服务端则订阅debug2,在debug1上publish消息 -
QrCode:
{ username, password, readTopic, // $uuid/debug1 writeTopic, // $uuid/debug2 }
-