package common import "sync" 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 { Config() Config Parent() Context Services() Services ChildContext(Config) Context State() ContextState WithState(ContextState) Context Mailbox() chan Message Done() chan struct{} WaitGroup() *sync.WaitGroup } 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 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 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 }