使用websocket做消息中心,通常做法是采用kafka、redis等中间件搭配实现,使用CONNMIX则无需使用中间件,同时分布式集群能力也无需担忧用户量大增后带来的性能问题。
user:,该uid从context中取出。/v1/mesh/publish 接口往对应 uid 发送实时消息,所有订阅该通道的ws客户端都将会收到消息。| 功能 | json格式 |
|---|---|
| 登录 | {“op”:“auth”,“token”:“***”} |
| 订阅用户消息 | {“op”:“subscribe”,“channel”:“@user”} |
| 取消用户消息 | {“op”:“unsubscribe”,“channel”:“@user”} |
| 用户消息事件 | {“event”:“@user”,“data”:{“uid”:1001,“msg”:“Hello,World!”}} |
| 成功 | {“result”:true} |
| 错误 | {“code”:1,“msg”:“Error”} |
在 connmix.yaml 配置文件的 options 选项,修改websocket的url路径
options:
- name: path
value: /message-center
修改 entry.websocket.lua 的 on_message 方法如下:
auth_url 接口通过token获取到uid,并保存到context中function on_message(msg)
--print(msg)
if msg["type"] ~= "text" then
conn:close()
return
end
local auth_url = "http://127.0.0.1:8000/websocket_auth" --填写解析token的api接口地址
local conn = mix.websocket()
local data, err = mix.json_decode(msg["data"])
if err then
mix_log(mix_DEBUG, "json_decode error: " .. err)
conn:close()
return
end
local op = data["op"]
local channel_raw = data["channel"]
local channel_table = mix.str_split(channel_raw, "@")
if table.getn(channel_table) ~= 2 then
mix_log(mix_DEBUG, "invalid channel: " .. channel_raw)
conn:close()
return
end
local channel_type = channel_table[2]
if op == "auth" then
local token = data["token"]
local resp, err = mix.http.request("POST", auth_url, {
body = '{"token:"' .. token .. '"}'
})
if err then
mix_log(mix_DEBUG, "http.request error: " .. err)
conn:close()
return
end
if resp.status_code ~= 200 then
mix_log(mix_DEBUG, "http.request status_code: " .. resp["status_code"])
conn:close()
return
end
local body_table, err = mix.json_decode(resp["body"])
if err then
mix_log(mix_DEBUG, "json_decode error: " .. err)
conn:close()
return
end
conn:set_context_value("uid", body_table["uid"])
return
end
local uid = conn:context_value("uid")
if op == "subscribe" and channel_type == "user" then
if uid == nil then
conn:send('{"code":1,"msg":"Not Auth"}')
return
end
local err = conn:subscribe("user:" .. uid)
if err then
mix_log(mix_DEBUG, "subscribe error: " .. err)
conn:close()
return
end
end
if op == "unsubscribe" and channel_type == "user" then
if uid == nil then
conn:send('{"code":1,"msg":"Not Auth"}')
return
end
local err = conn:unsubscribe("user:" .. uid)
if err then
mix_log(mix_DEBUG, "unsubscribe error: " .. err)
conn:close()
return
end
end
conn:send('{"result":true}')
end
在现有系统的框架中编写一个登录信息验证接口 /websocket_auth,用于ws登录获取用户uid
{"token":"***"}
{"uid":1001}
在现有系统的框架中实现主动消息推送
curl --request POST 'http://127.0.0.1:6789/v1/mesh/publish' \
--header 'Content-Type: application/json' \
--data-raw '{
"c": "user:1001",
"d": "{\"event\":\"@user\",\"data\":{\"uid\":1001,\"msg\":\"Hello,World!\"}}"
}'
使用 wstool 进行测试
ws://127.0.0.1:6790/message-center{"op":"auth","token":"***"}{"result":true}{"op":"subscribe","channel":"@user"}{"result":true}{"event":"@user","data":{"uid":1001,"msg":"Hello,World!"}}