记录link包的重构(2)
今天又对link包得API做了一次重构,这次重构的目的是提升Session和Server类型的API灵活性。
我们先来看重构之前link包的唯一用法:
server.Handle(func(session *Session) {
fmt.Println("session start")
session.OnMessage(func(session *Session, msg []byte) {
fmt.Printf("new message: %s\n", msg)
})
session.OnClose(func(session *Session, reason error) {
fmt.Println("session closed")
})
session.Start()
})
上一个版本的API设计有以下几个问题:
- Server不能可控的Accept,比如Accept特定的连接数之后就暂停Accept
- Session不能可控的接收消息,比如实现某种握手协议时需要顺序收发N个消息包,异步结构的代码没有顺序结构的清晰
因此我对Session和Server的API做了以下修改:
- Server中添加了Accept方法,每次调用只返回一个新Session,就像Listener的Accept那样。
- Session中添加了Read方法,每次调用只返回一个消息,就像Conn的Read那样,配合SyncSend就可以实现顺序收发。
这两个方法一开始是直接替代了Handle和OnMessage,导致link包的用法变成这样:
for {
session, err := server.Accept()
if err != nil {
break
}
go func() {
fmt.Println("session start")
for {
msg := session.Read()
if msg == nil {
break
}
fmt.Printf("new message: %s\n", msg)
}
fmt.Println("session closed")
}()
}
API变得原始很多,看起来没之前那么方便了。
于是我又给Server和Session加上了两个方法,AcceptLoop和ReadLoop,但是比之前的结构简化一些,Session不需要OnClose事件回调了。
server.AcceptLoop(func(session *Session) {
fmt.Println("session start")
session.ReadLoop(func(_ *Session, msg []byte) {
fmt.Printf("new message: %s\n", msg)
})
fmt.Println("session closed")
})
AcceptLoop在接收到新连接时会创建一个新的goroutine执行回调函数,所以这个回调函数就可以作为session处理消息的循环使用,ReadLoop会一直循环进行Read,就像第二段代码中那样。
经过这次重构,link就可以像之前一样用,又可以在需要的时候进行精细控制。