package netlib import ( "errors" "math" "time" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/module" "mongo.games.com/goserver/core/utils" ) const ( IoServiceMaxCount int = 10 ) var ( NetModule = newNetEngine() ) type NetEngine struct { pool map[int]ioService childAck chan int backlogSc chan *SessionConfig quit bool reaped bool } func newNetEngine() *NetEngine { e := &NetEngine{ pool: make(map[int]ioService), childAck: make(chan int, IoServiceMaxCount), backlogSc: make(chan *SessionConfig, IoServiceMaxCount), } return e } func (e *NetEngine) newIoService(sc *SessionConfig) ioService { var s ioService if sc.IsClient { if !sc.AllowMultiConn && ConnectorMgr.IsConnecting(sc) { return nil } switch sc.Protocol { case "ws", "wss": s = newWsConnector(e, sc) case "udp": s = newUdpConnector(e, sc) default: s = newTcpConnector(e, sc) } } else { switch sc.Protocol { case "ws", "wss": s = newWsAcceptor(e, sc) case "udp": s = newUdpAcceptor(e, sc) default: s = newTcpAcceptor(e, sc) } } return s } func (e *NetEngine) GetAcceptors() []Acceptor { acceptors := make([]Acceptor, 0, len(e.pool)) for _, v := range e.pool { if a, is := v.(Acceptor); is { acceptors = append(acceptors, a) } } return acceptors } func (e *NetEngine) Connect(sc *SessionConfig) error { if e.quit { return errors.New("NetEngine already quiting") } SendStartNetIoService(sc) return nil } func (e *NetEngine) Listen(sc *SessionConfig) error { if e.quit { return errors.New("NetEngine already quiting") } SendStartNetIoService(sc) return nil } func (e *NetEngine) ShutConnector(ip string, port int) { for _, v := range e.pool { if c, is := v.(Connector); is { sc := c.GetSessionConfig() if sc.Ip == ip && sc.Port == port { c.shutdown() return } } } } // ////////////////////////////////////////////////////////////////// // / Module Implement [beg] // ////////////////////////////////////////////////////////////////// func (e *NetEngine) ModuleName() string { return module.ModuleName_Net } func (e *NetEngine) Init() { var err error for i := 0; i < len(Config.IoServices); i++ { s := e.newIoService(&Config.IoServices[i]) if s != nil { e.pool[Config.IoServices[i].Id] = s err = s.start() if err != nil { logger.Logger.Error(err) } } } //time.AfterFunc(time.Minute*5, func() { e.dump() }) } func (e *NetEngine) Update() { defer utils.DumpStackIfPanic("NetEngine.Update") e.clearClosedIo() for _, v := range e.pool { v.update() } } func (e *NetEngine) Shutdown() { if e.quit { return } e.quit = true if len(e.pool) > 0 { for _, v := range e.pool { v.shutdown() } go e.reapRoutine() } else { e.destroy() } } //////////////////////////////////////////////////////////////////// /// Module Implement [end] //////////////////////////////////////////////////////////////////// func (e *NetEngine) clearClosedIo() { for { select { case k := <-e.childAck: delete(e.pool, k) case sc := <-e.backlogSc: s := e.newIoService(sc) if s != nil { e.pool[sc.Id] = s err := s.start() if err != nil { logger.Logger.Error(err) } } default: return } } } func (e *NetEngine) reapRoutine() { if e.reaped { return } e.reaped = true for { select { case k := <-e.childAck: delete(e.pool, k) if len(e.pool) == 0 { e.destroy() return } } } } func (e *NetEngine) destroy() { module.UnregisteModule(e) } func (e *NetEngine) dump() { for _, v := range e.pool { v.dump() } time.AfterFunc(time.Minute*5, func() { e.dump() }) } func (e *NetEngine) stats() map[int]ServiceStats { stats := make(map[int]ServiceStats) for k, v := range e.pool { s := v.stats() stats[k] = s } return stats } func init() { module.RegisteModule(NetModule, 0, math.MaxInt32) } func Connect(sc *SessionConfig) error { return NetModule.Connect(sc) } func Listen(sc *SessionConfig) error { return NetModule.Listen(sc) } func GetAcceptors() []Acceptor { return NetModule.GetAcceptors() } func ShutConnector(ip string, port int) { NetModule.ShutConnector(ip, port) } func Stats() map[int]ServiceStats { return NetModule.stats() }