使用WebSocket製作一個單機版彈幕系統非常簡單,但是當單機效能達到瓶頸,需要擴充套件為叢集部署時就會面臨很多分散式問題,使用CONNMIX則無需擔心這些問題,很少的程式碼即可完成一個高效能分散式WebSocket叢集。
要求
- connmix >= v1.0.4
設計思路
- 客戶端在ws連線成功後,訂閱一個影片ID的通道
video:<videoid>
- 在傳送彈幕的介面中,呼叫connmix任意節點的
/v1/mesh/publish
介面往對應video_id
傳送實時彈幕,所有訂閱該通道的ws客戶端都將會收到訊息。 - 以上都是增量推送設計,全量通常都是在頁面載入時透過一個全量api介面獲取。
互動協議設計
- 當使用者傳送 100001@video 我們在 lua 程式碼中就執行訂閱 video:100001 通道。
- 前端切換影片時,可先傳送取消彈幕訊息,然後傳送新的訂閱彈幕訊息。
功能 | json格式 |
---|---|
訂閱彈幕 | {“op”:”subscribe”,”channel”:”100001@video”} |
取消彈幕 | {“op”:”unsubscribe”,”channel”:”100001@video”} |
彈幕事件 | {“event”:”@video”,”data”:{“uid”:1001,”video_id”:100001,”msg”:”Hello,World!”}} |
成功 | {“result”:true} |
錯誤 | {“code”:1,”msg”:”Error”} |
安裝引擎
修改配置
在 connmix.yaml
配置檔案的 options
選項,修改websocket的url路徑
options:
- name: path
value: /barrage-videos
CONNMIX 編碼
修改 entry.websocket.lua
的 on_message
方法如下:
- 當接受到subscribe、unsubscribe訊息時,執行訂閱/取消訂閱對應的通道
function on_message(msg)
--print(msg)
if msg["type"] ~= "text" then
conn:close()
return
end
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 video_id = channel_table[1] --Lua的table索引預設從1開始
local channel_type = channel_table[2]
if op == "subscribe" and channel_type == "video" then
local err = conn:subscribe("video:" .. video_id)
if err then
mix_log(mix_DEBUG, "subscribe error: " .. err)
conn:close()
return
end
end
if op == "unsubscribe" and channel_type == "video" then
local err = conn:unsubscribe("video:" .. video_id)
if err then
mix_log(mix_DEBUG, "unsubscribe error: " .. err)
conn:close()
return
end
end
conn:send('{"result":true}')
end
API 編碼
接下來在現有系統的框架中實現主動彈幕推送
- 可以在 spring、laravel 框架中寫一個傳送彈幕介面
- 該介面中驗證完使用者身份後,執行以下http請求完成推送
- 如果傳送請求非常頻繁,可以改用 websocket-api推送 提升效能
curl --request POST 'http://127.0.0.1:6789/v1/mesh/publish' \
--header 'Content-Type: application/json' \
--data-raw '{
"c": "video:100001",
"d": "{\"event\":\"@video\",\"data\":{\"uid\":1001,\"video_id\":100001,\"msg\":\"Hello,World!\"}}"
}'
測試
使用 wstool 進行測試
- 連線
ws://127.0.0.1:6790/barrage-videos
- 傳送
{"op":"subscribe","channel":"100001@video"}
- 接收到
{"result":true}
- 執行 curl 主動推送
- 接收到
{"event":"@video","data":{"uid":1001,"video_id":100001,"msg":"Hello,World!"}}
本作品採用《CC 協議》,轉載必須註明作者和本文連結