MCPcopy
hub / github.com/caddyserver/caddy / LoadModuleByID

Method LoadModuleByID

context.go:364–465  ·  view source on GitHub ↗

LoadModuleByID decodes rawMsg into a new instance of mod and returns the value. 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. This is a lower-leve

(id string, rawMsg json.RawMessage)

Source from the content-addressed store, hash-verified

362// dynamically loading/unloading modules in their own context,
363// like from embedded scripts, etc.
364func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error) {
365 modulesMu.RLock()
366 modInfo, ok := modules[id]
367 modulesMu.RUnlock()
368 if !ok {
369 return nil, fmt.Errorf("unknown module: %s", id)
370 }
371
372 if modInfo.New == nil {
373 return nil, fmt.Errorf("module '%s' has no constructor", modInfo.ID)
374 }
375
376 val := modInfo.New()
377
378 // value must be a pointer for unmarshaling into concrete type, even if
379 // the module's concrete type is a slice or map; New() *should* return
380 // a pointer, otherwise unmarshaling errors or panics will occur
381 if rv := reflect.ValueOf(val); rv.Kind() != reflect.Pointer {
382 log.Printf("[WARNING] ModuleInfo.New() for module '%s' did not return a pointer,"+
383 " so we are using reflection to make a pointer instead; please fix this by"+
384 " using new(Type) or &Type notation in your module's New() function.", id)
385 val = reflect.New(rv.Type()).Elem().Addr().Interface().(Module)
386 }
387
388 // fill in its config only if there is a config to fill in
389 if len(rawMsg) > 0 {
390 err := StrictUnmarshalJSON(rawMsg, &val)
391 if err != nil {
392 return nil, fmt.Errorf("decoding module config: %s: %v", modInfo, err)
393 }
394 }
395
396 if val == nil {
397 // returned module values are almost always type-asserted
398 // before being used, so a nil value would panic; and there
399 // is no good reason to explicitly declare null modules in
400 // a config; it might be because the user is trying to achieve
401 // a result the developer isn't expecting, which is a smell
402 return nil, fmt.Errorf("module value cannot be null")
403 }
404
405 var err error
406
407 // if this is an app module, keep a reference to it,
408 // since submodules may need to reference it during
409 // provisioning (even though the parent app module
410 // may not be fully provisioned yet; this is the case
411 // with the tls app's automation policies, which may
412 // refer to the tls app to check if a global DNS
413 // module has been configured for DNS challenges)
414 if appModule, ok := val.(App); ok {
415 ctx.cfg.apps[id] = appModule
416 defer func() {
417 if err != nil {
418 ctx.cfg.failedApps[id] = err
419 }
420 }()
421 }

Callers 3

loadModuleMapMethod · 0.95
loadModuleInlineMethod · 0.95
AppMethod · 0.95

Calls 6

StrictUnmarshalJSONFunction · 0.85
AddrMethod · 0.80
ProvisionMethod · 0.65
CleanupMethod · 0.65
ValidateMethod · 0.65
TypeMethod · 0.45

Tested by

no test coverage detected