goserver_sync/core/module/modulemgr.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)
}
}