Hub
Landscape
- Server 中 Hub 数量为 CPU * 2
- register,unregister 应该用于连接接入或断开
- broadcast 用于事件通知,可能包含广播消息、用户进入或退出 Channel、Team
Connection
hubConnectionIndex 位于每一个 Hub 处理协程中,Hub 并不直接包含它。代码概要如下
func (h *Hub) Start() {
var doStart func()
var doRecoverableStart func()
var doRecover func()
doStart = func() {
// ...
connections := newHubConnectionIndex()
for {
// ...
}
}
doRecoverableStart = func() {
defer doRecover()
doStart()
}
doRecover = func() {
if !h.ExplicitStop {
// ...
go doRecoverableStart()
}
}
go doRecoverableStart()
}
Add Connection
Remove Connection
黄色线表示当 UserID 的最后一个 WebConn 在 Hub 中被移除后的处理。需要通过 Server 修改 Store,并向 Hub 通知有用户离线。如果存在集群,同时向集群广播,此处暂不涉及。
Broadcast
Procedure
web.Handler
web.Handler 实现了 http.Handler 接口,统一函数处理行为。web.Handler 的 ServeHTTP 方法中,实现了一般的中间件功能,实现过程如下图。
上图中,需要注意 web.Context 方法,主要作用是创建一个属于本次请求的 App 对象,App 是 Server 的功能代理,这样 Context 就包含了 Server,可以使用 Server 的功能。
如果 http.Request 中包含了 Token,说明发送请求的连接已经登陆系统,通过 App 获取 Session。无论是否登陆系统,后面都要执行 web.Handler 包含的处理方法。
Establish Connection
Login
用户登陆,通过用户名、密码或 oAuth 均可。登陆过程不做描述,登陆成功后,需要执行以下操作。
Upgrade
WebConn
Write Loop
Read Loop
Pong Timeout
func readPump() {
// ...
c.WebSocket.SetReadDeadline(time.Now().Add(PONG_WAIT))
c.WebSocket.SetPongHandler(func(string) error {
c.WebSocket.SetReadDeadline(time.Now().Add(PONG_WAIT))
if c.IsAuthenticated() {
c.App.Srv.Go(func() {
c.App.SetStatusAwayIfNeeded(c.UserId, false)
})
}
return nil
})
// ...
}