go项目脚手架
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.
sorbet/pkg/app/app.go

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)
}