mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-18 10:07:02 +00:00
Refactor datastore into it's own package for #67
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
package smtpd
|
package datastore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -7,15 +7,15 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/config"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/msghub"
|
||||||
"github.com/jhillyerd/inbucket/smtpd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Context is passed into every request handler function
|
// Context is passed into every request handler function
|
||||||
type Context struct {
|
type Context struct {
|
||||||
Vars map[string]string
|
Vars map[string]string
|
||||||
Session *sessions.Session
|
Session *sessions.Session
|
||||||
DataStore smtpd.DataStore
|
DataStore datastore.DataStore
|
||||||
MsgHub *msghub.Hub
|
MsgHub *msghub.Hub
|
||||||
WebConfig config.WebConfig
|
WebConfig config.WebConfig
|
||||||
IsJSON bool
|
IsJSON bool
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import (
|
|||||||
"github.com/gorilla/securecookie"
|
"github.com/gorilla/securecookie"
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/config"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/msghub"
|
||||||
"github.com/jhillyerd/inbucket/smtpd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler is a function type that handles an HTTP request in Inbucket
|
// Handler is a function type that handles an HTTP request in Inbucket
|
||||||
@@ -23,7 +23,7 @@ type Handler func(http.ResponseWriter, *http.Request, *Context) error
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// DataStore is where all the mailboxes and messages live
|
// DataStore is where all the mailboxes and messages live
|
||||||
DataStore smtpd.DataStore
|
DataStore datastore.DataStore
|
||||||
|
|
||||||
// msgHub holds a reference to the message pub/sub system
|
// msgHub holds a reference to the message pub/sub system
|
||||||
msgHub *msghub.Hub
|
msgHub *msghub.Hub
|
||||||
@@ -51,7 +51,7 @@ func init() {
|
|||||||
func Initialize(
|
func Initialize(
|
||||||
cfg config.WebConfig,
|
cfg config.WebConfig,
|
||||||
shutdownChan chan bool,
|
shutdownChan chan bool,
|
||||||
ds smtpd.DataStore,
|
ds datastore.DataStore,
|
||||||
mh *msghub.Hub) {
|
mh *msghub.Hub) {
|
||||||
|
|
||||||
webConfig = cfg
|
webConfig = cfg
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
"github.com/jhillyerd/inbucket/smtpd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// State tracks the current mode of our POP3 state machine
|
// State tracks the current mode of our POP3 state machine
|
||||||
@@ -65,8 +65,8 @@ type Session struct {
|
|||||||
state State // Current session state
|
state State // Current session state
|
||||||
reader *bufio.Reader // Buffered reader for our net conn
|
reader *bufio.Reader // Buffered reader for our net conn
|
||||||
user string // Mailbox name
|
user string // Mailbox name
|
||||||
mailbox smtpd.Mailbox // Mailbox instance
|
mailbox datastore.Mailbox // Mailbox instance
|
||||||
messages []smtpd.Message // Slice of messages in mailbox
|
messages []datastore.Message // Slice of messages in mailbox
|
||||||
retain []bool // Messages to retain upon UPDATE (true=retain)
|
retain []bool // Messages to retain upon UPDATE (true=retain)
|
||||||
msgCount int // Number of undeleted messages
|
msgCount int // Number of undeleted messages
|
||||||
}
|
}
|
||||||
@@ -432,7 +432,7 @@ func (ses *Session) transactionHandler(cmd string, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send the contents of the message to the client
|
// Send the contents of the message to the client
|
||||||
func (ses *Session) sendMessage(msg smtpd.Message) {
|
func (ses *Session) sendMessage(msg datastore.Message) {
|
||||||
reader, err := msg.RawReader()
|
reader, err := msg.RawReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ses.logError("Failed to read message for RETR command")
|
ses.logError("Failed to read message for RETR command")
|
||||||
@@ -465,7 +465,7 @@ func (ses *Session) sendMessage(msg smtpd.Message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send the headers plus the top N lines to the client
|
// Send the headers plus the top N lines to the client
|
||||||
func (ses *Session) sendMessageTop(msg smtpd.Message, lineCount int) {
|
func (ses *Session) sendMessageTop(msg datastore.Message, lineCount int) {
|
||||||
reader, err := msg.RawReader()
|
reader, err := msg.RawReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ses.logError("Failed to read message for RETR command")
|
ses.logError("Failed to read message for RETR command")
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/config"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
"github.com/jhillyerd/inbucket/smtpd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server defines an instance of our POP3 server
|
// Server defines an instance of our POP3 server
|
||||||
@@ -17,14 +17,14 @@ type Server struct {
|
|||||||
host string
|
host string
|
||||||
domain string
|
domain string
|
||||||
maxIdleSeconds int
|
maxIdleSeconds int
|
||||||
dataStore smtpd.DataStore
|
dataStore datastore.DataStore
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
globalShutdown chan bool
|
globalShutdown chan bool
|
||||||
waitgroup *sync.WaitGroup
|
waitgroup *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Server struct
|
// New creates a new Server struct
|
||||||
func New(cfg config.POP3Config, shutdownChan chan bool, ds smtpd.DataStore) *Server {
|
func New(cfg config.POP3Config, shutdownChan chan bool, ds datastore.DataStore) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
host: fmt.Sprintf("%v:%v", cfg.IP4address, cfg.IP4port),
|
host: fmt.Sprintf("%v:%v", cfg.IP4address, cfg.IP4port),
|
||||||
domain: cfg.Domain,
|
domain: cfg.Domain,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/httpd"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
"github.com/jhillyerd/inbucket/rest/model"
|
"github.com/jhillyerd/inbucket/rest/model"
|
||||||
@@ -64,7 +65,7 @@ func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
||||||
}
|
}
|
||||||
msg, err := mb.GetMessage(id)
|
msg, err := mb.GetMessage(id)
|
||||||
if err == smtpd.ErrNotExist {
|
if err == datastore.ErrNotExist {
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -149,7 +150,7 @@ func MailboxSourceV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Contex
|
|||||||
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
||||||
}
|
}
|
||||||
message, err := mb.GetMessage(id)
|
message, err := mb.GetMessage(id)
|
||||||
if err == smtpd.ErrNotExist {
|
if err == datastore.ErrNotExist {
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -183,7 +184,7 @@ func MailboxDeleteV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Contex
|
|||||||
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
||||||
}
|
}
|
||||||
message, err := mb.GetMessage(id)
|
message, err := mb.GetMessage(id)
|
||||||
if err == smtpd.ErrNotExist {
|
if err == datastore.ErrNotExist {
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/smtpd"
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -47,7 +47,7 @@ func TestRestMailboxList(t *testing.T) {
|
|||||||
// Test empty mailbox
|
// Test empty mailbox
|
||||||
emptybox := &MockMailbox{}
|
emptybox := &MockMailbox{}
|
||||||
ds.On("MailboxFor", "empty").Return(emptybox, nil)
|
ds.On("MailboxFor", "empty").Return(emptybox, nil)
|
||||||
emptybox.On("GetMessages").Return([]smtpd.Message{}, nil)
|
emptybox.On("GetMessages").Return([]datastore.Message{}, nil)
|
||||||
|
|
||||||
w, err = testRestGet(baseURL + "/mailbox/empty")
|
w, err = testRestGet(baseURL + "/mailbox/empty")
|
||||||
expectCode = 200
|
expectCode = 200
|
||||||
@@ -79,7 +79,7 @@ func TestRestMailboxList(t *testing.T) {
|
|||||||
// Test MailboxFor error
|
// Test MailboxFor error
|
||||||
error2box := &MockMailbox{}
|
error2box := &MockMailbox{}
|
||||||
ds.On("MailboxFor", "error2").Return(error2box, nil)
|
ds.On("MailboxFor", "error2").Return(error2box, nil)
|
||||||
error2box.On("GetMessages").Return([]smtpd.Message{}, fmt.Errorf("Internal error 2"))
|
error2box.On("GetMessages").Return([]datastore.Message{}, fmt.Errorf("Internal error 2"))
|
||||||
|
|
||||||
w, err = testRestGet(baseURL + "/mailbox/error2")
|
w, err = testRestGet(baseURL + "/mailbox/error2")
|
||||||
expectCode = 500
|
expectCode = 500
|
||||||
@@ -111,7 +111,7 @@ func TestRestMailboxList(t *testing.T) {
|
|||||||
ds.On("MailboxFor", "good").Return(goodbox, nil)
|
ds.On("MailboxFor", "good").Return(goodbox, nil)
|
||||||
msg1 := data1.MockMessage()
|
msg1 := data1.MockMessage()
|
||||||
msg2 := data2.MockMessage()
|
msg2 := data2.MockMessage()
|
||||||
goodbox.On("GetMessages").Return([]smtpd.Message{msg1, msg2}, nil)
|
goodbox.On("GetMessages").Return([]datastore.Message{msg1, msg2}, nil)
|
||||||
|
|
||||||
// Check return code
|
// Check return code
|
||||||
w, err = testRestGet(baseURL + "/mailbox/good")
|
w, err = testRestGet(baseURL + "/mailbox/good")
|
||||||
@@ -171,7 +171,7 @@ func TestRestMessage(t *testing.T) {
|
|||||||
// Test requesting a message that does not exist
|
// Test requesting a message that does not exist
|
||||||
emptybox := &MockMailbox{}
|
emptybox := &MockMailbox{}
|
||||||
ds.On("MailboxFor", "empty").Return(emptybox, nil)
|
ds.On("MailboxFor", "empty").Return(emptybox, nil)
|
||||||
emptybox.On("GetMessage", "0001").Return(&MockMessage{}, smtpd.ErrNotExist)
|
emptybox.On("GetMessage", "0001").Return(&MockMessage{}, datastore.ErrNotExist)
|
||||||
|
|
||||||
w, err = testRestGet(baseURL + "/mailbox/empty/0001")
|
w, err = testRestGet(baseURL + "/mailbox/empty/0001")
|
||||||
expectCode = 404
|
expectCode = 404
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/enmime"
|
"github.com/jhillyerd/enmime"
|
||||||
"github.com/jhillyerd/inbucket/smtpd"
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,14 +15,14 @@ type MockDataStore struct {
|
|||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockDataStore) MailboxFor(name string) (smtpd.Mailbox, error) {
|
func (m *MockDataStore) MailboxFor(name string) (datastore.Mailbox, error) {
|
||||||
args := m.Called(name)
|
args := m.Called(name)
|
||||||
return args.Get(0).(smtpd.Mailbox), args.Error(1)
|
return args.Get(0).(datastore.Mailbox), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockDataStore) AllMailboxes() ([]smtpd.Mailbox, error) {
|
func (m *MockDataStore) AllMailboxes() ([]datastore.Mailbox, error) {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).([]smtpd.Mailbox), args.Error(1)
|
return args.Get(0).([]datastore.Mailbox), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mock Mailbox object
|
// Mock Mailbox object
|
||||||
@@ -30,14 +30,14 @@ type MockMailbox struct {
|
|||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) GetMessages() ([]smtpd.Message, error) {
|
func (m *MockMailbox) GetMessages() ([]datastore.Message, error) {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).([]smtpd.Message), args.Error(1)
|
return args.Get(0).([]datastore.Message), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) GetMessage(id string) (smtpd.Message, error) {
|
func (m *MockMailbox) GetMessage(id string) (datastore.Message, error) {
|
||||||
args := m.Called(id)
|
args := m.Called(id)
|
||||||
return args.Get(0).(smtpd.Message), args.Error(1)
|
return args.Get(0).(datastore.Message), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) Purge() error {
|
func (m *MockMailbox) Purge() error {
|
||||||
@@ -45,9 +45,9 @@ func (m *MockMailbox) Purge() error {
|
|||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) NewMessage() (smtpd.Message, error) {
|
func (m *MockMailbox) NewMessage() (datastore.Message, error) {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(smtpd.Message), args.Error(1)
|
return args.Get(0).(datastore.Message), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) Name() string {
|
func (m *MockMailbox) Name() string {
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
|
|
||||||
"github.com/jhillyerd/enmime"
|
"github.com/jhillyerd/enmime"
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/config"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/httpd"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/msghub"
|
||||||
"github.com/jhillyerd/inbucket/smtpd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type InputMessageData struct {
|
type InputMessageData struct {
|
||||||
@@ -188,7 +188,7 @@ func testRestGet(url string) (*httptest.ResponseRecorder, error) {
|
|||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupWebServer(ds smtpd.DataStore) *bytes.Buffer {
|
func setupWebServer(ds datastore.DataStore) *bytes.Buffer {
|
||||||
// Capture log output
|
// Capture log output
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
log.SetOutput(buf)
|
log.SetOutput(buf)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/enmime"
|
"github.com/jhillyerd/enmime"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ type FileMessage struct {
|
|||||||
|
|
||||||
// NewMessage creates a new FileMessage object and sets the Date and Id fields.
|
// NewMessage creates a new FileMessage object and sets the Date and Id fields.
|
||||||
// It will also delete messages over messageCap if configured.
|
// It will also delete messages over messageCap if configured.
|
||||||
func (mb *FileMailbox) NewMessage() (Message, error) {
|
func (mb *FileMailbox) NewMessage() (datastore.Message, error) {
|
||||||
// Load index
|
// Load index
|
||||||
if !mb.indexLoaded {
|
if !mb.indexLoaded {
|
||||||
if err := mb.readIndex(); err != nil {
|
if err := mb.readIndex(); err != nil {
|
||||||
@@ -165,7 +166,7 @@ func (m *FileMessage) ReadRaw() (raw *string, err error) {
|
|||||||
func (m *FileMessage) Append(data []byte) error {
|
func (m *FileMessage) Append(data []byte) error {
|
||||||
// Prevent Appending to a pre-existing Message
|
// Prevent Appending to a pre-existing Message
|
||||||
if !m.writable {
|
if !m.writable {
|
||||||
return ErrNotWritable
|
return datastore.ErrNotWritable
|
||||||
}
|
}
|
||||||
// Open file for writing if we haven't yet
|
// Open file for writing if we haven't yet
|
||||||
if m.writer == nil {
|
if m.writer == nil {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/config"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ type FileDataStore struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewFileDataStore creates a new DataStore object using the specified path
|
// NewFileDataStore creates a new DataStore object using the specified path
|
||||||
func NewFileDataStore(cfg config.DataStoreConfig) DataStore {
|
func NewFileDataStore(cfg config.DataStoreConfig) datastore.DataStore {
|
||||||
path := cfg.Path
|
path := cfg.Path
|
||||||
if path == "" {
|
if path == "" {
|
||||||
log.Errorf("No value configured for datastore path")
|
log.Errorf("No value configured for datastore path")
|
||||||
@@ -73,14 +74,14 @@ func NewFileDataStore(cfg config.DataStoreConfig) DataStore {
|
|||||||
|
|
||||||
// DefaultFileDataStore creates a new DataStore object. It uses the inbucket.Config object to
|
// DefaultFileDataStore creates a new DataStore object. It uses the inbucket.Config object to
|
||||||
// construct it's path.
|
// construct it's path.
|
||||||
func DefaultFileDataStore() DataStore {
|
func DefaultFileDataStore() datastore.DataStore {
|
||||||
cfg := config.GetDataStoreConfig()
|
cfg := config.GetDataStoreConfig()
|
||||||
return NewFileDataStore(cfg)
|
return NewFileDataStore(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MailboxFor retrieves the Mailbox object for a specified email address, if the mailbox
|
// MailboxFor retrieves the Mailbox object for a specified email address, if the mailbox
|
||||||
// does not exist, it will attempt to create it.
|
// does not exist, it will attempt to create it.
|
||||||
func (ds *FileDataStore) MailboxFor(emailAddress string) (Mailbox, error) {
|
func (ds *FileDataStore) MailboxFor(emailAddress string) (datastore.Mailbox, error) {
|
||||||
name, err := ParseMailboxName(emailAddress)
|
name, err := ParseMailboxName(emailAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -96,8 +97,8 @@ func (ds *FileDataStore) MailboxFor(emailAddress string) (Mailbox, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AllMailboxes returns a slice with all Mailboxes
|
// AllMailboxes returns a slice with all Mailboxes
|
||||||
func (ds *FileDataStore) AllMailboxes() ([]Mailbox, error) {
|
func (ds *FileDataStore) AllMailboxes() ([]datastore.Mailbox, error) {
|
||||||
mailboxes := make([]Mailbox, 0, 100)
|
mailboxes := make([]datastore.Mailbox, 0, 100)
|
||||||
infos1, err := ioutil.ReadDir(ds.mailPath)
|
infos1, err := ioutil.ReadDir(ds.mailPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -159,14 +160,14 @@ func (mb *FileMailbox) String() string {
|
|||||||
|
|
||||||
// GetMessages scans the mailbox directory for .gob files and decodes them into
|
// GetMessages scans the mailbox directory for .gob files and decodes them into
|
||||||
// a slice of Message objects.
|
// a slice of Message objects.
|
||||||
func (mb *FileMailbox) GetMessages() ([]Message, error) {
|
func (mb *FileMailbox) GetMessages() ([]datastore.Message, error) {
|
||||||
if !mb.indexLoaded {
|
if !mb.indexLoaded {
|
||||||
if err := mb.readIndex(); err != nil {
|
if err := mb.readIndex(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
messages := make([]Message, len(mb.messages))
|
messages := make([]datastore.Message, len(mb.messages))
|
||||||
for i, m := range mb.messages {
|
for i, m := range mb.messages {
|
||||||
messages[i] = m
|
messages[i] = m
|
||||||
}
|
}
|
||||||
@@ -174,7 +175,7 @@ func (mb *FileMailbox) GetMessages() ([]Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetMessage decodes a single message by Id and returns a Message object
|
// GetMessage decodes a single message by Id and returns a Message object
|
||||||
func (mb *FileMailbox) GetMessage(id string) (Message, error) {
|
func (mb *FileMailbox) GetMessage(id string) (datastore.Message, error) {
|
||||||
if !mb.indexLoaded {
|
if !mb.indexLoaded {
|
||||||
if err := mb.readIndex(); err != nil {
|
if err := mb.readIndex(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -191,7 +192,7 @@ func (mb *FileMailbox) GetMessage(id string) (Message, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ErrNotExist
|
return nil, datastore.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
// Purge deletes all messages in this mailbox
|
// Purge deletes all messages in this mailbox
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/msghub"
|
||||||
)
|
)
|
||||||
@@ -71,7 +72,7 @@ var commands = map[string]bool{
|
|||||||
// recipientDetails for message delivery
|
// recipientDetails for message delivery
|
||||||
type recipientDetails struct {
|
type recipientDetails struct {
|
||||||
address, localPart, domainPart string
|
address, localPart, domainPart string
|
||||||
mailbox Mailbox
|
mailbox datastore.Mailbox
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session holds the state of an SMTP session
|
// Session holds the state of an SMTP session
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/config"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/msghub"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -376,7 +377,7 @@ func (m *mockConn) SetDeadline(t time.Time) error { return nil }
|
|||||||
func (m *mockConn) SetReadDeadline(t time.Time) error { return nil }
|
func (m *mockConn) SetReadDeadline(t time.Time) error { return nil }
|
||||||
func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil }
|
func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil }
|
||||||
|
|
||||||
func setupSMTPServer(ds DataStore) (s *Server, buf *bytes.Buffer, teardown func()) {
|
func setupSMTPServer(ds datastore.DataStore) (s *Server, buf *bytes.Buffer, teardown func()) {
|
||||||
// Test Server Config
|
// Test Server Config
|
||||||
cfg := config.SMTPConfig{
|
cfg := config.SMTPConfig{
|
||||||
IP4address: net.IPv4(127, 0, 0, 1),
|
IP4address: net.IPv4(127, 0, 0, 1),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/config"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/msghub"
|
||||||
)
|
)
|
||||||
@@ -27,7 +28,7 @@ type Server struct {
|
|||||||
storeMessages bool
|
storeMessages bool
|
||||||
|
|
||||||
// Dependencies
|
// Dependencies
|
||||||
dataStore DataStore // Mailbox/message store
|
dataStore datastore.DataStore // Mailbox/message store
|
||||||
globalShutdown chan bool // Shuts down Inbucket
|
globalShutdown chan bool // Shuts down Inbucket
|
||||||
msgHub *msghub.Hub // Pub/sub for message info
|
msgHub *msghub.Hub // Pub/sub for message info
|
||||||
retentionScanner *RetentionScanner // Deletes expired messages
|
retentionScanner *RetentionScanner // Deletes expired messages
|
||||||
@@ -62,7 +63,7 @@ var (
|
|||||||
func NewServer(
|
func NewServer(
|
||||||
cfg config.SMTPConfig,
|
cfg config.SMTPConfig,
|
||||||
globalShutdown chan bool,
|
globalShutdown chan bool,
|
||||||
ds DataStore,
|
ds datastore.DataStore,
|
||||||
msgHub *msghub.Hub) *Server {
|
msgHub *msghub.Hub) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
host: fmt.Sprintf("%v:%v", cfg.IP4address, cfg.IP4port),
|
host: fmt.Sprintf("%v:%v", cfg.IP4address, cfg.IP4port),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/config"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -42,14 +43,14 @@ func init() {
|
|||||||
type RetentionScanner struct {
|
type RetentionScanner struct {
|
||||||
globalShutdown chan bool // Closes when Inbucket needs to shut down
|
globalShutdown chan bool // Closes when Inbucket needs to shut down
|
||||||
retentionShutdown chan bool // Closed after the scanner has shut down
|
retentionShutdown chan bool // Closed after the scanner has shut down
|
||||||
ds DataStore
|
ds datastore.DataStore
|
||||||
retentionPeriod time.Duration
|
retentionPeriod time.Duration
|
||||||
retentionSleep time.Duration
|
retentionSleep time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRetentionScanner launches a go-routine that scans for expired
|
// NewRetentionScanner launches a go-routine that scans for expired
|
||||||
// messages, following the configured interval
|
// messages, following the configured interval
|
||||||
func NewRetentionScanner(ds DataStore, shutdownChannel chan bool) *RetentionScanner {
|
func NewRetentionScanner(ds datastore.DataStore, shutdownChannel chan bool) *RetentionScanner {
|
||||||
cfg := config.GetDataStoreConfig()
|
cfg := config.GetDataStoreConfig()
|
||||||
rs := &RetentionScanner{
|
rs := &RetentionScanner{
|
||||||
globalShutdown: shutdownChannel,
|
globalShutdown: shutdownChannel,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/enmime"
|
"github.com/jhillyerd/enmime"
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,12 +29,12 @@ func TestDoRetentionScan(t *testing.T) {
|
|||||||
old3 := mockMessage(24)
|
old3 := mockMessage(24)
|
||||||
|
|
||||||
// First it should ask for all mailboxes
|
// First it should ask for all mailboxes
|
||||||
mds.On("AllMailboxes").Return([]Mailbox{mb1, mb2, mb3}, nil)
|
mds.On("AllMailboxes").Return([]datastore.Mailbox{mb1, mb2, mb3}, nil)
|
||||||
|
|
||||||
// Then for all messages on each box
|
// Then for all messages on each box
|
||||||
mb1.On("GetMessages").Return([]Message{new1, old1, old2}, nil)
|
mb1.On("GetMessages").Return([]datastore.Message{new1, old1, old2}, nil)
|
||||||
mb2.On("GetMessages").Return([]Message{old3, new2}, nil)
|
mb2.On("GetMessages").Return([]datastore.Message{old3, new2}, nil)
|
||||||
mb3.On("GetMessages").Return([]Message{new3}, nil)
|
mb3.On("GetMessages").Return([]datastore.Message{new3}, nil)
|
||||||
|
|
||||||
// Test 4 hour retention
|
// Test 4 hour retention
|
||||||
rs := &RetentionScanner{
|
rs := &RetentionScanner{
|
||||||
@@ -76,14 +77,14 @@ type MockDataStore struct {
|
|||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockDataStore) MailboxFor(name string) (Mailbox, error) {
|
func (m *MockDataStore) MailboxFor(name string) (datastore.Mailbox, error) {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(Mailbox), args.Error(1)
|
return args.Get(0).(datastore.Mailbox), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockDataStore) AllMailboxes() ([]Mailbox, error) {
|
func (m *MockDataStore) AllMailboxes() ([]datastore.Mailbox, error) {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).([]Mailbox), args.Error(1)
|
return args.Get(0).([]datastore.Mailbox), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mock Mailbox object
|
// Mock Mailbox object
|
||||||
@@ -91,14 +92,14 @@ type MockMailbox struct {
|
|||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) GetMessages() ([]Message, error) {
|
func (m *MockMailbox) GetMessages() ([]datastore.Message, error) {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).([]Message), args.Error(1)
|
return args.Get(0).([]datastore.Message), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) GetMessage(id string) (Message, error) {
|
func (m *MockMailbox) GetMessage(id string) (datastore.Message, error) {
|
||||||
args := m.Called(id)
|
args := m.Called(id)
|
||||||
return args.Get(0).(Message), args.Error(1)
|
return args.Get(0).(datastore.Message), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) Purge() error {
|
func (m *MockMailbox) Purge() error {
|
||||||
@@ -106,9 +107,9 @@ func (m *MockMailbox) Purge() error {
|
|||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) NewMessage() (Message, error) {
|
func (m *MockMailbox) NewMessage() (datastore.Message, error) {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(Message), args.Error(1)
|
return args.Get(0).(datastore.Message), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockMailbox) Name() string {
|
func (m *MockMailbox) Name() string {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/jhillyerd/inbucket/datastore"
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/httpd"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/log"
|
||||||
"github.com/jhillyerd/inbucket/smtpd"
|
"github.com/jhillyerd/inbucket/smtpd"
|
||||||
@@ -103,7 +104,7 @@ func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
||||||
}
|
}
|
||||||
msg, err := mb.GetMessage(id)
|
msg, err := mb.GetMessage(id)
|
||||||
if err == smtpd.ErrNotExist {
|
if err == datastore.ErrNotExist {
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -143,7 +144,7 @@ func MailboxHTML(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
||||||
}
|
}
|
||||||
message, err := mb.GetMessage(id)
|
message, err := mb.GetMessage(id)
|
||||||
if err == smtpd.ErrNotExist {
|
if err == datastore.ErrNotExist {
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -180,7 +181,7 @@ func MailboxSource(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
||||||
}
|
}
|
||||||
message, err := mb.GetMessage(id)
|
message, err := mb.GetMessage(id)
|
||||||
if err == smtpd.ErrNotExist {
|
if err == datastore.ErrNotExist {
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -226,7 +227,7 @@ func MailboxDownloadAttach(w http.ResponseWriter, req *http.Request, ctx *httpd.
|
|||||||
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
||||||
}
|
}
|
||||||
message, err := mb.GetMessage(id)
|
message, err := mb.GetMessage(id)
|
||||||
if err == smtpd.ErrNotExist {
|
if err == datastore.ErrNotExist {
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -279,7 +280,7 @@ func MailboxViewAttach(w http.ResponseWriter, req *http.Request, ctx *httpd.Cont
|
|||||||
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
return fmt.Errorf("Failed to get mailbox for %q: %v", name, err)
|
||||||
}
|
}
|
||||||
message, err := mb.GetMessage(id)
|
message, err := mb.GetMessage(id)
|
||||||
if err == smtpd.ErrNotExist {
|
if err == datastore.ErrNotExist {
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user