func (sc *ServerConfig) emitChangeEvents(oldServer *ServerConfig, app Guerrilla) {
	changes := getChanges(
		*oldServer,
		*sc,
	)
	tlsChanges := getChanges(
		(*oldServer).TLS,
		(*sc).TLS,
	)
	if len(changes) > 0 || len(tlsChanges) > 0 {
		app.Publish(EventConfigServerConfig, sc)
	}
	if _, ok := changes["IsEnabled"]; ok {
		if sc.IsEnabled {
			app.Publish(EventConfigServerStart, sc)
		} else {
			app.Publish(EventConfigServerStop, sc)
		}
		return
	}
	if _, ok := changes["LogFile"]; ok {
		app.Publish(EventConfigServerLogFile, sc)
	} else {
		app.Publish(EventConfigServerLogReopen, sc)
	}
	if _, ok := changes["Timeout"]; ok {
		app.Publish(EventConfigServerTimeout, sc)
	}
	if _, ok := changes["MaxClients"]; ok {
		app.Publish(EventConfigServerMaxClients, sc)
	}
	if len(tlsChanges) > 0 {
		app.Publish(EventConfigServerTLSConfig, sc)
	}
}
Emits any configuration change events on the server.
All events are fired and run synchronously
package guerrilla
import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"reflect"
	"strings"
	"time"
	"github.com/flashmob/go-guerrilla/backends"
	"github.com/flashmob/go-guerrilla/log"
)
type AppConfig struct {
	Servers []ServerConfig `json:"servers"`
	AllowedHosts []string `json:"allowed_hosts"`
	PidFile string `json:"pid_file"`
	LogFile string `json:"log_file,omitempty"`
	LogLevel string `json:"log_level,omitempty"`
	BackendConfig backends.BackendConfig `json:"backend_config"`
}
type ServerConfig struct {
	TLS ServerTLSConfig `json:"tls,omitempty"`
	LogFile string `json:"log_file,omitempty"`
	Hostname string `json:"host_name"`
	ListenInterface string `json:"listen_interface"`
	MaxSize int64 `json:"max_size"`
	Timeout int `json:"timeout"`
	MaxClients int `json:"max_clients"`
	IsEnabled bool `json:"is_enabled"`
	XClientOn bool `json:"xclient_on,omitempty"`
}
type ServerTLSConfig struct {
	Protocols []string `json:"protocols,omitempty"`
	Ciphers []string `json:"ciphers,omitempty"`
	Curves []string `json:"curves,omitempty"`
	PrivateKeyFile string `json:"private_key_file"`
	PublicKeyFile string `json:"public_key_file"`
	RootCAs string `json:"root_cas_file,omitempty"`
	ClientAuthType string `json:"client_auth_type,omitempty"`
	_privateKeyFileMtime int64
	_publicKeyFileMtime  int64
	PreferServerCipherSuites bool `json:"prefer_server_cipher_suites,omitempty"`
	StartTLSOn bool `json:"start_tls_on,omitempty"`
	AlwaysOn bool `json:"tls_always_on,omitempty"`
}
var TLSCiphers = map[string]uint16{
	"TLS_RSA_WITH_3DES_EDE_CBC_SHA":        tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
	"TLS_RSA_WITH_AES_128_CBC_SHA":         tls.TLS_RSA_WITH_AES_128_CBC_SHA,
	"TLS_RSA_WITH_AES_256_CBC_SHA":         tls.TLS_RSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":  tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":   tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":   tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
	"TLS_RSA_WITH_RC4_128_SHA":        tls.TLS_RSA_WITH_RC4_128_SHA,
	"TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
	"TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":        tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_RSA_WITH_RC4_128_SHA":          tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
	"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":   tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
}
var TLSProtocols = map[string]uint16{
	"tls1.0": tls.VersionTLS10,
	"tls1.1": tls.VersionTLS11,
	"tls1.2": tls.VersionTLS12,
}
var TLSCurves = map[string]tls.CurveID{
	"P256": tls.CurveP256,
	"P384": tls.CurveP384,
	"P521": tls.CurveP521,
}
var TLSClientAuthTypes = map[string]tls.ClientAuthType{
	"NoClientCert":               tls.NoClientCert,
	"RequestClientCert":          tls.RequestClientCert,
	"RequireAnyClientCert":       tls.RequireAnyClientCert,
	"VerifyClientCertIfGiven":    tls.VerifyClientCertIfGiven,
	"RequireAndVerifyClientCert": tls.RequireAndVerifyClientCert,
}
const defaultMaxClients = 100
const defaultTimeout = 30
const defaultInterface = "127.0.0.1:2525"
const defaultMaxSize = int64(10 << 20)  
func (c *AppConfig) Load(jsonBytes []byte) error {
	err := json.Unmarshal(jsonBytes, c)
	if err != nil {
		return fmt.Errorf("could not parse config file: %s", err)
	}
	if err = c.setDefaults(); err != nil {
		return err
	}
	if err = c.setBackendDefaults(); err != nil {
		return err
	}
	for _, server := range c.Servers {
		if errs := server.Validate(); errs != nil {
			return errs
		}
	}
	for i := 0; i < len(c.Servers); i++ {
		if err := c.Servers[i].loadTlsKeyTimestamps(); err != nil {
			return err
		}
	}
	return nil
}
func (c *AppConfig) EmitChangeEvents(oldConfig *AppConfig, app Guerrilla) {
	if !reflect.DeepEqual((*c).BackendConfig, (*oldConfig).BackendConfig) {
		app.Publish(EventConfigBackendConfig, c)
	}
	if !reflect.DeepEqual(oldConfig, c) {
		app.Publish(EventConfigNewConfig, c)
	}
	if !reflect.DeepEqual(oldConfig.AllowedHosts, c.AllowedHosts) {
		app.Publish(EventConfigAllowedHosts, c)
	}
	if strings.Compare(oldConfig.PidFile, c.PidFile) != 0 {
		app.Publish(EventConfigPidFile, c)
	}
	if strings.Compare(oldConfig.LogFile, c.LogFile) != 0 {
		app.Publish(EventConfigLogFile, c)
	}
	if strings.Compare(oldConfig.LogLevel, c.LogLevel) != 0 {
		app.Publish(EventConfigLogLevel, c)
	}
	oldServers := oldConfig.getServers()
	for iface, newServer := range c.getServers() {
		if oldServer, ok := oldServers[iface]; ok {
			delete(oldServers, iface)
			newServer.emitChangeEvents(oldServer, app)
		} else {
			app.Publish(EventConfigServerNew, newServer)
		}
	}
	for _, oldServer := range oldServers {
		app.Publish(EventConfigServerRemove, oldServer)
	}
}
func (c *AppConfig) EmitLogReopenEvents(app Guerrilla) {
	app.Publish(EventConfigLogReopen, c)
	for _, sc := range c.getServers() {
		app.Publish(EventConfigServerLogReopen, sc)
	}
}
func (c *AppConfig) getServers() map[string]*ServerConfig {
	servers := make(map[string]*ServerConfig, len(c.Servers))
	for i := 0; i < len(c.Servers); i++ {
		servers[c.Servers[i].ListenInterface] = &c.Servers[i]
	}
	return servers
}
func (c *AppConfig) setDefaults() error {
	if c.LogFile == "" {
		c.LogFile = log.OutputStderr.String()
	}
	if c.LogLevel == "" {
		c.LogLevel = "debug"
	}
	if len(c.AllowedHosts) == 0 {
		if h, err := os.Hostname(); err != nil {
			return err
		} else {
			c.AllowedHosts = append(c.AllowedHosts, h)
		}
	}
	h, err := os.Hostname()
	if err != nil {
		return err
	}
	if len(c.Servers) == 0 {
		sc := ServerConfig{}
		sc.LogFile = c.LogFile
		sc.ListenInterface = defaultInterface
		sc.IsEnabled = true
		sc.Hostname = h
		sc.MaxClients = defaultMaxClients
		sc.Timeout = defaultTimeout
		sc.MaxSize = defaultMaxSize
		c.Servers = append(c.Servers, sc)
	} else {
		for i := range c.Servers {
			if c.Servers[i].Hostname == "" {
				c.Servers[i].Hostname = h
			}
			if c.Servers[i].MaxClients == 0 {
				c.Servers[i].MaxClients = defaultMaxClients
			}
			if c.Servers[i].Timeout == 0 {
				c.Servers[i].Timeout = defaultTimeout
			}
			if c.Servers[i].MaxSize == 0 {
				c.Servers[i].MaxSize = defaultMaxSize  
			}
			if c.Servers[i].ListenInterface == "" {
				return fmt.Errorf("listen interface not specified for server at index %d", i)
			}
			if c.Servers[i].LogFile == "" {
				c.Servers[i].LogFile = c.LogFile
			}
			err = c.Servers[i].Validate()
			if err != nil {
				return err
			}
		}
	}
	return nil
}
func (c *AppConfig) setBackendDefaults() error {
	if len(c.BackendConfig) == 0 {
		h, err := os.Hostname()
		if err != nil {
			return err
		}
		c.BackendConfig = backends.BackendConfig{
			"log_received_mails": true,
			"save_workers_size":  1,
			"save_process":       "HeadersParser|Header|Debugger",
			"primary_mail_host":  h,
		}
	} else {
		if _, ok := c.BackendConfig["save_process"]; !ok {
			c.BackendConfig["save_process"] = "HeadersParser|Header|Debugger"
		}
		if _, ok := c.BackendConfig["primary_mail_host"]; !ok {
			h, err := os.Hostname()
			if err != nil {
				return err
			}
			c.BackendConfig["primary_mail_host"] = h
		}
		if _, ok := c.BackendConfig["save_workers_size"]; !ok {
			c.BackendConfig["save_workers_size"] = 1
		}
		if _, ok := c.BackendConfig["log_received_mails"]; !ok {
			c.BackendConfig["log_received_mails"] = false
		}
	}
	return nil
}