179 lines
3.1 KiB
Go
179 lines
3.1 KiB
Go
package common
|
|
|
|
import (
|
|
stdlib_context "context"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type Config interface {
|
|
Name() string
|
|
Starter() StartFct
|
|
Children() []Config
|
|
Add(Config)
|
|
}
|
|
|
|
type Message interface{}
|
|
|
|
type Services map[string]Context
|
|
|
|
type ContextState interface{}
|
|
|
|
type Context interface {
|
|
stdlib_context.Context
|
|
Config() Config
|
|
Parent() Context
|
|
Services() Services
|
|
ChildContext(Config) Context
|
|
State() ContextState
|
|
WithState(ContextState) Context
|
|
Mailbox() chan Message
|
|
WaitGroup() *sync.WaitGroup
|
|
Stop()
|
|
}
|
|
|
|
type FctCtx = func(Context)
|
|
|
|
type StartFct = FctCtx
|
|
|
|
// async Runners
|
|
|
|
func RunCtx(ctx Context, fct FctCtx) {
|
|
ctx.WaitGroup().Add(1)
|
|
go func() {
|
|
defer ctx.WaitGroup().Done()
|
|
fct(ctx)
|
|
}()
|
|
}
|
|
|
|
// Context implementation
|
|
|
|
type context struct {
|
|
cfg Config
|
|
parent Context
|
|
children []Context
|
|
state ContextState
|
|
mailbox chan Message
|
|
}
|
|
|
|
func (ctx *context) Config() Config {
|
|
return ctx.cfg
|
|
}
|
|
|
|
func (ctx *context) Parent() Context {
|
|
return ctx.parent
|
|
}
|
|
|
|
func (ctx *context) Services() Services {
|
|
return ctx.parent.Services()
|
|
}
|
|
|
|
func (ctx *context) ChildContext(cfg Config) Context {
|
|
cctx := makeCtx(cfg, ctx)
|
|
ctx.Services()[cfg.Name()] = cctx
|
|
ctx.children = append(ctx.children, cctx)
|
|
return cctx
|
|
}
|
|
|
|
func (ctx *context) State() ContextState {
|
|
return ctx.state
|
|
}
|
|
|
|
func (ctx *context) WithState(state ContextState) Context {
|
|
ctx.state = state
|
|
return ctx
|
|
}
|
|
|
|
func (ctx *context) Mailbox() chan Message {
|
|
return ctx.mailbox
|
|
}
|
|
|
|
func (ctx *context) WaitGroup() *sync.WaitGroup {
|
|
return ctx.parent.WaitGroup()
|
|
}
|
|
|
|
func (ctx *context) Done() <-chan struct{} {
|
|
return ctx.parent.Done()
|
|
}
|
|
|
|
func (ctx *context) Stop() {
|
|
// ctx.Warn("Only application-level service can be stopped
|
|
}
|
|
|
|
func makeCtx(cfg Config, parent Context) *context {
|
|
return &context{
|
|
cfg: cfg,
|
|
parent: parent,
|
|
mailbox: make(chan Message, 10),
|
|
}
|
|
}
|
|
|
|
// top-level application context
|
|
|
|
type appContext struct {
|
|
*context
|
|
services Services
|
|
waitgroup *sync.WaitGroup
|
|
doneCh chan struct{}
|
|
}
|
|
|
|
func (ctx *appContext) ChildContext(cfg Config) Context {
|
|
cctx := makeCtx(cfg, ctx)
|
|
ctx.services[cfg.Name()] = cctx
|
|
ctx.children = append(ctx.children, cctx)
|
|
return cctx
|
|
}
|
|
|
|
func (ctx *appContext) Services() Services {
|
|
return ctx.services
|
|
}
|
|
|
|
func (ctx *appContext) WithState(state ContextState) Context {
|
|
ctx.state = state
|
|
return ctx
|
|
}
|
|
|
|
func (ctx *appContext) WaitGroup() *sync.WaitGroup {
|
|
return ctx.waitgroup
|
|
}
|
|
|
|
func (ctx *appContext) Done() <-chan struct{} {
|
|
return ctx.doneCh
|
|
}
|
|
|
|
func (ctx *appContext) Stop() {
|
|
close(ctx.doneCh)
|
|
}
|
|
|
|
func AppContext(cfg Config) Context {
|
|
ctx := &appContext{
|
|
context: makeCtx(cfg, nil),
|
|
services: Services{},
|
|
waitgroup: &sync.WaitGroup{},
|
|
doneCh: make(chan struct{}),
|
|
}
|
|
ctx.services[cfg.Name()] = ctx
|
|
return ctx
|
|
}
|
|
|
|
// implement interface context.Context from standard library
|
|
|
|
func (ctx *context) Deadline() (deadline time.Time, ok bool) {
|
|
return time.Time{}, false
|
|
}
|
|
|
|
func (ctx *context) Err() error {
|
|
select {
|
|
case _, ok := <-ctx.Done():
|
|
if !ok {
|
|
return stdlib_context.Canceled
|
|
}
|
|
default:
|
|
return nil
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ctx *context) Value(key interface{}) interface{} {
|
|
return nil
|
|
}
|