maddy

Fork https://github.com/foxcpp/maddy

git clone git://git.lin.moe/go/maddy.git

  1/*
  2Maddy Mail Server - Composable all-in-one email server.
  3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
  4
  5This program is free software: you can redistribute it and/or modify
  6it under the terms of the GNU General Public License as published by
  7the Free Software Foundation, either version 3 of the License, or
  8(at your option) any later version.
  9
 10This program is distributed in the hope that it will be useful,
 11but WITHOUT ANY WARRANTY; without even the implied warranty of
 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13GNU General Public License for more details.
 14
 15You should have received a copy of the GNU General Public License
 16along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17*/
 18
 19package module
 20
 21import (
 22	"fmt"
 23	"io"
 24
 25	"github.com/foxcpp/maddy/framework/config"
 26	"github.com/foxcpp/maddy/framework/hooks"
 27	"github.com/foxcpp/maddy/framework/log"
 28)
 29
 30var (
 31	instances = make(map[string]struct {
 32		mod Module
 33		cfg *config.Map
 34	})
 35	aliases = make(map[string]string)
 36
 37	Initialized = make(map[string]bool)
 38)
 39
 40// RegisterInstance adds module instance to the global registry.
 41//
 42// Instance name must be unique. Second RegisterInstance with same instance
 43// name will replace previous.
 44func RegisterInstance(inst Module, cfg *config.Map) {
 45	instances[inst.InstanceName()] = struct {
 46		mod Module
 47		cfg *config.Map
 48	}{inst, cfg}
 49}
 50
 51// RegisterAlias creates an association between a certain name and instance name.
 52//
 53// After RegisterAlias, module.GetInstance(aliasName) will return the same
 54// result as module.GetInstance(instName).
 55func RegisterAlias(aliasName, instName string) {
 56	aliases[aliasName] = instName
 57}
 58
 59func HasInstance(name string) bool {
 60	aliasedName := aliases[name]
 61	if aliasedName != "" {
 62		name = aliasedName
 63	}
 64
 65	_, ok := instances[name]
 66	return ok
 67}
 68
 69// GetInstance returns module instance from global registry, initializing it if
 70// necessary.
 71//
 72// Error is returned if module initialization fails or module instance does not
 73// exists.
 74func GetInstance(name string) (Module, error) {
 75	aliasedName := aliases[name]
 76	if aliasedName != "" {
 77		name = aliasedName
 78	}
 79
 80	mod, ok := instances[name]
 81	if !ok {
 82		return nil, fmt.Errorf("unknown config block: %s", name)
 83	}
 84
 85	// Break circular dependencies.
 86	if Initialized[name] {
 87		return mod.mod, nil
 88	}
 89
 90	Initialized[name] = true
 91	if err := mod.mod.Init(mod.cfg); err != nil {
 92		return mod.mod, err
 93	}
 94
 95	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	}
103
104	return mod.mod, nil
105}