1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-20 02:57:05 +00:00

Begin work on message retention

- Refactor datastore such that we have a FileDataStore that implements
  the DataStore interface.
- Add in missing SMTP configuration options: max recips, max idle, max
  message size
- Add retention options to config
This commit is contained in:
James Hillyerd
2012-10-25 18:06:29 -07:00
parent 0db9aa8966
commit 45e1995d17
8 changed files with 255 additions and 85 deletions

View File

@@ -12,9 +12,12 @@ import (
// SmtpConfig houses the SMTP server configuration - not using pointers
// so that I can pass around copies of the object safely.
type SmtpConfig struct {
Ip4address net.IP
Ip4port int
Domain string
Ip4address net.IP
Ip4port int
Domain string
MaxRecipients int
MaxIdleSeconds int
MaxMessageBytes int
}
type WebConfig struct {
@@ -25,11 +28,21 @@ type WebConfig struct {
PublicDir string
}
var smtpConfig *SmtpConfig
type DataStoreConfig struct {
Path string
RetentionMinutes int
RetentionSleep int
}
var webConfig *WebConfig
var (
// Global goconfig object
Config *config.Config
var Config *config.Config
// Parsed specific configs
smtpConfig *SmtpConfig
webConfig *WebConfig
dataStoreConfig *DataStoreConfig
)
// GetSmtpConfig returns a copy of the SmtpConfig object
func GetSmtpConfig() SmtpConfig {
@@ -41,6 +54,11 @@ func GetWebConfig() WebConfig {
return *webConfig
}
// GetDataStoreConfig returns a copy of the DataStoreConfig object
func GetDataStoreConfig() DataStoreConfig {
return *dataStoreConfig
}
// LoadConfig loads the specified configuration file into inbucket.Config
// and performs validations on it.
func LoadConfig(filename string) error {
@@ -70,12 +88,19 @@ func LoadConfig(filename string) error {
requireOption(messages, "smtp", "ip4.address")
requireOption(messages, "smtp", "ip4.port")
requireOption(messages, "smtp", "domain")
requireOption(messages, "smtp", "max.recipients")
requireOption(messages, "smtp", "max.idle.seconds")
requireOption(messages, "smtp", "max.message.bytes")
requireOption(messages, "web", "ip4.address")
requireOption(messages, "web", "ip4.port")
requireOption(messages, "web", "template.dir")
requireOption(messages, "web", "template.cache")
requireOption(messages, "web", "public.dir")
requireOption(messages, "datastore", "path")
requireOption(messages, "datastore", "retention.minutes")
requireOption(messages, "datastore", "retention.sleep.millis")
// Return error if validations failed
if messages.Len() > 0 {
fmt.Fprintln(os.Stderr, "Error(s) validating configuration:")
for e := messages.Front(); e != nil; e = e.Next() {
@@ -96,15 +121,17 @@ func LoadConfig(filename string) error {
// parseLoggingConfig trying to catch config errors early
func parseLoggingConfig() error {
option := "[logging]level"
str, err := Config.String("logging", "level")
section := "logging"
option := "level"
str, err := Config.String(section, option)
if err != nil {
return fmt.Errorf("Failed to parse %v: %v", option, err)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
switch strings.ToUpper(str) {
case "TRACE", "INFO", "WARN", "ERROR":
default:
return fmt.Errorf("Invalid value provided for %v: %v", option, str)
return fmt.Errorf("Invalid value provided for [%v]%v: '%v'", section, option, str)
}
return nil
}
@@ -112,89 +139,135 @@ func parseLoggingConfig() error {
// parseSmtpConfig trying to catch config errors early
func parseSmtpConfig() error {
smtpConfig = new(SmtpConfig)
section := "smtp"
// Parse IP4 address only, error on IP6.
option := "[smtp]ip4.address"
str, err := Config.String("smtp", "ip4.address")
option := "ip4.address"
str, err := Config.String(section, option)
if err != nil {
return fmt.Errorf("Failed to parse %v: %v", option, err)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
addr := net.ParseIP(str)
if addr == nil {
return fmt.Errorf("Failed to parse %v '%v'", option, str)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
addr = addr.To4()
if addr == nil {
return fmt.Errorf("Failed to parse %v '%v' not IPv4!", option, str)
return fmt.Errorf("Failed to parse [%v]%v: '%v' not IPv4!", section, option, err)
}
smtpConfig.Ip4address = addr
option = "[smtp]ip4.port"
smtpConfig.Ip4port, err = Config.Int("smtp", "ip4.port")
option = "ip4.port"
smtpConfig.Ip4port, err = Config.Int(section, option)
if err != nil {
return fmt.Errorf("Failed to parse %v: %v", option, err)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
option = "[smtp]domain"
str, err = Config.String("smtp", "domain")
option = "domain"
str, err = Config.String(section, option)
if err != nil {
return fmt.Errorf("Failed to parse %v: %v", option, err)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
smtpConfig.Domain = str
option = "max.recipients"
smtpConfig.MaxRecipients, err = Config.Int(section, option)
if err != nil {
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
option = "max.idle.seconds"
smtpConfig.MaxIdleSeconds, err = Config.Int(section, option)
if err != nil {
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
option = "max.message.bytes"
smtpConfig.MaxMessageBytes, err = Config.Int(section, option)
if err != nil {
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
return nil
}
// parseWebConfig trying to catch config errors early
func parseWebConfig() error {
webConfig = new(WebConfig)
section := "web"
// Parse IP4 address only, error on IP6.
option := "[web]ip4.address"
str, err := Config.String("web", "ip4.address")
option := "ip4.address"
str, err := Config.String(section, option)
if err != nil {
return fmt.Errorf("Failed to parse %v: %v", option, err)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
addr := net.ParseIP(str)
if addr == nil {
return fmt.Errorf("Failed to parse %v '%v'", option, str)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
addr = addr.To4()
if addr == nil {
return fmt.Errorf("Failed to parse %v '%v' not IPv4!", option, str)
return fmt.Errorf("Failed to parse [%v]%v: '%v' not IPv4!", section, option, err)
}
webConfig.Ip4address = addr
option = "[web]ip4.port"
webConfig.Ip4port, err = Config.Int("web", "ip4.port")
option = "ip4.port"
webConfig.Ip4port, err = Config.Int(section, option)
if err != nil {
return fmt.Errorf("Failed to parse %v: %v", option, err)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
option = "[web]template.dir"
str, err = Config.String("web", "template.dir")
option = "template.dir"
str, err = Config.String(section, option)
if err != nil {
return fmt.Errorf("Failed to parse %v: %v", option, err)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
webConfig.TemplateDir = str
option = "[web]template.cache"
flag, err := Config.Bool("web", "template.cache")
option = "template.cache"
flag, err := Config.Bool(section, option)
if err != nil {
return fmt.Errorf("Failed to parse %v: %v", option, err)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
webConfig.TemplateCache = flag
option = "[web]public.dir"
str, err = Config.String("web", "public.dir")
option = "public.dir"
str, err = Config.String(section, option)
if err != nil {
return fmt.Errorf("Failed to parse %v: %v", option, err)
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
webConfig.PublicDir = str
return nil
}
// parseDataStoreConfig trying to catch config errors early
func parseDataStoreConfig() error {
dataStoreConfig = new(DataStoreConfig)
section := "datastore"
option := "path"
str, err := Config.String(section, option)
if err != nil {
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
dataStoreConfig.Path = str
option = "retention.minutes"
dataStoreConfig.RetentionMinutes, err = Config.Int(section, option)
if err != nil {
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
option = "retention.sleep.millis"
dataStoreConfig.RetentionSleep, err = Config.Int(section, option)
if err != nil {
return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err)
}
return nil
}
// requireSection checks that a [section] is defined in the configuration file,
// appending a message if not.
func requireSection(messages *list.List, section string) {