Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

events: Implement event system #4912

Merged
merged 16 commits into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 52 additions & 16 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ import (
// not actually need to do this).
type Context struct {
context.Context
moduleInstances map[string][]any
moduleInstances map[string][]Module
cfg *Config
cleanupFuncs []func()
ancestry []Module
}

// NewContext provides a new context derived from the given
Expand All @@ -51,7 +52,7 @@ type Context struct {
// modules which are loaded will be properly unloaded.
// See standard library context package's documentation.
func NewContext(ctx Context) (Context, context.CancelFunc) {
newCtx := Context{moduleInstances: make(map[string][]any), cfg: ctx.cfg}
newCtx := Context{moduleInstances: make(map[string][]Module), cfg: ctx.cfg}
c, cancel := context.WithCancel(ctx.Context)
wrappedCancel := func() {
cancel()
Expand Down Expand Up @@ -90,15 +91,15 @@ func (ctx *Context) OnCancel(f func()) {
// ModuleMap may be used in place of map[string]json.RawMessage. The return value's
// underlying type mirrors the input field's type:
//
// json.RawMessage => any
// []json.RawMessage => []any
// [][]json.RawMessage => [][]any
// map[string]json.RawMessage => map[string]any
// []map[string]json.RawMessage => []map[string]any
// json.RawMessage => any
// []json.RawMessage => []any
// [][]json.RawMessage => [][]any
// map[string]json.RawMessage => map[string]any
// []map[string]json.RawMessage => []map[string]any
//
// The field must have a "caddy" struct tag in this format:
//
// caddy:"key1=val1 key2=val2"
// caddy:"key1=val1 key2=val2"
//
// To load modules, a "namespace" key is required. For example, to load modules
// in the "http.handlers" namespace, you'd put: `namespace=http.handlers` in the
Expand All @@ -115,7 +116,7 @@ func (ctx *Context) OnCancel(f func()) {
// meaning the key containing the module's name that is defined inline with the module
// itself. You must specify the inline key in a struct tag, along with the namespace:
//
// caddy:"namespace=http.handlers inline_key=handler"
// caddy:"namespace=http.handlers inline_key=handler"
//
// This will look for a key/value pair like `"handler": "..."` in the json.RawMessage
// in order to know the module name.
Expand Down Expand Up @@ -301,17 +302,17 @@ func (ctx Context) loadModuleMap(namespace string, val reflect.Value) (map[strin
// like from embedded scripts, etc.
func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error) {
modulesMu.RLock()
mod, ok := modules[id]
modInfo, ok := modules[id]
modulesMu.RUnlock()
if !ok {
return nil, fmt.Errorf("unknown module: %s", id)
}

if mod.New == nil {
return nil, fmt.Errorf("module '%s' has no constructor", mod.ID)
if modInfo.New == nil {
return nil, fmt.Errorf("module '%s' has no constructor", modInfo.ID)
}

val := mod.New().(any)
val := modInfo.New()

// value must be a pointer for unmarshaling into concrete type, even if
// the module's concrete type is a slice or map; New() *should* return
Expand All @@ -327,7 +328,7 @@ func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error
if len(rawMsg) > 0 {
err := strictUnmarshalJSON(rawMsg, &val)
if err != nil {
return nil, fmt.Errorf("decoding module config: %s: %v", mod, err)
return nil, fmt.Errorf("decoding module config: %s: %v", modInfo, err)
}
}

Expand All @@ -340,6 +341,8 @@ func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error
return nil, fmt.Errorf("module value cannot be null")
}

ctx.ancestry = append(ctx.ancestry, val)

if prov, ok := val.(Provisioner); ok {
err := prov.Provision(ctx)
if err != nil {
Expand All @@ -351,7 +354,7 @@ func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error
err = fmt.Errorf("%v; additionally, cleanup: %v", err, err2)
}
}
return nil, fmt.Errorf("provision %s: %v", mod, err)
return nil, fmt.Errorf("provision %s: %v", modInfo, err)
}
}

Expand All @@ -365,7 +368,7 @@ func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error
err = fmt.Errorf("%v; additionally, cleanup: %v", err, err2)
}
}
return nil, fmt.Errorf("%s: invalid configuration: %v", mod, err)
return nil, fmt.Errorf("%s: invalid configuration: %v", modInfo, err)
}
}

Expand Down Expand Up @@ -439,8 +442,10 @@ func (ctx Context) Storage() certmagic.Storage {
return ctx.cfg.storage
}

// TODO: aw man, can I please change this?
// Logger returns a logger that can be used by mod.
func (ctx Context) Logger(mod Module) *zap.Logger {
// TODO: if mod is nil, use ctx.Module() instead...
if ctx.cfg == nil {
// often the case in tests; just use a dev logger
l, err := zap.NewDevelopment()
Expand All @@ -451,3 +456,34 @@ func (ctx Context) Logger(mod Module) *zap.Logger {
}
return ctx.cfg.Logging.Logger(mod)
}

// TODO: use this
// // Logger returns a logger that can be used by the current module.
// func (ctx Context) Log() *zap.Logger {
// if ctx.cfg == nil {
// // often the case in tests; just use a dev logger
// l, err := zap.NewDevelopment()
// if err != nil {
// panic("config missing, unable to create dev logger: " + err.Error())
// }
// return l
// }
// return ctx.cfg.Logging.Logger(ctx.Module())
// }

// Modules returns the lineage of modules that this context provisioned,
// with the most recent/current module being last in the list.
func (ctx Context) Modules() []Module {
mods := make([]Module, len(ctx.ancestry))
copy(mods, ctx.ancestry)
return mods
}

// Module returns the current module, or the most recent one
// provisioned by the context.
func (ctx Context) Module() Module {
if len(ctx.ancestry) == 0 {
return nil
}
return ctx.ancestry[len(ctx.ancestry)-1]
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/Masterminds/sprig/v3 v3.2.2
github.com/alecthomas/chroma v0.10.0
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b
github.com/caddyserver/certmagic v0.16.3
github.com/caddyserver/certmagic v0.17.0
github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac
github.com/go-chi/chi v4.1.2+incompatible
github.com/google/cel-go v0.12.4
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/caddyserver/certmagic v0.16.3 h1:1ZbiU7y5X0MnDjBTXywUbPMs/ScHbgCeeCy/LPh4IZk=
github.com/caddyserver/certmagic v0.16.3/go.mod h1:pSS2aZcdKlrTZrb2DKuRafckx20o5Fz1EdDKEB8KOQM=
github.com/caddyserver/certmagic v0.17.0 h1:AHHvvmv6SNcq0vK5BgCevQqYMV8GNprVk6FWZzx8d+Q=
github.com/caddyserver/certmagic v0.17.0/go.mod h1:pSS2aZcdKlrTZrb2DKuRafckx20o5Fz1EdDKEB8KOQM=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
Expand Down
Loading