Make endpoint modules special

To support unusual configuration syntax, endpoint modules (imap, smtp,
etc) relied on rather awkward code using modName+instName+aliases as
arguments. This commit replaces old handling with use of special
signature similar to inlineArgs introduced in 1edd031.

Endpoint modules are placed in a separate 'registry' and use
different initialization callback signature for simplicity. This makes
them inaccessible for other modules, though they are not supposed to be
anyway.

Endpoint modules are initialized before other modules. This allows
detecting unused configuration blocks by checking for modules
that were not lazily initalized after endpoint initialization.
This relies on endpoint modules being essentially "roots" of
instances dependency tree.

Idea of "semantical module names" is completely dropped now and so
HACKING.md is updated to not mention it.
This commit is contained in:
fox.cpp 2019-10-26 21:05:46 +03:00
parent 97b370191d
commit ad13d026ec
No known key found for this signature in database
GPG key ID: E76D97CCEDE90B6C
11 changed files with 190 additions and 118 deletions

View file

@ -5,7 +5,6 @@ import (
"github.com/foxcpp/maddy/config"
"github.com/foxcpp/maddy/log"
"github.com/foxcpp/maddy/module"
// Import packages for side-effect of module registration.
_ "github.com/foxcpp/maddy/auth/external"
@ -22,13 +21,7 @@ import (
_ "github.com/foxcpp/maddy/target/smtp_downstream"
)
type modInfo struct {
instance module.Module
cfg config.Node
}
func Start(cfg []config.Node) error {
instances := make(map[string]modInfo)
globals := config.NewMap(nil, &config.Node{Children: cfg})
globals.String("hostname", false, false, "", nil)
globals.String("autogenerated_msg_domain", false, false, "", nil)
@ -45,65 +38,17 @@ func Start(cfg []config.Node) error {
defer log.DefaultLogger.Out.Close()
for _, block := range unmatched {
var instName string
var modAliases []string
if len(block.Args) == 0 {
instName = block.Name
} else {
instName = block.Args[0]
modAliases = block.Args[1:]
}
modName := block.Name
factory := module.Get(modName)
if factory == nil {
return config.NodeErr(&block, "unknown module: %s", modName)
}
if module.HasInstance(instName) {
return config.NodeErr(&block, "config block named %s already exists", instName)
}
log.Debugln("module create", modName, instName)
inst, err := factory(modName, instName, modAliases, nil)
if err != nil {
return err
}
block := block
module.RegisterInstance(inst, config.NewMap(globals.Values, &block))
for _, alias := range modAliases {
if module.HasInstance(alias) {
return config.NodeErr(&block, "config block named %s already exists", alias)
}
module.RegisterAlias(alias, instName)
log.Debugln("module alias", alias, "->", instName)
}
instances[instName] = modInfo{instance: inst, cfg: block}
insts, err := instancesFromConfig(globals.Values, unmatched)
if err != nil {
return err
}
for _, inst := range instances {
if module.Initialized[inst.instance.InstanceName()] {
log.Debugln("module init", inst.instance.Name(), inst.instance.InstanceName(), "skipped because it was lazily initialized before")
continue
}
handleSignals()
module.Initialized[inst.instance.InstanceName()] = true
log.Debugln("module init", inst.instance.Name(), inst.instance.InstanceName())
if err := inst.instance.Init(config.NewMap(globals.Values, &inst.cfg)); err != nil {
return err
}
}
waitForSignal()
for _, inst := range instances {
if closer, ok := inst.instance.(io.Closer); ok {
log.Debugln("clean-up for module", inst.instance.Name(), inst.instance.InstanceName())
for _, inst := range insts {
if closer, ok := inst.(io.Closer); ok {
if err := closer.Close(); err != nil {
log.Printf("module %s (%s) close failed: %v", inst.instance.Name(), inst.instance.InstanceName(), err)
log.Printf("module %s (%s) close failed: %v", inst.Name(), inst.InstanceName(), err)
}
}
}