package app import ( "context" "errors" "os" "sorbet/pkg/app/appkit" ) func Init(args ...string) (err error) { if len(args) == 0 { args = os.Args[1:] } switch Status() { case Initialized: return nil case Starting: return errors.New("starting") case Running: return errors.New("running") case Stopping: return errors.New("stopping") case Idle, Stopped: // continue } initLifecycle() initStats(args) initUdp(args) initBus() initBuiltins() setStatus(Initialized) return } func initBuiltins() { // 订阅应用启动 var sub appkit.Subscriber sub = Sub("start", func([]byte) []byte { sub.Cancel() return nil }) // 订阅应用停止 Sub("stop", func(bytes []byte) []byte { quit := exit if quit != nil { exit = nil quit() } return nil }) } func Loop() error { switch Status() { case Starting, Running: return nil case Stopping: return errors.New("stopping") case Idle: return errors.New("idle, you maybe forgot call app.Init()") case Stopped: return errors.New("stopped, you maybe forgot call app.Init()") case Initialized: // nothing } // 释放内存 defer free() wg.Add(1) setStatus(Starting) // In a goroutine, we wait on for all goroutines to complete (for example // timers). We use this to signal to the main thread to exit. // wg.Add(1) basically translates to uv_ref, if this was Node. // wg.Done() basically translates to uv_unref go func() { wg.Wait() setStatus(Stopping) stop() }() // 启动应用指令 Pub("start", nil) for { select { case msg := <-pubs: err := dispatch(msg) exitOnError(err) wg.Done() // Corresponds to the wg.Add(1) in Pub(). case <-ctx.Done(): // 只有等待所有协程全部完成后, // 然后才可以退出主循环 checkPubsEmpty() setStatus(Stopped) return ctx.Err() } // We don't want to exit until we've received at least one message. // This is so the program doesn't exit after sending the "start" // message. if Status() == Starting { wg.Done() start() setStatus(Running) } } } func Stop() { Pub("stop", nil) } func Go(fn func(context.Context)) { assert(fn != nil, "invalid fn") async(fn) }