go-scopes/lib/lib.go

179 lines
3.1 KiB
Go

package lib
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
}