//实现了Module接口的Run方法并提供了: //1.ChanRPC(用于模块间交互) //2.Command ChanRPC(用于提供命令服务) //3.Go(避免操作阻塞当前goroutine) //4.timer(用于定时器) func (s *Skeleton) Run(closeSig chan bool) { for { //死循环 select { case <-closeSig: //读取关闭信号 s.commandServer.Close() //关闭命令rpc服务器 s.server.Close() //关闭rpc服务器 s.g.Close() //关闭Go return case ci := <-s.server.ChanCall: //从rpc服务器读取调用信息 err := s.server.Exec(ci) //执行调用 if err != nil { log.Error("%v", err) } case ci := <-s.commandServer.ChanCall: //从命令rpc服务器读取调用信息 err := s.commandServer.Exec(ci) //执行命令调用 if err != nil { log.Error("%v", err) } case cb := <-s.g.ChanCb: //从Go的回调管道中读取回调函数 s.g.Cb(cb) //执行回调函数(不用自己写 d.Cb(<-d.ChanCb)了 ) case t := <-s.dispatcher.ChanTimer: //从分发器中读取到时定时器 t.Cb() //执行定时器回调 } } }
func execCb(ri *RetInfo) { defer func() { if r := recover(); r != nil { if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) } } }() // execute switch ri.cb.(type) { case func(error): ri.cb.(func(error))(ri.err) case func(interface{}, error): ri.cb.(func(interface{}, error))(ri.ret, ri.err) case func([]interface{}, error): ri.cb.(func([]interface{}, error))(assert(ri.ret), ri.err) default: panic("bug") } return }
func (s *Skeleton) Run(closeSig chan bool) { for { select { case <-closeSig: s.commandServer.Close() s.server.Close() s.g.Close() return case ci := <-s.server.ChanCall: err := s.server.Exec(ci) if err != nil { log.Error("%v", err) } case ci := <-s.commandServer.ChanCall: err := s.commandServer.Exec(ci) if err != nil { log.Error("%v", err) } case cb := <-s.g.ChanCb: s.g.Cb(cb) case t := <-s.dispatcher.ChanTimer: t.Cb() } } }
func (c *LinearContext) Go(f func(), cb func()) { c.g.pendingGo++ c.mutexLinearGo.Lock() c.linearGo.PushBack(&LinearGo{f: f, cb: cb}) c.mutexLinearGo.Unlock() go func() { c.mutexExecution.Lock() defer c.mutexExecution.Unlock() c.mutexLinearGo.Lock() e := c.linearGo.Remove(c.linearGo.Front()).(*LinearGo) c.mutexLinearGo.Unlock() defer func() { c.g.ChanCb <- e.cb if r := recover(); r != nil { if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) } } }() e.f() }() }
//线性上下文的Go函数 func (c *LinearContext) Go(f func(), cb func()) { c.g.pendingGo++ //增加待处理回调函数计数器 c.mutexLinearGo.Lock() //链表加锁 c.linearGo.PushBack(&LinearGo{f: f, cb: cb}) //向链表添加元素 c.mutexLinearGo.Unlock() //链表解锁 go func() { //在新的goroutine中执行 c.mutexExecution.Lock() //执行加锁,后来的Go将会阻塞在这里,直到该Go执行完成 defer c.mutexExecution.Unlock() //延迟 执行解锁 c.mutexLinearGo.Lock() //链表加锁 e := c.linearGo.Remove(c.linearGo.Front()).(*LinearGo) //从表头移出一个元素 c.mutexLinearGo.Unlock() //链表解锁 defer func() { c.g.ChanCb <- e.cb //当f执行完成后,将回调发送到回调管道中 //捕获异常 if r := recover(); r != nil { if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) } } }() e.f() //执行函数 }() }
func (a *agent) WriteMsg(msg interface{}) { if a.gate.JSONProcessor != nil { // json data, err := a.gate.JSONProcessor.Marshal(msg) if err != nil { log.Error("marshal json %v error: %v", reflect.TypeOf(msg), err) return } if a.wsConn != nil { a.wsConn.WriteMsg(data) } else if a.tcpConn != nil { a.tcpConn.WriteMsg(data) } } else if a.gate.ProtobufProcessor != nil { // protobuf id, data, err := a.gate.ProtobufProcessor.Marshal(msg.(proto.Message)) if err != nil { log.Error("marshal protobuf %v error: %v", reflect.TypeOf(msg), err) return } if a.wsConn != nil { b := make([]byte, len(id)+len(data)) copy(b, id) copy(b[len(id):], data) a.wsConn.WriteMsg(b) } else if a.tcpConn != nil { a.tcpConn.WriteMsg(id, data) } } }
func (a *agent) WriteMsg(msg interface{}) { if a.gate.Processor != nil { data, err := a.gate.Processor.Marshal(msg) if err != nil { log.Error("marshal message %v error: %v", reflect.TypeOf(msg), err) return } err = a.conn.WriteMsg(data...) if err != nil { log.Error("write message %v error: %v", reflect.TypeOf(msg), err) } } }
func (user *User) login(accID string) { userData := new(UserData) skeleton.Go(func() { db := mongoDB.Ref() defer mongoDB.UnRef(db) // load err := db.DB("game").C("users"). Find(bson.M{"accid": accID}).One(userData) if err != nil { // unknown error if err != mgo.ErrNotFound { log.Error("load acc %v data error: %v", accID, err) userData = nil user.WriteMsg(&msg.S2C_Close{Err: msg.S2C_Close_InnerError}) user.Close() return } // new err := userData.initValue(accID) if err != nil { log.Error("init acc %v data error: %v", accID, err) userData = nil user.WriteMsg(&msg.S2C_Close{Err: msg.S2C_Close_InnerError}) user.Close() return } } }, func() { // network closed if user.state == userLogout { user.logout(accID) return } // db error user.state = userGame if userData == nil { return } // ok user.data = userData users[userData.UserID] = user user.UserData().(*AgentInfo).userID = userData.UserID user.onLogin() user.autoSaveDB() }) }
func (session *Session) login(accID int64) { userData := new(UserData) skeleton.Go(func() { user := new(model.User) user.AccId = accID has, err := model.Engine.Get(user) if err != nil { log.Error("load acc %v data error: %v", accID, err) userData = nil m := &msg.ClosePush{Code: msg.ClosePush_INNER.Enum()} session.WriteMsg(m) session.Close() return } if has { userData.User = user } else { err := userData.initValue(accID) if err != nil { log.Error("init acc %v data error: %v", accID, err) userData = nil m := &msg.ClosePush{Code: msg.ClosePush_INNER.Enum()} session.WriteMsg(m) session.Close() return } } }, func() { // network closed if session.state == Session_Logout { session.logout(accID) return } // db error session.state = Session_InGame if userData == nil { return } // ok session.data = userData userIDSessions[userData.User.Id] = session session.UserData().(*AgentInfo).userID = userData.User.Id session.onLogin() session.autoSaveDB() }) }
func destroy(m *module) { defer func() { if r := recover(); r != nil { if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) } } }() m.mi.OnDestroy() }
//销毁模块 func destroy(m *module) { defer func() { //延迟执行 if r := recover(); r != nil { //捕获异常 if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) //创建一个字节切片用于存储格式化后的stack trace l := runtime.Stack(buf, false) //格式化调用Stack函数的goroutine的stack trace log.Error("%v: %s", r, buf[:l]) //打印错误消息和stack trace } else { log.Error("%v", r) //只打印错误消息 } } }() m.mi.OnDestroy() //先调用模块的销毁函数,再执行上面的延迟函数 }
func (session *Session) logout(accID int64) { if session.data != nil { session.saveDBTimer.Stop() session.onLogout() delete(userIDSessions, session.data.User.Id) } // save data := util.DeepClone(session.data) session.Go(func() { if data != nil { //db := mongoDB.Ref() //defer mongoDB.UnRef(db) // userID := data.(*UserData).UserID // _, err := db.DB("game").C("users"). // UpsertId(userID, data) //err := data.(*UserData).saveDB() err := session.data.saveDB() if err != nil { log.Error("save user %v data error: %v", session.data.User.Id, err) } } }, func() { delete(accIDSessions, accID) }) }
func (a *TCPAgent) OnClose() { if a.gate.AgentChanRPC != nil { err := a.gate.AgentChanRPC.Open(0).Call0("CloseAgent", a) if err != nil { log.Error("chanrpc error: %v", err) } } }
func (g *Go) Cb(cb func()) { defer func() { g.pendingGo-- if r := recover(); r != nil { if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) } } }() if cb != nil { cb() } }
func (t *Timer) Cb() { defer func() { t.cb = nil if r := recover(); r != nil { if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) } } }() if t.cb != nil { t.cb() } }
//执行回调函数 func (g *Go) Cb(cb func()) { defer func() { g.pendingGo-- //处理完一个,减少待处理回调函数计数器 //异常处理 if r := recover(); r != nil { if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) } } }() if cb != nil { //如果回调函数不为空 cb() //执行回调函数 } }
//调用定时器的回调函数 func (t *Timer) Cb() { defer func() { //延迟执行 t.cb = nil //置空回调 if r := recover(); r != nil { //捕获异常 if conf.LenStackBuf > 0 { //堆栈buf长度大于0 //打印堆栈信息 buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) //打印异常 } } }() //回调不为空 if t.cb != nil { t.cb() //调用回调 } }
//实现代理接口(gate.Agent)WriteMsg函数 //发送消息 func (a *TCPAgent) WriteMsg(msg interface{}) { if a.gate.JSONProcessor != nil { //使用JSON处理器 // json data, err := a.gate.JSONProcessor.Marshal(msg) //编码JSON消息。消息id存储在data内,直接发送就好了 if err != nil { log.Error("marshal json %v error: %v", reflect.TypeOf(msg), err) return } a.conn.WriteMsg(data) //发送消息 } else if a.gate.ProtobufProcessor != nil { //使用protobuf处理器 // protobuf id, data, err := a.gate.ProtobufProcessor.Marshal(msg.(proto.Message)) //编码protobuf消息。消息id是返回的,需要和data一起发送到客户端 if err != nil { log.Error("marshal protobuf %v error: %v", reflect.TypeOf(msg), err) return } a.conn.WriteMsg(id, data) //发送消息 } }
// goroutine safe func (c *DialContext) Close() { c.Lock() for _, s := range c.sessions { s.Close() if s.ref != 0 { log.Error("session ref = %v", s.ref) } } c.Unlock() }
func (a *TCPAgent) WriteMsg(msg interface{}) { if a.gate.JSONProcessor != nil { // json data, err := a.gate.JSONProcessor.Marshal(msg) if err != nil { log.Error("marshal json %v error: %v", reflect.TypeOf(msg), err) return } a.conn.WriteMsg(data) } else if a.gate.ProtobufProcessor != nil { // protobuf id, data, err := a.gate.ProtobufProcessor.Marshal(msg.(proto.Message)) if err != nil { log.Error("marshal protobuf %v error: %v", reflect.TypeOf(msg), err) return } a.conn.WriteMsg(id, data) } }
func (g *Go) Go(f func(), cb func()) { g.pendingGo++ go func() { defer func() { g.ChanCb <- cb if r := recover(); r != nil { if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) } } }() f() }() }
//一般的Go函数 //执行一个比较耗时的操作,并在执行完成后,将回调函数通过回调管道发送回原goroutine执行 func (g *Go) Go(f func(), cb func()) { g.pendingGo++ //增加待处理回调函数计数器 go func() { //在一个新的goroutine内执行 defer func() { //在f执行完后执行 g.ChanCb <- cb //发送回调函数到回调管道中 //异常处理 if r := recover(); r != nil { if conf.LenStackBuf > 0 { buf := make([]byte, conf.LenStackBuf) l := runtime.Stack(buf, false) log.Error("%v: %s", r, buf[:l]) } else { log.Error("%v", r) } } }() f() //在新的gouroutine执行f(比如一个很耗时的操作) }() }
func (p *RoomManager) Leave(id int, name string) error { room, err := p.whereAmI(name) if err != nil { return errors.New("you are not in any room") } if room.id != id { return errors.New("you are not in this room") } p.Lock() defer p.Unlock() room.players.Remove(name) log.Error("player %s removed", name) return nil }
func (data *UserData) saveDB() error { //save User id := data.User.Id affected, err := model.Engine.Id(id).AllCols().Omit("Id", "AccId").Update(data.User) if err != nil { return fmt.Errorf("save db error: %v", err) } if affected != 1 { log.Error("%v", "save db no affect,may be an error") } else { log.Release("%v", "save db ok") } return nil }
//运行TCP服务器 func (server *TCPServer) run() { for { //死循环 conn, err := server.ln.Accept() //接受一个连接 if err != nil { //如果有错(如果调用了server.Close,再Accept,那么就会出错) if server.closeFlag { //服务器关闭标志为true 因为关闭了TCP服务器导致的出错 return //结束循环 } else { log.Error("accept error: %v", err) //日志记录接受连接出错 continue //继续循环 } } server.mutexConns.Lock() //加锁,为什么要加锁,因为会从不同的goroutine中访问server.conns,比如从外部goroutine中调用server.Close或者在新的goroutine中运行代理执行清理工作的时候或者当前for循环所在goroutine中增加连接记录 if len(server.conns) >= server.MaxConnNum { //如果当前连接数超过上限 server.mutexConns.Unlock() //解锁 conn.Close() //关闭新来的连接 log.Debug("too many connections") //日志记录:太多连接了 continue //继续循环 } //增加连接记录 server.conns[conn] = struct{}{} //struct{}为类型,第二个{}为初始化,只不过是空值而已 server.mutexConns.Unlock() //解锁 server.wg.Add(1) //等待组+1 tcpConn := newTCPConn(conn, server.PendingWriteNum, server.msgParser) //创建一个TCP连接(原有net.Conn的封装) agent := server.NewAgent(tcpConn) //调用注册的创建代理函数创建代理 go func() { //此处形成闭包 agent.Run() //在一个新的goroutine中运行代理,一个客户端一个agent //执行到这里时agent.Run for循环结束 // cleanup //清理工作 tcpConn.Close() //关闭连接(封装层) server.mutexConns.Lock() //加锁 delete(server.conns, conn) //从连接集合中删除连接 server.mutexConns.Unlock() //解锁 agent.OnClose() //关闭代理 server.wg.Done() //等待组-1 }() } }
func (user *User) autoSaveDB() { const duration = 5 * time.Minute // save user.saveDBTimer = skeleton.AfterFunc(duration, func() { data := util.DeepClone(user.data) user.Go(func() { db := mongoDB.Ref() defer mongoDB.UnRef(db) userID := data.(*UserData).UserID _, err := db.DB("game").C("users"). UpsertId(userID, data) if err != nil { log.Error("save user %v data error: %v", userID, err) } }, func() { user.autoSaveDB() }) }) }
func (session *Session) autoSaveDB() { const duration = 5 * time.Minute // save session.saveDBTimer = skeleton.AfterFunc(duration, func() { data := util.DeepClone(session.data) session.Go(func() { //db := mongoDB.Ref() //defer mongoDB.UnRef(db) // userID := data.(*UserData).UserID // _, err := db.DB("game").C("users"). // UpsertId(userID, data) err := data.(*UserData).saveDB() if err != nil { log.Error("save user %v data error: %v", session.data.User.Id, err) } }, func() { session.autoSaveDB() }) }) }
func handleRegister(args []interface{}) { m := args[0].(*msg.RegisterReq) a := args[1].(gate.Agent) log.Debug("%v", m, a) account := new(model.Account) account.Name = m.GetName() account.Password = m.GetPassword() affected, err := model.Engine.Insert(account) if err != nil { //所有错误都返回用户名已存在 log.Error("%v", err) a.WriteMsg(&msg.RegisterRes{Code: msg.RegisterRes_EXIST.Enum()}) return } log.Debug("%v", affected) if affected == 1 { a.WriteMsg(&msg.RegisterRes{Code: msg.RegisterRes_YES.Enum()}) } else { a.WriteMsg(&msg.RegisterRes{Code: msg.RegisterRes_NO.Enum()}) } }
func (server *TCPServer) run() { for { conn, err := server.ln.Accept() if err != nil { if server.closeFlag { return } else { log.Error("accept error: %v", err) continue } } server.mutexConns.Lock() if len(server.conns) >= server.MaxConnNum { server.mutexConns.Unlock() conn.Close() log.Debug("too many connections") continue } server.conns[conn] = struct{}{} server.mutexConns.Unlock() server.wg.Add(1) tcpConn := newTCPConn(conn, server.PendingWriteNum, server.msgParser) agent := server.NewAgent(tcpConn) go func() { agent.Run() // cleanup tcpConn.Close() server.mutexConns.Lock() delete(server.conns, conn) server.mutexConns.Unlock() agent.OnClose() server.wg.Done() }() } }
func Example() { name := "Leaf" log.Debug("My name is %v", name) log.Release("My name is %v", name) log.Error("My name is %v", name) // log.Fatal("My name is %v", name) logger, err := log.New("release", "") if err != nil { return } defer logger.Close() logger.Debug("will not print") logger.Release("My name is %v", name) log.Export(logger) log.Debug("will not print") log.Release("My name is %v", name) }