liangdas / mqant

mqant是一款基于Golang语言的简洁,高效,高性能的分布式微服务框架

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

内置GateHandler Bind函数逻辑修改建议

youngpto opened this issue · comments

issue:执行156行会产生nil pointer panic
branch:master
runtime: go1.12+
复现流程:内置的ClientAgent实现确保了session不为空且无置nil操作所以不会触发,通过SetCreateAgent函数自定义ClientAgent并在调用Bind函数前对session置空则稳定复现
修改建议:此处设计上是对新连接的session同步持久化数据,不应该有空session的存在,抛出异常会更恰当

func (h *handler) Bind(span log.TraceSpan, Sessionid string, Userid string) (result gate.Session, err string) {
agent, ok := h.sessions.Load(Sessionid)
if !ok || agent == nil {
err = "No Sesssion found"
return
}
agent.(gate.Agent).GetSession().SetUserID(Userid)
if h.gate.GetStorageHandler() != nil && agent.(gate.Agent).GetSession().GetUserID() != "" {
//可以持久化
data, err := h.gate.GetStorageHandler().Query(Userid)
if err == nil && data != nil {
//有已持久化的数据,可能是上一次连接保存的
impSession, err := h.gate.NewSession(data)
if err == nil {
if agent.(gate.Agent).GetSession() == nil {
agent.(gate.Agent).GetSession().SetSettings(impSession.CloneSettings())
} else {
//合并两个map 并且以 agent.(Agent).GetSession().Settings 已有的优先
settings := impSession.CloneSettings()
_ = agent.(gate.Agent).GetSession().ImportSettings(settings)
}
} else {
//解析持久化数据失败
log.Warning("Sesssion Resolve fail %s", err.Error())
}
}
//数据持久化
_ = h.gate.GetStorageHandler().Storage(agent.(gate.Agent).GetSession())
}
result = agent.(gate.Agent).GetSession()
return
}

还有文档好像很久没有更新了,Gate模块对StorageHandler的介绍几乎没有,需要自行研究代码,比如此处153行的使用到的data是由使用者自定义的StorageHandler返回的,此处文档没有说明StorageHandler返回[]byte该遵守什么约定或者需要额外做什么处理,看了默认的NewSession实现才能发现需要把data解码为proto.SessionImp类型。

您说的那个nil pointer panic我没太看明白,那个地方有做nil判断呀?
第二个问题StorageHandler序列化方式完全由开发者选择,所以[]byte不用遵循什么规范,按开发者自己的规范序列化和反序列化就行

第一个问题我觉得通过155行也可以看出此处判断的是为空的时候还调用了这个空指针,只是正常情况下不会触发这个case,所以这个判空其实是没有意义的,并且可以看到整个方法体内是默认GetSession不为空的比如说一开始就调用了SetUserID这个方法。
第二个问题可能是我描述的有些问题,StorageHandler内部如何存储数据确实是开发者自己定义结构就可以的,但是Query这个方法在上面代码块的150行也被调用,而后这个data被传入NewSession方法。

确实默认的Agent实现方法NewMqttAgent,确保了客户端连接后就初始化了session,所以不会出现nil,如果是自己实现的Agent也得遵循这个逻辑

第一个问题我觉得通过155行也可以看出此处判断的是为空的时候还调用了这个空指针,只是正常情况下不会触发这个case,所以这个判空其实是没有意义的,并且可以看到整个方法体内是默认GetSession不为空的比如说一开始就调用了SetUserID这个方法。 第二个问题可能是我描述的有些问题,StorageHandler内部如何存储数据确实是开发者自己定义结构就可以的,但是Query这个方法在上面代码块的150行也被调用,而后这个data被传入NewSession方法。

确实会有这个问题,session必须有序列化规范,不过可以用session.Serializable() ([]byte, error) 来解决session序列化问题,别自己去序列化

确实会有这个问题,session必须有序列化规范,不过可以用session.Serializable() ([]byte, error) 来解决session序列化问题,别自己去序列化

是的,这是一种比较好的方案,两个问题其实都可以总结为文档没有明确指出一些约定俗成的规范,框架功能多是一件好事配套的文档如果更完善一些就更好了,感谢作者持续跟进。