maddy/maddy.go
fox.cpp af62042aec Allow omitting instance_name in config
One will be assigned automatically.
2019-03-30 17:34:19 +02:00

138 lines
3.2 KiB
Go

package maddy
import (
"errors"
"fmt"
"io"
"log"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"github.com/emersion/maddy/config"
"github.com/emersion/maddy/module"
)
func Start(cfg []config.CfgTreeNode) error {
var instances []module.Module
for _, block := range cfg {
var instName string
if len(block.Args) == 0 {
instName = implicitInstanceName(block.Name)
} else {
instName = block.Args[0]
}
modName := block.Name
factory := module.GetMod(modName)
if factory == nil {
return fmt.Errorf("unknown module: %s", modName)
}
if mod := module.GetInstance(instName); mod != nil {
if !strings.HasPrefix(instName, "default") {
return fmt.Errorf("module instance named %s already exists", instName)
}
// Clean up default module before replacing it.
if closer, ok := mod.(io.Closer); ok {
closer.Close()
}
}
inst, err := factory(instName, block)
if err != nil {
return fmt.Errorf("module instance %s initialization failed: %v", instName, err)
}
module.RegisterInstance(inst)
instances = append(instances, inst)
}
sig := make(chan os.Signal, 5)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGINT)
s := <-sig
log.Printf("signal received (%v), next signal will force immediate shutdown.\n", s)
go func() {
s := <-sig
log.Printf("forced shutdown due to signal (%v)!\n", s)
os.Exit(1)
}()
for _, inst := range instances {
if closer, ok := inst.(io.Closer); ok {
closer.Close()
}
}
module.WaitGroup.Wait()
return nil
}
func authProvider(args []string) (module.AuthProvider, error) {
if len(args) != 1 {
return nil, errors.New("auth: expected 1 argument")
}
authName := args[0]
authMod := module.GetInstance(authName)
if authMod == nil {
return nil, fmt.Errorf("unknown auth. provider instance: %s", authName)
}
provider, ok := authMod.(module.AuthProvider)
if !ok {
return nil, fmt.Errorf("module %s doesn't implements auth. provider interface", authMod.Name())
}
return provider, nil
}
func storageBackend(args []string) (module.Storage, error) {
if len(args) != 1 {
return nil, errors.New("storage: expected 1 argument")
}
authName := args[0]
authMod := module.GetInstance(authName)
if authMod == nil {
return nil, fmt.Errorf("unknown storage backend instance: %s", authName)
}
provider, ok := authMod.(module.Storage)
if !ok {
return nil, fmt.Errorf("module %s doesn't implements storage interface", authMod.Name())
}
return provider, nil
}
func deliveryTarget(args []string) (module.DeliveryTarget, error) {
if len(args) != 1 {
return nil, errors.New("delivery: expected 1 argument")
}
modName := args[0]
mod := module.GetInstance(modName)
if mod == nil {
return nil, fmt.Errorf("unknown delivery target instance: %s", modName)
}
target, ok := mod.(module.DeliveryTarget)
if !ok {
return nil, fmt.Errorf("module %s doesn't implements delivery target interface", mod.Name())
}
return target, nil
}
func implicitInstanceName(modName string) string {
if mod := module.GetInstance(modName); mod == nil {
return modName
}
i := 1
for ; module.GetInstance(modName+strconv.Itoa(i)) != nil; i++ {
}
return modName + strconv.Itoa(i)
}