337 lines
7.8 KiB
Go
337 lines
7.8 KiB
Go
package module
|
|
|
|
import (
|
|
"container/list"
|
|
"time"
|
|
|
|
"fmt"
|
|
"mongo.games.com/goserver/core"
|
|
"mongo.games.com/goserver/core/basic"
|
|
"mongo.games.com/goserver/core/logger"
|
|
"mongo.games.com/goserver/core/profile"
|
|
"mongo.games.com/goserver/core/utils"
|
|
)
|
|
|
|
const (
|
|
///module state
|
|
ModuleStateInvalid int = iota
|
|
ModuleStateInit
|
|
ModuleStateRun
|
|
ModuleStateShutdown
|
|
ModuleStateWaitShutdown
|
|
ModuleStateFini
|
|
///other
|
|
ModuleMaxCount = 1024
|
|
)
|
|
|
|
var (
|
|
AppModule = newModuleMgr()
|
|
)
|
|
|
|
type ModuleEntity struct {
|
|
lastTick time.Time
|
|
tickInterval time.Duration
|
|
priority int
|
|
module Module
|
|
quited bool
|
|
}
|
|
|
|
type PreloadModuleEntity struct {
|
|
priority int
|
|
module PreloadModule
|
|
}
|
|
|
|
type ModuleMgr struct {
|
|
*basic.Object
|
|
modules *list.List
|
|
modulesByName map[string]*ModuleEntity
|
|
preloadModule *list.List
|
|
state int
|
|
waitShutAct chan interface{}
|
|
waitShutCnt int
|
|
waitShut bool
|
|
currTimeSec int64
|
|
currTimeNano int64
|
|
currTime time.Time
|
|
}
|
|
|
|
func newModuleMgr() *ModuleMgr {
|
|
mm := &ModuleMgr{
|
|
modules: list.New(),
|
|
preloadModule: list.New(),
|
|
modulesByName: make(map[string]*ModuleEntity),
|
|
waitShutAct: make(chan interface{}, ModuleMaxCount),
|
|
state: ModuleStateInvalid,
|
|
}
|
|
|
|
return mm
|
|
}
|
|
|
|
func (this *ModuleMgr) GetCurrTime() time.Time {
|
|
return this.currTime
|
|
}
|
|
|
|
func (this *ModuleMgr) GetCurrTimeSec() int64 {
|
|
return this.currTimeSec
|
|
}
|
|
|
|
func (this *ModuleMgr) GetCurrTimeNano() int64 {
|
|
return this.currTimeNano
|
|
}
|
|
|
|
func (this *ModuleMgr) RegisteModule(m Module, tickInterval time.Duration, priority int) {
|
|
logger.Logger.Infof("module [%16s] registe;interval=%v,priority=%v", m.ModuleName(), tickInterval, priority)
|
|
mentiry := &ModuleEntity{
|
|
lastTick: time.Now(),
|
|
tickInterval: tickInterval,
|
|
priority: priority,
|
|
module: m,
|
|
}
|
|
|
|
this.modulesByName[m.ModuleName()] = mentiry
|
|
|
|
for e := this.modules.Front(); e != nil; e = e.Next() {
|
|
if me, ok := e.Value.(*ModuleEntity); ok {
|
|
if priority < me.priority {
|
|
this.modules.InsertBefore(mentiry, e)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
this.modules.PushBack(mentiry)
|
|
}
|
|
|
|
func (this *ModuleMgr) UnregisteModule(m Module) {
|
|
for e := this.modules.Front(); e != nil; e = e.Next() {
|
|
if me, ok := e.Value.(*ModuleEntity); ok {
|
|
if me.module == m {
|
|
delete(this.modulesByName, m.ModuleName())
|
|
this.modules.Remove(e)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (this *ModuleMgr) RegistePreloadModule(m PreloadModule, priority int) {
|
|
mentiry := &PreloadModuleEntity{
|
|
priority: priority,
|
|
module: m,
|
|
}
|
|
|
|
for e := this.preloadModule.Front(); e != nil; e = e.Next() {
|
|
if me, ok := e.Value.(*PreloadModuleEntity); ok {
|
|
if priority < me.priority {
|
|
this.preloadModule.InsertBefore(mentiry, e)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
this.preloadModule.PushBack(mentiry)
|
|
}
|
|
|
|
func (this *ModuleMgr) UnregistePreloadModule(m PreloadModule) {
|
|
for e := this.preloadModule.Front(); e != nil; e = e.Next() {
|
|
if me, ok := e.Value.(*PreloadModuleEntity); ok {
|
|
if me.module == m {
|
|
this.preloadModule.Remove(e)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (this *ModuleMgr) Start() *utils.Waitor {
|
|
logger.Logger.Info("Startup PreloadModules")
|
|
for e := this.preloadModule.Front(); e != nil; e = e.Next() {
|
|
if me, ok := e.Value.(*PreloadModuleEntity); ok {
|
|
me.module.Start()
|
|
}
|
|
}
|
|
logger.Logger.Info("Startup PreloadModules [ok]")
|
|
|
|
this.Object = basic.NewObject(core.ObjId_CoreId,
|
|
"core",
|
|
Config.Options,
|
|
this)
|
|
this.UserData = this
|
|
core.LaunchChild(this.Object)
|
|
core.AppCtx.CoreObj = this.Object
|
|
this.state = ModuleStateInit
|
|
//给模块预留调度的空间,防止主线程直接跑过去
|
|
select {
|
|
case <-time.After(time.Second):
|
|
}
|
|
return this.Object.Waitor
|
|
}
|
|
|
|
func (this *ModuleMgr) Close() {
|
|
this.state = ModuleStateShutdown
|
|
}
|
|
|
|
func (this *ModuleMgr) init() {
|
|
logger.Logger.Info("Start Initialize Modules")
|
|
defer logger.Logger.Info("Start Initialize Modules [ok]")
|
|
for e := this.modules.Front(); e != nil; e = e.Next() {
|
|
if me, ok := e.Value.(*ModuleEntity); ok && !me.quited {
|
|
logger.Logger.Infof("module [%16s] init...", me.module.ModuleName())
|
|
me.safeInit()
|
|
logger.Logger.Infof("module [%16s] init[ok]", me.module.ModuleName())
|
|
}
|
|
}
|
|
this.state = ModuleStateRun
|
|
}
|
|
|
|
func (this *ModuleMgr) update() {
|
|
nowTime := time.Now()
|
|
this.currTime = nowTime
|
|
this.currTimeSec = nowTime.Unix()
|
|
this.currTimeNano = nowTime.UnixNano()
|
|
for e := this.modules.Front(); e != nil; e = e.Next() {
|
|
if me, ok := e.Value.(*ModuleEntity); ok && !me.quited {
|
|
me.safeUpt(nowTime)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (this *ModuleMgr) shutdown() {
|
|
if this.waitShut {
|
|
return
|
|
}
|
|
logger.Logger.Info("ModuleMgr shutdown()")
|
|
this.waitShut = true
|
|
this.state = ModuleStateWaitShutdown
|
|
for e := this.modules.Front(); e != nil; e = e.Next() {
|
|
if me, ok := e.Value.(*ModuleEntity); ok {
|
|
logger.Logger.Infof("module [%16s] shutdown...", me.module.ModuleName())
|
|
me.safeShutdown(this.waitShutAct)
|
|
logger.Logger.Infof("module [%16s] shutdown[ok]", me.module.ModuleName())
|
|
this.waitShutCnt++
|
|
}
|
|
}
|
|
}
|
|
|
|
func (this *ModuleMgr) checkShutdown() bool {
|
|
select {
|
|
case param := <-this.waitShutAct:
|
|
logger.Logger.Infof("module [%16s] shutdowned", param)
|
|
if name, ok := param.(string); ok {
|
|
me := this.getModuleEntityByName(name)
|
|
if me != nil && !me.quited {
|
|
me.quited = true
|
|
this.waitShutCnt--
|
|
}
|
|
}
|
|
case _ = <-time.After(time.Second):
|
|
logger.Logger.Trace("ModuleMgr.checkShutdown wait...")
|
|
for e := this.modules.Front(); e != nil; e = e.Next() {
|
|
if me, ok := e.Value.(*ModuleEntity); ok {
|
|
if me.quited == false {
|
|
logger.Logger.Infof("Module [%v] wait shutdown...", me.module.ModuleName())
|
|
}
|
|
}
|
|
}
|
|
//default:
|
|
}
|
|
if this.waitShutCnt == 0 {
|
|
this.state = ModuleStateFini
|
|
return true
|
|
}
|
|
this.update()
|
|
return false
|
|
}
|
|
|
|
func (this *ModuleMgr) tick() {
|
|
|
|
switch this.state {
|
|
case ModuleStateInit:
|
|
this.init()
|
|
case ModuleStateRun:
|
|
this.update()
|
|
case ModuleStateShutdown:
|
|
this.shutdown()
|
|
case ModuleStateWaitShutdown:
|
|
this.checkShutdown()
|
|
case ModuleStateFini:
|
|
this.fini()
|
|
}
|
|
}
|
|
|
|
func (this *ModuleMgr) fini() {
|
|
core.Terminate(this.Object)
|
|
this.state = ModuleStateInvalid
|
|
logger.Logger.Info("=============ModuleMgr fini=============")
|
|
logger.Logger.Flush()
|
|
}
|
|
|
|
func (this *ModuleMgr) getModuleEntityByName(name string) *ModuleEntity {
|
|
if me, exist := this.modulesByName[name]; exist {
|
|
return me
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (this *ModuleMgr) GetModuleByName(name string) Module {
|
|
if me, exist := this.modulesByName[name]; exist {
|
|
return me.module
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (this *ModuleEntity) safeInit() {
|
|
defer utils.DumpStackIfPanic("ModuleEntity.safeInit")
|
|
this.module.Init()
|
|
}
|
|
|
|
func (this *ModuleEntity) safeUpt(nowTime time.Time) {
|
|
defer utils.DumpStackIfPanic("ModuleEntity.safeTick")
|
|
|
|
if this.tickInterval == 0 || nowTime.Sub(this.lastTick) >= this.tickInterval {
|
|
this.lastTick = nowTime
|
|
watch := profile.TimeStatisticMgr.WatchStart(fmt.Sprintf("/module/%v/update", this.module.ModuleName()), profile.TIME_ELEMENT_MODULE)
|
|
if watch != nil {
|
|
defer watch.Stop()
|
|
}
|
|
this.module.Update()
|
|
}
|
|
}
|
|
|
|
func (this *ModuleEntity) safeShutdown(shutWaitAck chan<- interface{}) {
|
|
defer utils.DumpStackIfPanic("ModuleEntity.safeShutdown")
|
|
this.module.Shutdown()
|
|
}
|
|
|
|
func (this *ModuleMgr) OnStart() {}
|
|
func (this *ModuleMgr) OnStop() {}
|
|
func (this *ModuleMgr) OnTick() {
|
|
this.tick()
|
|
}
|
|
|
|
func RegistePreloadModule(m PreloadModule, priority int) {
|
|
AppModule.RegistePreloadModule(m, priority)
|
|
}
|
|
|
|
func RegisteModule(m Module, tickInterval time.Duration, priority int) {
|
|
AppModule.RegisteModule(m, tickInterval, priority)
|
|
}
|
|
|
|
func UnregisteModule(m Module) {
|
|
AppModule.waitShutAct <- m.ModuleName()
|
|
}
|
|
|
|
func Start() *utils.Waitor {
|
|
err := core.ExecuteHook(core.HOOK_BEFORE_START)
|
|
if err != nil {
|
|
logger.Logger.Error("ExecuteHook(HOOK_BEFORE_START) error", err)
|
|
}
|
|
return AppModule.Start()
|
|
}
|
|
|
|
func Stop() {
|
|
AppModule.Close()
|
|
err := core.ExecuteHook(core.HOOK_AFTER_STOP)
|
|
if err != nil {
|
|
logger.Logger.Error("ExecuteHook(HOOK_BEFORE_START) error", err)
|
|
}
|
|
}
|