WebSocket User Message Center
Using websocket as a message center is usually implemented with middleware such as kafka and redis. Using CONNMIX does not need to use middleware, and the distributed cluster capability does not need to worry about performance problems caused by a large increase in the number of users.
Require
- connmix >= v1.0.4
Design ideas
- The client sends a message to log in after the ws connection is successful, uses lua to call the business api interface to parse the uid in the login token data, and then saves the uid in the connection context.
- After the login is successful, send a message to subscribe to a channel with a user ID
user:<uid>
, and the uid is taken from the context. - In the interface for sending user messages, call the
/v1/mesh/publish
interface of any node in connmix to the correspondinguid
to send real-time messages, and all ws clients that subscribe to the channel will receive the message. - The above are all incremental push designs, and the full amount is usually obtained through a full amount api interface when the page is loaded.
Interactive protocol design
- You must be logged in to subscribe, unsubscribe
- When the user sends @user we do subscribing to the user:\<uid\> channel in the lua code.
Function | json format |
---|---|
Log in | {"op":"auth","token":" * "} |
Subscribe to user news | {"op":"subscribe","channel":"@user"} |
Cancel user message | {"op":"unsubscribe","channel":"@user"} |
User message events | {"event":"@user","data":{"uid":1001,"msg":"Hello,World!"}} |
success | {"result":true} |
mistake | {"code":1,"msg":"Error"} |
Install the engine
Change setting
In the connmix.yaml
configuration file options
option, modify the url path of the websocket
options:
- name: path
value: /message-center
CONNMIX encoding
Modify the entry.websocket.lua
on_message
method of ---98978f813922f9382ac7c73f71f49333--- as follows:
- When the message is of auth type, call
auth_url
interface to get the uid through the token and save it to the context - When the message is subscribe or unsubscribe, the uid is taken out from the context, and the channel corresponding to the subscription/unsubscription is executed.
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
API encoding
Write a login information verification interface in the framework of the existing system /websocket_auth
for ws login to obtain user uid
- Interface input parameter: token
{"token":"***"}
- Interface output parameter: uid
{"uid":1001}
Implement proactive message push in the framework of existing systems
- You can write an interface for sending user messages in spring and laravel frameworks
- After verifying the user's identity in this interface, execute the following http request to complete the push
- If sending requests are very frequent, you can use websocket-api push instead to improve performance
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!\"}}"
}'
test
Test with wstool
- connect
ws://127.0.0.1:6790/message-center
- send
{"op":"auth","token":"***"}
- Received
{"result":true}
- send
{"op":"subscribe","channel":"@user"}
- Received
{"result":true}
- Execute curl active push
- Received
{"event":"@user","data":{"uid":1001,"msg":"Hello,World!"}}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。