func (lf LoaderFunc) Load(serverType string) (Input, error) {
	return lf(serverType)
}
Load loads a Casketfile.
package casket
import (
	"fmt"
	"log"
	"net"
	"sort"
	"sync"
	"github.com/tmpim/casket/casketfile"
)
var (
	serverTypes = make(map[string]ServerType)
	plugins = make(map[string]map[string]Plugin)
	eventHooks = &sync.Map{}
	parsingCallbacks = make(map[string]map[string][]ParsingCallback)
	casketfileLoaders []casketfileLoader
)
func DescribePlugins() string {
	pl := ListPlugins()
	str := "Server types:\n"
	for _, name := range pl["server_types"] {
		str += "  " + name + "\n"
	}
	str += "\nCasketfile loaders:\n"
	for _, name := range pl["casketfile_loaders"] {
		str += "  " + name + "\n"
	}
	if len(pl["event_hooks"]) > 0 {
		str += "\nEvent hook plugins:\n"
		for _, name := range pl["event_hooks"] {
			str += "  hook." + name + "\n"
		}
	}
	if len(pl["clustering"]) > 0 {
		str += "\nClustering plugins:\n"
		for _, name := range pl["clustering"] {
			str += "  " + name + "\n"
		}
	}
	str += "\nOther plugins:\n"
	for _, name := range pl["others"] {
		str += "  " + name + "\n"
	}
	return str
}
func ListPlugins() map[string][]string {
	p := make(map[string][]string)
	for name := range serverTypes {
		p["server_types"] = append(p["server_types"], name)
	}
	for _, loader := range casketfileLoaders {
		p["casketfile_loaders"] = append(p["casketfile_loaders"], loader.name)
	}
	if defaultCasketfileLoader.name != "" {
		p["casketfile_loaders"] = append(p["casketfile_loaders"], defaultCasketfileLoader.name)
	}
	eventHooks.Range(func(k, _ interface{}) bool {
		p["event_hooks"] = append(p["event_hooks"], k.(string))
		return true
	})
	var others []string
	for stype, stypePlugins := range plugins {
		for name := range stypePlugins {
			var s string
			if stype != "" {
				s = stype + "."
			}
			s += name
			others = append(others, s)
		}
	}
	sort.Strings(others)
	for _, name := range others {
		p["others"] = append(p["others"], name)
	}
	return p
}
func ValidDirectives(serverType string) []string {
	stype, err := getServerType(serverType)
	if err != nil {
		return nil
	}
	return stype.Directives()
}
type ServerListener struct {
	server   Server
	listener net.Listener
	packet   net.PacketConn
}
func (s ServerListener) LocalAddr() net.Addr {
	if s.packet == nil {
		return nil
	}
	return s.packet.LocalAddr()
}
func (s ServerListener) Addr() net.Addr {
	if s.listener == nil {
		return nil
	}
	return s.listener.Addr()
}
type Context interface {
	InspectServerBlocks(string, []casketfile.ServerBlock) ([]casketfile.ServerBlock, error)
	MakeServers() ([]Server, error)
}
func RegisterServerType(typeName string, srv ServerType) {
	if _, ok := serverTypes[typeName]; ok {
		panic("server type already registered")
	}
	serverTypes[typeName] = srv
}
type ServerType struct {
	Directives func() []string
	DefaultInput func() Input
	NewContext func(inst *Instance) Context
}
type Plugin struct {
	ServerType string
	Action SetupFunc
}
func RegisterPlugin(name string, plugin Plugin) {
	if name == "" {
		panic("plugin must have a name")
	}
	if _, ok := plugins[plugin.ServerType]; !ok {
		plugins[plugin.ServerType] = make(map[string]Plugin)
	}
	if _, dup := plugins[plugin.ServerType][name]; dup {
		panic("plugin named " + name + " already registered for server type " + plugin.ServerType)
	}
	plugins[plugin.ServerType][name] = plugin
}
type EventName string
const (
	StartupEvent         EventName = "startup"
	ShutdownEvent                  = "shutdown"
	CertRenewEvent                 = "certrenew"
	InstanceStartupEvent           = "instancestartup"
	InstanceRestartEvent           = "instancerestart"
)
type EventHook func(eventType EventName, eventInfo interface{}) error
func RegisterEventHook(name string, hook EventHook) {
	if name == "" {
		panic("event hook must have a name")
	}
	_, dup := eventHooks.LoadOrStore(name, hook)
	if dup {
		panic("hook named " + name + " already registered")
	}
}
func EmitEvent(event EventName, info interface{}) {
	eventHooks.Range(func(k, v interface{}) bool {
		err := v.(EventHook)(event, info)
		if err != nil {
			log.Printf("error on '%s' hook: %v", k.(string), err)
		}
		return true
	})
}
func cloneEventHooks() *sync.Map {
	c := &sync.Map{}
	eventHooks.Range(func(k, v interface{}) bool {
		c.Store(k, v)
		return true
	})
	return c
}
func purgeEventHooks() {
	eventHooks.Range(func(k, _ interface{}) bool {
		eventHooks.Delete(k)
		return true
	})
}
func restoreEventHooks(m *sync.Map) {
	purgeEventHooks()
	m.Range(func(k, v interface{}) bool {
		eventHooks.Store(k, v)
		return true
	})
}
type ParsingCallback func(Context) error
func RegisterParsingCallback(serverType, afterDir string, callback ParsingCallback) {
	if _, ok := parsingCallbacks[serverType]; !ok {
		parsingCallbacks[serverType] = make(map[string][]ParsingCallback)
	}
	parsingCallbacks[serverType][afterDir] = append(parsingCallbacks[serverType][afterDir], callback)
}
type SetupFunc func(c *Controller) error
func DirectiveAction(serverType, dir string) (SetupFunc, error) {
	if stypePlugins, ok := plugins[serverType]; ok {
		if plugin, ok := stypePlugins[dir]; ok {
			return plugin.Action, nil
		}
	}
	if genericPlugins, ok := plugins[""]; ok {
		if plugin, ok := genericPlugins[dir]; ok {
			return plugin.Action, nil
		}
	}
	return nil, fmt.Errorf("no action found for directive '%s' with server type '%s' (missing a plugin?)",
		dir, serverType)
}
type Loader interface {
	Load(serverType string) (Input, error)
}
type LoaderFunc func(serverType string) (Input, error)