You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
2.2 KiB
128 lines
2.2 KiB
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)
|
|
err := ctx.Err()
|
|
if errors.Is(err, context.Canceled) {
|
|
return nil
|
|
}
|
|
return 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)
|
|
}
|
|
|