func Started() bool {
	mu.Lock()
	defer mu.Unlock()
	return started
}
Started returns true if at least one instance has been
started by this package. It never gets reset to false
once it is set to true.
package casket
import (
	"bytes"
	"encoding/gob"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
	"github.com/tmpim/casket/casketfile"
	"github.com/tmpim/casket/telemetry"
)
var (
	AppName string
	AppVersion string
	Quiet bool
	PidFile string
	GracefulTimeout time.Duration
	isUpgrade = os.Getenv("CASKET__UPGRADE") == "1"
	started bool
	mu sync.Mutex
)
func init() {
	OnProcessExit = append(OnProcessExit, func() {
		if PidFile != "" {
			os.Remove(PidFile)
		}
	})
}
type Instance struct {
	serverType string
	casketfileInput Input
	wg *sync.WaitGroup
	context Context
	servers []ServerListener
	OnFirstStartup  []func() error  
	OnStartup       []func() error  
	OnRestart       []func() error  
	OnRestartFailed []func() error  
	OnShutdown      []func() error  
	OnFinalShutdown []func() error  
	Storage   map[interface{}]interface{}
	StorageMu sync.RWMutex
}
func Instances() []*Instance {
	return instances
}
func (i *Instance) Servers() []ServerListener { return i.servers }
func (i *Instance) Stop() error {
	for _, s := range i.servers {
		if gs, ok := s.server.(GracefulServer); ok {
			if err := gs.Stop(); err != nil {
				log.Printf("[ERROR] Stopping %s: %v", gs.Address(), err)
			}
		}
	}
	instancesMu.Lock()
	for j, other := range instances {
		if other == i {
			instances = append(instances[:j], instances[j+1:]...)
			break
		}
	}
	instancesMu.Unlock()
	return nil
}
func (i *Instance) ShutdownCallbacks() []error {
	var errs []error
	for _, shutdownFunc := range i.OnShutdown {
		err := shutdownFunc()
		if err != nil {
			errs = append(errs, err)
		}
	}
	for _, finalShutdownFunc := range i.OnFinalShutdown {
		err := finalShutdownFunc()
		if err != nil {
			errs = append(errs, err)
		}
	}
	return errs
}
func (i *Instance) Restart(newCasketfile Input) (*Instance, error) {
	log.Println("[INFO] Reloading")
	i.wg.Add(1)
	defer i.wg.Done()
	var err error
	defer func() {
		r := recover()
		if err != nil || r != nil {
			for _, fn := range i.OnRestartFailed {
				if err := fn(); err != nil {
					log.Printf("[ERROR] Restart failed callback returned error: %v", err)
				}
			}
			if err != nil {
				log.Printf("[ERROR] Restart failed: %v", err)
			}
			if r != nil {
				log.Printf("[PANIC] Restart: %v", r)
			}
		}
	}()
	for _, fn := range i.OnRestart {
		err = fn()
		if err != nil {
			return i, err
		}
	}
	if newCasketfile == nil {
		newCasketfile = i.casketfileInput
	}
	restartFds := make(map[string]restartTriple)
	for _, s := range i.servers {
		gs, srvOk := s.server.(GracefulServer)
		ln, lnOk := s.listener.(Listener)
		pc, pcOk := s.packet.(PacketConn)
		if srvOk {
			if lnOk && pcOk {
				restartFds[gs.Address()] = restartTriple{server: gs, listener: ln, packet: pc}
				continue
			}
			if lnOk {
				restartFds[gs.Address()] = restartTriple{server: gs, listener: ln}
				continue
			}
			if pcOk {
				restartFds[gs.Address()] = restartTriple{server: gs, packet: pc}
				continue
			}
		}
	}
	newInst := &Instance{serverType: newCasketfile.ServerType(), wg: i.wg, Storage: make(map[interface{}]interface{})}
	err = startWithListenerFds(newCasketfile, newInst, restartFds)
	if err != nil {
		return i, fmt.Errorf("starting with listener file descriptors: %v", err)
	}
	err = i.Stop()
	if err != nil {
		return i, err
	}
	for _, shutdownFunc := range i.OnShutdown {
		err = shutdownFunc()
		if err != nil {
			return i, err
		}
	}
	EmitEvent(InstanceStartupEvent, newInst)
	log.Println("[INFO] Reloading complete")
	return newInst, nil
}
func (i *Instance) SaveServer(s Server, ln net.Listener) {
	i.servers = append(i.servers, ServerListener{server: s, listener: ln})
}
type TCPServer interface {
	Listen() (net.Listener, error)
	Serve(net.Listener) error
}
type UDPServer interface {
	ListenPacket() (net.PacketConn, error)
	ServePacket(net.PacketConn) error
}
type Server interface {
	TCPServer
	UDPServer
}
type Stopper interface {
	Stop() error
}
type GracefulServer interface {
	Server
	Stopper
	Address() string
	WrapListener(net.Listener) net.Listener
}
type Listener interface {
	net.Listener
	File() (*os.File, error)
}
type PacketConn interface {
	net.PacketConn
	File() (*os.File, error)
}
type AfterStartup interface {
	OnStartupComplete()
}
func LoadCasketfile(serverType string) (Input, error) {
	if IsUpgrade() {
		err := gob.NewDecoder(os.Stdin).Decode(&loadedGob)
		if err != nil {
			return nil, err
		}
		return loadedGob.Casketfile, nil
	}
	cdyfile, err := loadCasketfileInput(serverType)
	if err != nil {
		return nil, err
	}
	if cdyfile == nil {
		cdyfile = DefaultInput(serverType)
	}
	if cdyfile == nil {
		cdyfile = CasketfileInput{ServerTypeName: serverType}
	}
	return cdyfile, nil
}
func (i *Instance) Wait() {
	i.wg.Wait()
}
func CasketfileFromPipe(f *os.File, serverType string) (Input, error) {
	fi, err := f.Stat()
	if err == nil && fi.Mode()&os.ModeCharDevice == 0 {
		confBody, err := ioutil.ReadAll(f)
		if err != nil {
			return nil, err
		}
		return CasketfileInput{
			Contents:       confBody,
			Filepath:       f.Name(),
			ServerTypeName: serverType,
		}, nil
	}
	return nil, nil
}
func (i *Instance) Casketfile() Input {
	return i.casketfileInput
}
func Start(cdyfile Input) (*Instance, error) {
	inst := &Instance{serverType: cdyfile.ServerType(), wg: new(sync.WaitGroup), Storage: make(map[interface{}]interface{})}
	err := startWithListenerFds(cdyfile, inst, nil)
	if err != nil {
		return inst, err
	}
	signalSuccessToParent()
	if pidErr := writePidFile(); pidErr != nil {
		log.Printf("[ERROR] Could not write pidfile: %v", pidErr)
	}
	EmitEvent(InstanceStartupEvent, inst)
	return inst, nil
}
func startWithListenerFds(cdyfile Input, inst *Instance, restartFds map[string]restartTriple) error {
	instancesMu.Lock()
	instances = append(instances, inst)
	instancesMu.Unlock()
	var err error
	defer func() {
		if err != nil {
			instancesMu.Lock()
			for i, otherInst := range instances {
				if otherInst == inst {
					instances = append(instances[:i], instances[i+1:]...)
					break
				}
			}
			instancesMu.Unlock()
		}
	}()
	if cdyfile == nil {
		cdyfile = CasketfileInput{}
	}
	err = ValidateAndExecuteDirectives(cdyfile, inst, false)
	if err != nil {
		return err
	}
	slist, err := inst.context.MakeServers()
	if err != nil {
		return err
	}
	if !IsUpgrade() && restartFds == nil {
		for _, firstStartupFunc := range inst.OnFirstStartup {
			err = firstStartupFunc()
			if err != nil {
				return err
			}
		}
	}
	for _, startupFunc := range inst.OnStartup {
		err = startupFunc()
		if err != nil {
			return err
		}
	}
	err = startServers(slist, inst, restartFds)
	if err != nil {
		return err
	}
	if restartFds == nil {
		for _, srvln := range inst.servers {
			if srv, ok := srvln.server.(AfterStartup); ok {
				srv.OnStartupComplete()
			}
		}
		if !Quiet {
			for _, srvln := range inst.servers {
				if srvln.listener == nil {
					continue
				}
				if !IsLoopback(srvln.listener.Addr().String()) {
					checkFdlimit()
					break
				}
			}
		}
	}
	mu.Lock()
	started = true
	mu.Unlock()
	return nil
}
func ValidateAndExecuteDirectives(cdyfile Input, inst *Instance, justValidate bool) error {
	if justValidate {
		inst = &Instance{serverType: cdyfile.ServerType(), wg: new(sync.WaitGroup), Storage: make(map[interface{}]interface{})}
	}
	stypeName := cdyfile.ServerType()
	stype, err := getServerType(stypeName)
	if err != nil {
		return err
	}
	inst.casketfileInput = cdyfile
	sblocks, err := loadServerBlocks(stypeName, cdyfile.Path(), bytes.NewReader(cdyfile.Body()))
	if err != nil {
		return err
	}
	for _, sb := range sblocks {
		for dir := range sb.Tokens {
			telemetry.AppendUnique("directives", dir)
		}
	}
	inst.context = stype.NewContext(inst)
	if inst.context == nil {
		return fmt.Errorf("server type %s produced a nil Context", stypeName)
	}
	sblocks, err = inst.context.InspectServerBlocks(cdyfile.Path(), sblocks)
	if err != nil {
		return fmt.Errorf("error inspecting server blocks: %v", err)
	}
	telemetry.Set("num_server_blocks", len(sblocks))
	return executeDirectives(inst, cdyfile.Path(), stype.Directives(), sblocks, justValidate)
}
func executeDirectives(inst *Instance, filename string,
	directives []string, sblocks []casketfile.ServerBlock, justValidate bool) error {
	storages := make(map[int]map[string]interface{})
	for _, dir := range directives {
		for i, sb := range sblocks {
			var once sync.Once
			if _, ok := storages[i]; !ok {
				storages[i] = make(map[string]interface{})
			}
			for j, key := range sb.Keys {
				if tokens, ok := sb.Tokens[dir]; ok {
					controller := &Controller{
						instance:  inst,
						Key:       key,
						Dispenser: casketfile.NewDispenserTokens(filename, tokens),
						OncePerServerBlock: func(f func() error) error {
							var err error
							once.Do(func() {
								err = f()
							})
							return err
						},
						ServerBlockIndex:    i,
						ServerBlockKeyIndex: j,
						ServerBlockKeys:     sb.Keys,
						ServerBlockStorage:  storages[i][dir],
					}
					setup, err := DirectiveAction(inst.serverType, dir)
					if err != nil {
						return err
					}
					err = setup(controller)
					if err != nil {
						return err
					}
					storages[i][dir] = controller.ServerBlockStorage  
				}
			}
		}
		if !justValidate {
			if allCallbacks, ok := parsingCallbacks[inst.serverType]; ok {
				callbacks := allCallbacks[dir]
				for _, callback := range callbacks {
					if err := callback(inst.context); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}
func startServers(serverList []Server, inst *Instance, restartFds map[string]restartTriple) error {
	errChan := make(chan error, len(serverList))
	stopChan := make(chan struct{})
	stopWg := &sync.WaitGroup{}
	for _, s := range serverList {
		var (
			ln  net.Listener
			pc  net.PacketConn
			err error
		)
		if IsUpgrade() {
			if gs, ok := s.(GracefulServer); ok {
				addr := gs.Address()
				if fdIndex, ok := loadedGob.ListenerFds["tcp"+addr]; ok {
					file := os.NewFile(fdIndex, "")
					ln, err = net.FileListener(file)
					if err != nil {
						return fmt.Errorf("making listener from file: %v", err)
					}
					err = file.Close()
					if err != nil {
						return fmt.Errorf("closing copy of listener file: %v", err)
					}
				}
				if fdIndex, ok := loadedGob.ListenerFds["udp"+addr]; ok {
					file := os.NewFile(fdIndex, "")
					pc, err = net.FilePacketConn(file)
					if err != nil {
						return fmt.Errorf("making packet connection from file: %v", err)
					}
					err = file.Close()
					if err != nil {
						return fmt.Errorf("closing copy of packet connection file: %v", err)
					}
				}
				ln = gs.WrapListener(ln)
			}
		}
		if gs, ok := s.(GracefulServer); ok && restartFds != nil {
			addr := gs.Address()
			if old, ok := restartFds[addr]; ok {
				if old.listener != nil {
					file, err := old.listener.File()
					if err != nil {
						return fmt.Errorf("getting old listener file: %v", err)
					}
					ln, err = net.FileListener(file)
					if err != nil {
						return fmt.Errorf("getting file listener: %v", err)
					}
					err = file.Close()
					if err != nil {
						return fmt.Errorf("closing copy of listener file: %v", err)
					}
				}
				if old.packet != nil {
					file, err := old.packet.File()
					if err != nil {
						return fmt.Errorf("getting old packet file: %v", err)
					}
					pc, err = net.FilePacketConn(file)
					if err != nil {
						return fmt.Errorf("getting file packet connection: %v", err)
					}
					err = file.Close()
					if err != nil {
						return fmt.Errorf("close copy of packet file: %v", err)
					}
				}
				ln = gs.WrapListener(ln)
			}
		}
		if ln == nil {
			ln, err = s.Listen()
			if err != nil {
				return fmt.Errorf("Listen: %v", err)
			}
		}
		if pc == nil {
			pc, err = s.ListenPacket()
			if err != nil {
				return fmt.Errorf("ListenPacket: %v", err)
			}
		}
		inst.servers = append(inst.servers, ServerListener{server: s, listener: ln, packet: pc})
	}
	for _, s := range inst.servers {
		inst.wg.Add(2)
		stopWg.Add(2)
		func(s Server, ln net.Listener, pc net.PacketConn, inst *Instance) {
			go func() {
				defer func() {
					inst.wg.Done()
					stopWg.Done()
				}()
				errChan <- s.Serve(ln)
			}()
			go func() {
				defer func() {
					inst.wg.Done()
					stopWg.Done()
				}()
				errChan <- s.ServePacket(pc)
			}()
		}(s.server, s.listener, s.packet, inst)
	}
	go func() {
		for {
			select {
			case err := <-errChan:
				if err != nil {
					if !strings.Contains(err.Error(), "use of closed network connection") {
						log.Println(err)
					}
				}
			case <-stopChan:
				return
			}
		}
	}()
	go func() {
		stopWg.Wait()
		stopChan <- struct{}{}
	}()
	return nil
}
func getServerType(serverType string) (ServerType, error) {
	stype, ok := serverTypes[serverType]
	if ok {
		return stype, nil
	}
	if len(serverTypes) == 0 {
		return ServerType{}, fmt.Errorf("no server types plugged in")
	}
	if serverType == "" {
		if len(serverTypes) == 1 {
			for _, stype := range serverTypes {
				return stype, nil
			}
		}
		return ServerType{}, fmt.Errorf("multiple server types available; must choose one")
	}
	return ServerType{}, fmt.Errorf("unknown server type '%s'", serverType)
}
func loadServerBlocks(serverType, filename string, input io.Reader) ([]casketfile.ServerBlock, error) {
	validDirectives := ValidDirectives(serverType)
	serverBlocks, err := casketfile.Parse(filename, input, validDirectives)
	if err != nil {
		return nil, err
	}
	if len(serverBlocks) == 0 && serverTypes[serverType].DefaultInput != nil {
		newInput := serverTypes[serverType].DefaultInput()
		serverBlocks, err = casketfile.Parse(newInput.Path(),
			bytes.NewReader(newInput.Body()), validDirectives)
		if err != nil {
			return nil, err
		}
	}
	return serverBlocks, nil
}
func Stop() error {
	for {
		instancesMu.Lock()
		if len(instances) == 0 {
			instancesMu.Unlock()
			break
		}
		inst := instances[0]
		instancesMu.Unlock()
		inst.wg.Add(1)
		defer inst.wg.Done()
		if err := inst.Stop(); err != nil {
			log.Printf("[ERROR] Stopping %s: %v", inst.serverType, err)
		}
	}
	return nil
}
func IsLoopback(addr string) bool {
	host, _, err := net.SplitHostPort(strings.ToLower(addr))
	if err != nil {
		host = addr  
	}
	return host == "localhost" ||
		strings.Trim(host, "[]") == "::1" ||
		strings.HasPrefix(host, "127.") ||
		strings.HasSuffix(host, ".localhost")
}
func IsInternal(addr string) bool {
	privateNetworks := []string{
		"10.0.0.0/8",
		"172.16.0.0/12",
		"192.168.0.0/16",
		"fc00::/7",
	}
	privateTLDs := []string{
		".example", ".invalid", ".test", ".local",
	}
	host, _, err := net.SplitHostPort(addr)
	if err != nil {
		host = addr  
		host = strings.Trim(host, "[]")
	}
	for _, tld := range privateTLDs {
		if strings.HasSuffix(host, tld) {
			return true
		}
	}
	ip := net.ParseIP(host)
	if ip == nil {
		return false
	}
	for _, privateNetwork := range privateNetworks {
		_, ipnet, _ := net.ParseCIDR(privateNetwork)
		if ipnet.Contains(ip) {
			return true
		}
	}
	return false
}