1/*2Maddy Mail Server - Composable all-in-one email server.3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors45This program is free software: you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation, either version 3 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program. If not, see <https://www.gnu.org/licenses/>.17*/1819package module2021import (22 "fmt"23 "io"2425 "github.com/foxcpp/maddy/framework/config"26 "github.com/foxcpp/maddy/framework/hooks"27 "github.com/foxcpp/maddy/framework/log"28)2930var (31 instances = make(map[string]struct {32 mod Module33 cfg *config.Map34 })35 aliases = make(map[string]string)3637 Initialized = make(map[string]bool)38)3940// RegisterInstance adds module instance to the global registry.41//42// Instance name must be unique. Second RegisterInstance with same instance43// name will replace previous.44func RegisterInstance(inst Module, cfg *config.Map) {45 instances[inst.InstanceName()] = struct {46 mod Module47 cfg *config.Map48 }{inst, cfg}49}5051// RegisterAlias creates an association between a certain name and instance name.52//53// After RegisterAlias, module.GetInstance(aliasName) will return the same54// result as module.GetInstance(instName).55func RegisterAlias(aliasName, instName string) {56 aliases[aliasName] = instName57}5859func HasInstance(name string) bool {60 aliasedName := aliases[name]61 if aliasedName != "" {62 name = aliasedName63 }6465 _, ok := instances[name]66 return ok67}6869// GetInstance returns module instance from global registry, initializing it if70// necessary.71//72// Error is returned if module initialization fails or module instance does not73// exists.74func GetInstance(name string) (Module, error) {75 aliasedName := aliases[name]76 if aliasedName != "" {77 name = aliasedName78 }7980 mod, ok := instances[name]81 if !ok {82 return nil, fmt.Errorf("unknown config block: %s", name)83 }8485 // Break circular dependencies.86 if Initialized[name] {87 return mod.mod, nil88 }8990 Initialized[name] = true91 if err := mod.mod.Init(mod.cfg); err != nil {92 return mod.mod, err93 }9495 if closer, ok := mod.mod.(io.Closer); ok {96 hooks.AddHook(hooks.EventShutdown, func() {97 log.Debugf("close %s (%s)", mod.mod.Name(), mod.mod.InstanceName())98 if err := closer.Close(); err != nil {99 log.Printf("module %s (%s) close failed: %v", mod.mod.Name(), mod.mod.InstanceName(), err)100 }101 })102 }103104 return mod.mod, nil105}