mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 09:37:02 +00:00
storage: Make type/params configurable for #88
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||
"github.com/jhillyerd/inbucket/pkg/storage/file"
|
||||
"github.com/jhillyerd/inbucket/pkg/storage/mem"
|
||||
"github.com/jhillyerd/inbucket/pkg/webui"
|
||||
)
|
||||
|
||||
@@ -45,6 +46,10 @@ func init() {
|
||||
expvar.Publish("goroutines", expvar.Func(func() interface{} {
|
||||
return runtime.NumGoroutine()
|
||||
}))
|
||||
|
||||
// Register storage implementations.
|
||||
storage.Constructors["file"] = file.New
|
||||
storage.Constructors["memory"] = mem.New
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -97,8 +102,13 @@ func main() {
|
||||
// Configure internal services.
|
||||
rootCtx, rootCancel := context.WithCancel(context.Background())
|
||||
shutdownChan := make(chan bool)
|
||||
store, err := storage.FromConfig(conf.Storage)
|
||||
if err != nil {
|
||||
log.Errorf("Fatal storage error: %v", err)
|
||||
removePIDFile(*pidfile)
|
||||
os.Exit(1)
|
||||
}
|
||||
msgHub := msghub.New(rootCtx, conf.Web.MonitorHistory)
|
||||
store := file.New(conf.Storage)
|
||||
addrPolicy := &policy.Addressing{Config: conf.SMTP}
|
||||
mmanager := &message.StoreManager{Store: store, Hub: msgHub}
|
||||
// Start Retention scanner.
|
||||
|
||||
@@ -69,10 +69,11 @@ type Web struct {
|
||||
|
||||
// Storage contains the mail store configuration.
|
||||
type Storage struct {
|
||||
Path string `required:"true" default:"/tmp/inbucket" desc:"Mail store path"`
|
||||
RetentionPeriod time.Duration `required:"true" default:"24h" desc:"Duration to retain messages"`
|
||||
RetentionSleep time.Duration `required:"true" default:"50ms" desc:"Duration to sleep between mailboxes"`
|
||||
MailboxMsgCap int `required:"true" default:"500" desc:"Maximum messages per mailbox"`
|
||||
Type string `required:"true" default:"memory" desc:"Storage impl: file or memory"`
|
||||
Params map[string]string `desc:"Storage impl parameters, see docs."`
|
||||
RetentionPeriod time.Duration `required:"true" default:"24h" desc:"Duration to retain messages"`
|
||||
RetentionSleep time.Duration `required:"true" default:"50ms" desc:"Duration to sleep between mailboxes"`
|
||||
MailboxMsgCap int `required:"true" default:"500" desc:"Maximum messages per mailbox"`
|
||||
}
|
||||
|
||||
// Process loads and parses configuration from the environment.
|
||||
|
||||
@@ -48,11 +48,10 @@ type Store struct {
|
||||
}
|
||||
|
||||
// New creates a new DataStore object using the specified path
|
||||
func New(cfg config.Storage) storage.Store {
|
||||
path := cfg.Path
|
||||
func New(cfg config.Storage) (storage.Store, error) {
|
||||
path := cfg.Params["path"]
|
||||
if path == "" {
|
||||
log.Errorf("No value configured for datastore path")
|
||||
return nil
|
||||
return nil, fmt.Errorf("'path' parameter not specified")
|
||||
}
|
||||
mailPath := filepath.Join(path, "mail")
|
||||
if _, err := os.Stat(mailPath); err != nil {
|
||||
@@ -61,7 +60,7 @@ func New(cfg config.Storage) storage.Store {
|
||||
log.Errorf("Error creating dir %q: %v", mailPath, err)
|
||||
}
|
||||
}
|
||||
return &Store{path: path, mailPath: mailPath, messageCap: cfg.MailboxMsgCap}
|
||||
return &Store{path: path, mailPath: mailPath, messageCap: cfg.MailboxMsgCap}, nil
|
||||
}
|
||||
|
||||
// AddMessage adds a message to the specified mailbox.
|
||||
|
||||
@@ -265,13 +265,18 @@ func setupDataStore(cfg config.Storage) (*Store, *bytes.Buffer) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Capture log output
|
||||
// Capture log output.
|
||||
buf := new(bytes.Buffer)
|
||||
log.SetOutput(buf)
|
||||
|
||||
cfg.Path = path
|
||||
return New(cfg).(*Store), buf
|
||||
if cfg.Params == nil {
|
||||
cfg.Params = make(map[string]string)
|
||||
}
|
||||
cfg.Params["path"] = path
|
||||
s, err := New(cfg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return s.(*Store), buf
|
||||
}
|
||||
|
||||
// deliverMessage creates and delivers a message to the specific mailbox, returning
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/jhillyerd/inbucket/pkg/config"
|
||||
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||
)
|
||||
|
||||
@@ -25,10 +26,10 @@ type mbox struct {
|
||||
var _ storage.Store = &Store{}
|
||||
|
||||
// New returns an emtpy memory store.
|
||||
func New() *Store {
|
||||
func New(cfg config.Storage) (storage.Store, error) {
|
||||
return &Store{
|
||||
boxes: make(map[string]*mbox),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AddMessage stores the message, message ID and Size will be ignored.
|
||||
|
||||
@@ -3,6 +3,7 @@ package mem
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jhillyerd/inbucket/pkg/config"
|
||||
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||
"github.com/jhillyerd/inbucket/pkg/test"
|
||||
)
|
||||
@@ -10,7 +11,7 @@ import (
|
||||
// TestSuite runs storage package test suite on file store.
|
||||
func TestSuite(t *testing.T) {
|
||||
test.StoreSuite(t, func() (storage.Store, func(), error) {
|
||||
s := New()
|
||||
s, _ := New(config.Storage{})
|
||||
destroy := func() {}
|
||||
return s, destroy, nil
|
||||
})
|
||||
|
||||
@@ -3,9 +3,12 @@ package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/mail"
|
||||
"time"
|
||||
|
||||
"github.com/jhillyerd/inbucket/pkg/config"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -14,6 +17,9 @@ var (
|
||||
|
||||
// ErrNotWritable indicates the message is closed; no longer writable
|
||||
ErrNotWritable = errors.New("Message not writable")
|
||||
|
||||
// Constructors tracks registered storage constructors
|
||||
Constructors = make(map[string]func(config.Storage) (Store, error))
|
||||
)
|
||||
|
||||
// Store is the interface Inbucket uses to interact with storage implementations.
|
||||
@@ -38,3 +44,11 @@ type Message interface {
|
||||
Source() (io.ReadCloser, error)
|
||||
Size() int64
|
||||
}
|
||||
|
||||
// FromConfig creates an instance of the Store based on the provided configuration.
|
||||
func FromConfig(c config.Storage) (store Store, err error) {
|
||||
if cf := Constructors[c.Type]; cf != nil {
|
||||
return cf(c)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown storage type configured: %q", c.Type)
|
||||
}
|
||||
|
||||
@@ -171,6 +171,10 @@ $(document).ready(
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="metrics">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-xs-7"><b>Store Type:</b></div>
|
||||
<div class="col-sm-8 col-xs-5">{{ .storageConfig.Type }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-xs-7"><b>Retention Period:</b></div>
|
||||
<div class="col-sm-8 col-xs-5">
|
||||
|
||||
Reference in New Issue
Block a user