func (timeoutOptions *TimeoutOptions) Parse(config map[interface{}]interface{}) error {
	if interfaceVal, ok := config["readTimeout"]; ok {
		if readTimeoutStr, ok := interfaceVal.(string); ok {
			if readTimeout, err := time.ParseDuration(readTimeoutStr); err == nil {
				timeoutOptions.ReadTimeout = readTimeout
			} else {
				return fmt.Errorf("could not parse readTimeout %s as a duration (e.g. 1m): %v", readTimeoutStr, err)
			}
		} else {
			return errors.New("could not use value for readTimeout, not a string")
		}
	}
	if interfaceVal, ok := config["idleTimeout"]; ok {
		if idleTimeoutStr, ok := interfaceVal.(string); ok {
			if idleTimeout, err := time.ParseDuration(idleTimeoutStr); err == nil {
				timeoutOptions.IdleTimeout = idleTimeout
			} else {
				return fmt.Errorf("could not parse idleTimeout %s as a duration (e.g. 1m): %v", idleTimeoutStr, err)
			}
		} else {
			return errors.New("could not use value for idleTimeout, not a string")
		}
	}
	if interfaceVal, ok := config["writeTimeout"]; ok {
		if writeTimeoutStr, ok := interfaceVal.(string); ok {
			if writeTimeout, err := time.ParseDuration(writeTimeoutStr); err == nil {
				timeoutOptions.WriteTimeout = writeTimeout
			} else {
				return fmt.Errorf("could not parse writeTimeout %s as a duration (e.g. 1m): %v", writeTimeoutStr, err)
			}
		} else {
			return errors.New("could not use value for writeTimeout, not a string")
		}
	}
	return nil
}
Parse parses a config map
package xweb
import (
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/openziti/foundation/identity/identity"
	"time"
)
type Config struct {
	SourceConfig map[interface{}]interface{}
	WebListeners []*WebListener
	WebSection   string
	DefaultIdentity        identity.Identity
	DefaultIdentitySection string
	defaultIdentityConfig *identity.Config
	enabled bool
}
func (config *Config) Parse(configMap map[interface{}]interface{}) error {
	config.SourceConfig = configMap
	if config.DefaultIdentity == nil && config.DefaultIdentitySection == "" {
		return errors.New("identity section not specified for configuration, must be specified if a default identity is not provided")
	}
	if config.WebSection == "" {
		return errors.New("web section not specified for configuration")
	}
	if config.DefaultIdentity == nil {
		if identityInterface, ok := configMap[config.DefaultIdentitySection]; ok {
			if identityMap, ok := identityInterface.(map[interface{}]interface{}); ok {
				if identityConfig, err := parseIdentityConfig(identityMap, config.DefaultIdentitySection); err == nil {
					config.defaultIdentityConfig = identityConfig
				} else {
					return fmt.Errorf("error parsing root identity section [%s] : %v", config.DefaultIdentitySection, err)
				}
			} else {
				return fmt.Errorf("root identity section [%s] must be a map", config.DefaultIdentitySection)
			}
		} else {
			return fmt.Errorf("root identity section [%s] must be defined", config.DefaultIdentitySection)
		}
	} else {
		config.defaultIdentityConfig = config.DefaultIdentity.GetConfig()
	}
	if webInterface, ok := configMap[config.WebSection]; ok {
		if webArrayInterface, ok := webInterface.([]interface{}); ok {
			for i, webInterface := range webArrayInterface {
				if webMap, ok := webInterface.(map[interface{}]interface{}); ok {
					webListener := &WebListener{
						DefaultIdentity: config.DefaultIdentity,
					}
					if err := webListener.Parse(webMap, config.WebSection); err != nil {
						return fmt.Errorf("error parsing web configuration [%s] at index [%d]: %v", config.WebSection, i, err)
					}
					config.WebListeners = append(config.WebListeners, webListener)
				} else {
					return fmt.Errorf("error parsing web configuration [%s] at index [%d]: not a map", config.WebSection, i)
				}
			}
		} else {
			return fmt.Errorf("%s identity section [%s] must be a map", config.WebSection, config.DefaultIdentitySection)
		}
	}
	return nil
}
func (config *Config) Validate(registry WebHandlerFactoryRegistry) error {
	if config.DefaultIdentity == nil {
		if defaultIdentity, err := identity.LoadIdentity(*config.defaultIdentityConfig); err == nil {
			config.DefaultIdentity = defaultIdentity
		} else {
			return fmt.Errorf("could not load default identity: %v", err)
		}
		for _, webListener := range config.WebListeners {
			webListener.DefaultIdentity = config.DefaultIdentity
		}
	}
	presentApis := map[string]WebHandlerFactory{}
	for i, webListener := range config.WebListeners {
		if err := webListener.Validate(registry); err != nil {
			return fmt.Errorf("could not validate web listener at %s[%d]: %v", config.WebSection, i, err)
		}
		for _, api := range webListener.APIs {
			presentApis[api.Binding()] = registry.Get(api.Binding())
		}
	}
	for presentApiBinding, presentApiFactory := range presentApis {
		if err := presentApiFactory.Validate(config); err != nil {
			return fmt.Errorf("error validating API binding %s: %v", presentApiBinding, err)
		}
	}
	config.enabled = true
	return nil
}
func (config *Config) Enabled() bool {
	return config.enabled
}
type Options struct {
	TimeoutOptions
	TlsVersionOptions
}
func (options *Options) Default() {
	options.TimeoutOptions.Default()
	options.TlsVersionOptions.Default()
}
func (options *Options) Parse(optionsMap map[interface{}]interface{}) error {
	if err := options.TimeoutOptions.Parse(optionsMap); err != nil {
		return fmt.Errorf("error parsing options: %v", err)
	}
	if err := options.TlsVersionOptions.Parse(optionsMap); err != nil {
		return fmt.Errorf("error parsing options: %v", err)
	}
	return nil
}
type TimeoutOptions struct {
	ReadTimeout  time.Duration
	IdleTimeout  time.Duration
	WriteTimeout time.Duration
}
func (timeoutOptions *TimeoutOptions) Default() {
	timeoutOptions.WriteTimeout = time.Second * 10
	timeoutOptions.ReadTimeout = time.Second * 5
	timeoutOptions.IdleTimeout = time.Second * 5
}