|
@@ -0,0 +1,330 @@
|
|
|
+package mhaya
|
|
|
+
|
|
|
+import (
|
|
|
+ "os"
|
|
|
+ "os/signal"
|
|
|
+ "sync/atomic"
|
|
|
+ "syscall"
|
|
|
+
|
|
|
+ cconst "github.com/mhaya/const"
|
|
|
+ ctime "github.com/mhaya/extend/time"
|
|
|
+ cutils "github.com/mhaya/extend/utils"
|
|
|
+ cfacade "github.com/mhaya/facade"
|
|
|
+ clog "github.com/mhaya/logger"
|
|
|
+ cactor "github.com/mhaya/net/actor"
|
|
|
+ cserializer "github.com/mhaya/net/serializer"
|
|
|
+ cprofile "github.com/mhaya/profile"
|
|
|
+)
|
|
|
+
|
|
|
+const (
|
|
|
+ Cluster NodeMode = 1 // 集群模式
|
|
|
+ Standalone NodeMode = 2 // 单机模式
|
|
|
+)
|
|
|
+
|
|
|
+type (
|
|
|
+ NodeMode byte
|
|
|
+
|
|
|
+ Application struct {
|
|
|
+ cfacade.INode
|
|
|
+ isFrontend bool
|
|
|
+ nodeMode NodeMode
|
|
|
+ startTime ctime.MhayaTime // application start time
|
|
|
+ running int32 // is running
|
|
|
+ dieChan chan bool // wait for end application
|
|
|
+ onShutdownFn []func() // on shutdown execute functions
|
|
|
+ components []cfacade.IComponent // all components
|
|
|
+ serializer cfacade.ISerializer // serializer
|
|
|
+ discovery cfacade.IDiscovery // discovery component
|
|
|
+ cluster cfacade.ICluster // cluster component
|
|
|
+ actorSystem *cactor.Component // actor system
|
|
|
+ netParser cfacade.INetParser // net packet parser
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+// NewApp create new application instance
|
|
|
+func NewApp(profileFilePath, nodeId string, isFrontend bool, mode NodeMode) *Application {
|
|
|
+ node, err := cprofile.Init(profileFilePath, nodeId)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return NewAppNode(node, isFrontend, mode)
|
|
|
+}
|
|
|
+
|
|
|
+func NewAppNode(node cfacade.INode, isFrontend bool, mode NodeMode) *Application {
|
|
|
+ // set logger
|
|
|
+ clog.SetNodeLogger(node)
|
|
|
+
|
|
|
+ // print version info
|
|
|
+ clog.Info(cconst.GetLOGO())
|
|
|
+
|
|
|
+ app := &Application{
|
|
|
+ INode: node,
|
|
|
+ serializer: cserializer.NewJSON(),
|
|
|
+ isFrontend: isFrontend,
|
|
|
+ nodeMode: mode,
|
|
|
+ startTime: ctime.Now(),
|
|
|
+ running: 0,
|
|
|
+ dieChan: make(chan bool),
|
|
|
+ actorSystem: cactor.New(),
|
|
|
+ }
|
|
|
+
|
|
|
+ return app
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) IsFrontend() bool {
|
|
|
+ return a.isFrontend
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) NodeMode() NodeMode {
|
|
|
+ return a.nodeMode
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) Running() bool {
|
|
|
+ return a.running > 0
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) DieChan() chan bool {
|
|
|
+ return a.dieChan
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) Register(components ...cfacade.IComponent) {
|
|
|
+ if a.Running() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, c := range components {
|
|
|
+ if c == nil || c.Name() == "" {
|
|
|
+ clog.Errorf("[component = %T] name is nil", c)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ result := a.Find(c.Name())
|
|
|
+ if result != nil {
|
|
|
+ clog.Errorf("[component name = %s] is duplicate.", c.Name())
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ a.components = append(a.components, c)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) Find(name string) cfacade.IComponent {
|
|
|
+ if name == "" {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, component := range a.components {
|
|
|
+ if component.Name() == name {
|
|
|
+ return component
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// Remove component by name
|
|
|
+func (a *Application) Remove(name string) cfacade.IComponent {
|
|
|
+ if name == "" {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ var removeComponent cfacade.IComponent
|
|
|
+ for i := 0; i < len(a.components); i++ {
|
|
|
+ if a.components[i].Name() == name {
|
|
|
+ removeComponent = a.components[i]
|
|
|
+ a.components = append(a.components[:i], a.components[i+1:]...)
|
|
|
+ i--
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return removeComponent
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) All() []cfacade.IComponent {
|
|
|
+ return a.components
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) OnShutdown(fn ...func()) {
|
|
|
+ a.onShutdownFn = append(a.onShutdownFn, fn...)
|
|
|
+}
|
|
|
+
|
|
|
+// Startup load components before startup
|
|
|
+func (a *Application) Startup() {
|
|
|
+ defer func() {
|
|
|
+ if r := recover(); r != nil {
|
|
|
+ clog.Error(r)
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
+ if a.Running() {
|
|
|
+ clog.Error("Application has running.")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ defer func() {
|
|
|
+ clog.Flush()
|
|
|
+ }()
|
|
|
+
|
|
|
+ // register actor system
|
|
|
+ a.Register(a.actorSystem)
|
|
|
+
|
|
|
+ // add connector component
|
|
|
+ if a.netParser != nil {
|
|
|
+ for _, connector := range a.netParser.Connectors() {
|
|
|
+ a.Register(connector)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ clog.Info("-------------------------------------------------")
|
|
|
+ clog.Infof("[nodeId = %s] application is starting...", a.NodeId())
|
|
|
+ clog.Infof("[nodeType = %s]", a.NodeType())
|
|
|
+ clog.Infof("[pid = %d]", os.Getpid())
|
|
|
+ clog.Infof("[startTime = %s]", a.StartTime())
|
|
|
+ clog.Infof("[profilePath = %s]", cprofile.Path())
|
|
|
+ clog.Infof("[profileName = %s]", cprofile.Name())
|
|
|
+ clog.Infof("[env = %s]", cprofile.Env())
|
|
|
+ clog.Infof("[debug = %v]", cprofile.Debug())
|
|
|
+ clog.Infof("[printLevel = %s]", cprofile.PrintLevel())
|
|
|
+ clog.Infof("[logLevel = %s]", clog.DefaultLogger.LogLevel)
|
|
|
+ clog.Infof("[stackLevel = %s]", clog.DefaultLogger.StackLevel)
|
|
|
+ clog.Infof("[writeFile = %v]", clog.DefaultLogger.EnableWriteFile)
|
|
|
+ clog.Infof("[serializer = %s]", a.serializer.Name())
|
|
|
+ clog.Info("-------------------------------------------------")
|
|
|
+
|
|
|
+ // component list
|
|
|
+ for _, c := range a.components {
|
|
|
+ c.Set(a)
|
|
|
+ clog.Infof("[component = %s] is added.", c.Name())
|
|
|
+ }
|
|
|
+ clog.Info("-------------------------------------------------")
|
|
|
+
|
|
|
+ // execute Init()
|
|
|
+ for _, c := range a.components {
|
|
|
+ clog.Infof("[component = %s] -> OnInit().", c.Name())
|
|
|
+ c.Init()
|
|
|
+ }
|
|
|
+ clog.Info("-------------------------------------------------")
|
|
|
+
|
|
|
+ // execute OnAfterInit()
|
|
|
+ for _, c := range a.components {
|
|
|
+ clog.Infof("[component = %s] -> OnAfterInit().", c.Name())
|
|
|
+ c.OnAfterInit()
|
|
|
+ }
|
|
|
+
|
|
|
+ // load net packet parser
|
|
|
+ if a.isFrontend {
|
|
|
+ if a.netParser == nil {
|
|
|
+ clog.Panic("net packet parser is nil.")
|
|
|
+ }
|
|
|
+ a.netParser.Load(a)
|
|
|
+ }
|
|
|
+
|
|
|
+ clog.Info("-------------------------------------------------")
|
|
|
+ spendTime := a.startTime.DiffInMillisecond(ctime.Now())
|
|
|
+ clog.Infof("[spend time = %dms] application is running.", spendTime)
|
|
|
+ clog.Info("-------------------------------------------------")
|
|
|
+
|
|
|
+ // set application is running
|
|
|
+ atomic.AddInt32(&a.running, 1)
|
|
|
+
|
|
|
+ sg := make(chan os.Signal, 1)
|
|
|
+ signal.Notify(sg, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
|
|
|
+
|
|
|
+ select {
|
|
|
+ case <-a.dieChan:
|
|
|
+ clog.Info("invoke shutdown().")
|
|
|
+ case s := <-sg:
|
|
|
+ clog.Infof("receive shutdown signal = %v.", s)
|
|
|
+ }
|
|
|
+
|
|
|
+ // stop status
|
|
|
+ atomic.StoreInt32(&a.running, 0)
|
|
|
+
|
|
|
+ clog.Info("------- application will shutdown -------")
|
|
|
+
|
|
|
+ if a.onShutdownFn != nil {
|
|
|
+ for _, f := range a.onShutdownFn {
|
|
|
+ cutils.Try(func() {
|
|
|
+ f()
|
|
|
+ }, func(errString string) {
|
|
|
+ clog.Warnf("[onShutdownFn] error = %s", errString)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //all components in reverse order
|
|
|
+ for i := len(a.components) - 1; i >= 0; i-- {
|
|
|
+ cutils.Try(func() {
|
|
|
+ clog.Infof("[component = %s] -> OnBeforeStop().", a.components[i].Name())
|
|
|
+ a.components[i].OnBeforeStop()
|
|
|
+ }, func(errString string) {
|
|
|
+ clog.Warnf("[component = %s] -> OnBeforeStop(). error = %s", a.components[i].Name(), errString)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := len(a.components) - 1; i >= 0; i-- {
|
|
|
+ cutils.Try(func() {
|
|
|
+ clog.Infof("[component = %s] -> OnStop().", a.components[i].Name())
|
|
|
+ a.components[i].OnStop()
|
|
|
+ }, func(errString string) {
|
|
|
+ clog.Warnf("[component = %s] -> OnStop(). error = %s", a.components[i].Name(), errString)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ clog.Info("------- application has been shutdown... -------")
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) Shutdown() {
|
|
|
+ a.dieChan <- true
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) Serializer() cfacade.ISerializer {
|
|
|
+ return a.serializer
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) Discovery() cfacade.IDiscovery {
|
|
|
+ return a.discovery
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) Cluster() cfacade.ICluster {
|
|
|
+ return a.cluster
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) ActorSystem() cfacade.IActorSystem {
|
|
|
+ return a.actorSystem
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) StartTime() string {
|
|
|
+ return a.startTime.ToDateTimeFormat()
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) SetSerializer(serializer cfacade.ISerializer) {
|
|
|
+ if a.Running() || serializer == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ a.serializer = serializer
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) SetDiscovery(discovery cfacade.IDiscovery) {
|
|
|
+ if a.Running() || discovery == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ a.discovery = discovery
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) SetCluster(cluster cfacade.ICluster) {
|
|
|
+ if a.Running() || cluster == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ a.cluster = cluster
|
|
|
+}
|
|
|
+
|
|
|
+func (a *Application) SetNetParser(netParser cfacade.INetParser) {
|
|
|
+ if a.Running() || netParser == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ a.netParser = netParser
|
|
|
+}
|