前言
在openedge-hub模块启动源码浅析——百度BIE边缘侧openedge项目源码阅读(1)一文中浅析了openedge-hub模块的启动过程,openedge-hub为每一个连接的请求创建一个实体——session,这个实体负责创建后会话的处理(这部分代码位于openedge/openedge-hub/session/session_handle.go),比如说处理连接、发布、发布确认、订阅、取消订阅、断开连接等请求,下面分别进行解析。
预处理
当接收到来自客户端的连接请求后,openedge-hub底层依赖的gomqtt库为其创建了一个连接,openedge-hub在其之上封装了session及其session相关的操作。
在创建了session后,还需要进行如下处理如下代码:
pkt, err = s.conn.Receive()
if err != nil {
if !s.tomb.Alive() {
return
}
s.log.WithError(err).Warnf("failed to reveive message")
s.close(true)
return
}
if _, ok := pkt.(*packet.Connect); !ok && s.authorizer == nil {
s.log.Errorf("only connect packet allowed before auth")
s.close(true)
return
}
这段代码是位于session_handle中的Handle方法中,也是后续所有种类packet处理逻辑的入口,主要是通过阻塞接收请求,并看一下这个会话有没有授权,代码中也有显示,只有Connect类型的请求才可以不需要授权,其他必须要求授权。
Connect处理
处理连接的入口是Handle方法的如下部分:
func (s *session) Handle() {
···
for {
pkt, err = s.conn.Receive()
···
switch p := pkt.(type) {
case *packet.Connect:
s.log.Debugln("received:", p.Type())
err = s.onConnect(p)
···
}
}
}
再继续看onConnect方法:
func (s *session) onConnect(p *packet.Connect) error {
···
authorizer := s.manager.auth.AuthenticateAccount(p.Username, p.Password)
if authorizer == nil {
s.sendConnack(packet.BadUsernameOrPassword)
return fmt.Errorf("username (%s) or password not permitted", p.Username)
}
s.authorizer = authorizer
p.Will != nil {
//处理一下will中的publish是否允许,与onPublish逻辑差不多,后面讲
···
}
var err error
s.clientID = p.ClientID
s.clean = p.CleanSession
if p.ClientID == "" {
s.id = common.PrefixTmp + uuid.Generate().String()
s.clean = true
} else {
s.id = common.PrefixSess + p.ClientID
}
err = s.manager.register(s)
···
err = s.sendConnack(packet.ConnectionAccepted)
if err != nil {
return err
}
err = s.manager.rules.StartRule(s.id)
···
return nil
}
这段代码分为三个部分,第一部分进行验证授权,第二个部分是向sessionManager和ruleManager注册(ruleManager注册的过程包括在sessionManager中),第三部分就是向客户端返回连接成功并开启rule。
第一部分:验证授权
在sessionManager进行初始化的时候,曾经创建过一个Auth对象,这个对象保存了用户名、密码、以及对应每个用户的发布、订阅的权限,AuthenticateAccount方法就是根据用户名、密码验证是不是正确,并返回相应的authorizer:
// AuthenticateAccount auth client account, then return authorizer if pass
func (a *Auth) AuthenticateAccount(username, password string) *Authorizer {
_account, ok := a.accounts[username]
if ok