From 1f0c061ce30f218e63fcc17e0fdfc8b90d754ba5 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Thu, 16 May 2019 16:05:38 -0600 Subject: Architectural shift to using context for config and module state --- modules.go | 95 +++++--------------------------------------------------------- 1 file changed, 7 insertions(+), 88 deletions(-) (limited to 'modules.go') diff --git a/modules.go b/modules.go index b2c9b96..bba6b93 100644 --- a/modules.go +++ b/modules.go @@ -3,7 +3,6 @@ package caddy2 import ( "encoding/json" "fmt" - "reflect" "sort" "strings" "sync" @@ -32,9 +31,6 @@ func RegisterModule(mod Module) error { if mod.Name == "caddy" { return fmt.Errorf("modules cannot be named 'caddy'") } - if strings.HasPrefix(mod.Name, "caddy.") { - return fmt.Errorf("modules cannot be namespaced in 'caddy'") - } modulesMu.Lock() defer modulesMu.Unlock() @@ -123,88 +119,6 @@ func Modules() []string { return names } -// LoadModule decodes rawMsg into a new instance of mod and -// returns the value. If mod.New() does not return a pointer -// value, it is converted to one so that it is unmarshaled -// into the underlying concrete type. If mod.New is nil, an -// error is returned. If the module implements Validator or -// Provisioner interfaces, those methods are invoked to -// ensure the module is fully configured and valid before -// being used. -func LoadModule(name string, rawMsg json.RawMessage) (interface{}, error) { - modulesMu.Lock() - mod, ok := modules[name] - modulesMu.Unlock() - if !ok { - return nil, fmt.Errorf("unknown module: %s", name) - } - - if mod.New == nil { - return nil, fmt.Errorf("module '%s' has no constructor", mod.Name) - } - - val, err := mod.New() - if err != nil { - return nil, fmt.Errorf("initializing module '%s': %v", mod.Name, err) - } - - // value must be a pointer for unmarshaling into concrete type - if rv := reflect.ValueOf(val); rv.Kind() != reflect.Ptr { - val = reflect.New(rv.Type()).Elem().Addr().Interface() - } - - // fill in its config only if there is a config to fill in - if len(rawMsg) > 0 { - err = json.Unmarshal(rawMsg, &val) - if err != nil { - return nil, fmt.Errorf("decoding module config: %s: %v", mod.Name, err) - } - } - - if prov, ok := val.(Provisioner); ok { - err := prov.Provision() - if err != nil { - return nil, fmt.Errorf("provision %s: %v", mod.Name, err) - } - } - - if validator, ok := val.(Validator); ok { - err := validator.Validate() - if err != nil { - return nil, fmt.Errorf("%s: invalid configuration: %v", mod.Name, err) - } - } - - moduleInstances[mod.Name] = append(moduleInstances[mod.Name], val) - - return val, nil -} - -// LoadModuleInline loads a module from a JSON raw message which decodes -// to a map[string]interface{}, where one of the keys is moduleNameKey -// and the corresponding value is the module name as a string, which -// can be found in the given scope. -// -// This allows modules to be decoded into their concrete types and -// used when their names cannot be the unique key in a map, such as -// when there are multiple instances in the map or it appears in an -// array (where there are no custom keys). In other words, the key -// containing the module name is treated special/separate from all -// the other keys. -func LoadModuleInline(moduleNameKey, moduleScope string, raw json.RawMessage) (interface{}, error) { - moduleName, err := getModuleNameInline(moduleNameKey, raw) - if err != nil { - return nil, err - } - - val, err := LoadModule(moduleScope+"."+moduleName, raw) - if err != nil { - return nil, fmt.Errorf("loading module '%s': %v", moduleName, err) - } - - return val, nil -} - // getModuleNameInline loads the string value from raw of moduleNameKey, // where raw must be a JSON encoding of a map. func getModuleNameInline(moduleNameKey string, raw json.RawMessage) (string, error) { @@ -228,14 +142,19 @@ func getModuleNameInline(moduleNameKey string, raw json.RawMessage) (string, err // always be fast (imperceptible running time) and an error should // be returned only if the value's configuration is invalid. type Validator interface { - Validate() error + Validate(Context) error } // Provisioner is implemented by modules which may need to perform // some additional "setup" steps immediately after being loaded. // This method will be called after Validate() (if implemented). type Provisioner interface { - Provision() error + Provision(Context) error +} + +// TODO: different name... +type CleanerUpper interface { + Cleanup() error } var ( -- cgit v1.2.3