mirror of
https://gitlab.com/ric_harvey/MailHog.git
synced 2024-11-27 08:14:04 +00:00
Fix storage interface and fix dependency mess
This commit is contained in:
parent
2b58b571cb
commit
fc25fce4d2
8 changed files with 56 additions and 44 deletions
|
@ -1,5 +1,9 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/ian-kent/Go-MailHog/mailhog/storage"
|
||||
)
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
SMTPBindAddr: "0.0.0.0:1025",
|
||||
|
@ -19,6 +23,6 @@ type Config struct {
|
|||
MongoDb string
|
||||
MongoColl string
|
||||
MessageChan chan interface{}
|
||||
Storage interface{}
|
||||
Storage storage.Storage
|
||||
Assets func(asset string) ([]byte, error)
|
||||
}
|
||||
|
|
|
@ -23,10 +23,22 @@ type Protocol struct {
|
|||
message *data.SMTPMessage
|
||||
hostname string
|
||||
|
||||
LogHandler func(message string, args ...interface{})
|
||||
MessageReceivedHandler func(*data.Message) (string, error)
|
||||
ValidateSenderHandler func(from string) bool
|
||||
ValidateRecipientHandler func(to string) bool
|
||||
// LogHandler is called for each log message. If nil, log messages will
|
||||
// be output using fmt.Printf instead.
|
||||
LogHandler func(message string, args ...interface{})
|
||||
// MessageReceivedHandler is called for each message accepted by the
|
||||
// SMTP protocol. It must return a MessageID or error. If nil, messages
|
||||
// will be rejected with an error.
|
||||
MessageReceivedHandler func(*data.Message) (string, error)
|
||||
// ValidateSenderHandler should return true if the sender is valid,
|
||||
// otherwise false. If nil, all senders will be accepted.
|
||||
ValidateSenderHandler func(from string) bool
|
||||
// ValidateRecipientHandler should return true if the recipient is valid,
|
||||
// otherwise false. If nil, all recipients will be accepted.
|
||||
ValidateRecipientHandler func(to string) bool
|
||||
// ValidateAuthenticationhandler should return true if the authentication
|
||||
// parameters are valid, otherwise false. If nil, all authentication
|
||||
// attempts will be accepted.
|
||||
ValidateAuthenticationHandler func(mechanism string, args ...string) bool
|
||||
}
|
||||
|
||||
|
@ -50,7 +62,8 @@ func (proto *Protocol) logf(message string, args ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// Start begins an SMTP conversation with a 220 reply
|
||||
// Start begins an SMTP conversation with a 220 reply, placing the state
|
||||
// machine in ESTABLISH state.
|
||||
func (proto *Protocol) Start(hostname string) *Reply {
|
||||
proto.state = ESTABLISH
|
||||
proto.hostname = hostname
|
||||
|
@ -60,7 +73,8 @@ func (proto *Protocol) Start(hostname string) *Reply {
|
|||
// Parse parses a line string and returns any remaining line string
|
||||
// and a reply, if a command was found. Parse does nothing until a
|
||||
// new line is found.
|
||||
// - TODO move this to a buffer inside proto?
|
||||
// - TODO decide whether to move this to a buffer inside Protocol
|
||||
// sort of like it this way, since it gives control back to the caller
|
||||
func (proto *Protocol) Parse(line string) (string, *Reply) {
|
||||
var reply *Reply
|
||||
|
||||
|
@ -266,7 +280,7 @@ func ParseMAIL(mail string) (string, error) {
|
|||
r := regexp.MustCompile("(?i:From):<([^>]+)>")
|
||||
match := r.FindStringSubmatch(mail)
|
||||
if len(match) != 2 {
|
||||
return "", errors.New("Invalid sender")
|
||||
return "", errors.New("Invalid sender " + mail)
|
||||
}
|
||||
return match[1], nil
|
||||
}
|
||||
|
@ -276,7 +290,7 @@ func ParseRCPT(rcpt string) (string, error) {
|
|||
r := regexp.MustCompile("(?i:To):<([^>]+)>")
|
||||
match := r.FindStringSubmatch(rcpt)
|
||||
if len(match) != 2 {
|
||||
return "", errors.New("Invalid recipient")
|
||||
return "", errors.New("Invalid recipient " + rcpt)
|
||||
}
|
||||
return match[1], nil
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package protocol
|
||||
|
||||
// http://www.rfc-editor.org/rfc/rfc5321.txt
|
||||
|
||||
// State represents the state of an SMTP conversation
|
||||
type State int
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package server
|
|||
// http://www.rfc-editor.org/rfc/rfc5321.txt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
|
@ -11,7 +10,6 @@ import (
|
|||
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
||||
"github.com/ian-kent/Go-MailHog/mailhog/data"
|
||||
"github.com/ian-kent/Go-MailHog/mailhog/smtp/protocol"
|
||||
"github.com/ian-kent/Go-MailHog/mailhog/storage"
|
||||
)
|
||||
|
||||
// Session represents a SMTP session using net.TCPConn
|
||||
|
@ -43,6 +41,7 @@ func Accept(conn *net.TCPConn, conf *config.Config) {
|
|||
func (c *Session) validateAuthentication(mechanism string, args ...string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Session) validateRecipient(to string) bool {
|
||||
return true
|
||||
}
|
||||
|
@ -52,16 +51,8 @@ func (c *Session) validateSender(from string) bool {
|
|||
}
|
||||
|
||||
func (c *Session) acceptMessage(msg *data.Message) (id string, err error) {
|
||||
switch c.conf.Storage.(type) {
|
||||
case *storage.MongoDB:
|
||||
c.logf("Storing message using MongoDB")
|
||||
id, err = c.conf.Storage.(*storage.MongoDB).Store(msg)
|
||||
case *storage.InMemory:
|
||||
c.logf("Storing message using Memory")
|
||||
id, err = c.conf.Storage.(*storage.InMemory).Store(msg)
|
||||
default:
|
||||
err = errors.New("Unknown storage stype")
|
||||
}
|
||||
c.logf("Storing message %s", msg.ID)
|
||||
id, err = c.conf.Storage.Store(msg)
|
||||
c.conf.MessageChan <- msg
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
||||
"github.com/ian-kent/Go-MailHog/mailhog/data"
|
||||
)
|
||||
import "github.com/ian-kent/Go-MailHog/mailhog/data"
|
||||
|
||||
// InMemory is an in memory storage backend
|
||||
type InMemory struct {
|
||||
Config *config.Config
|
||||
Messages map[string]*data.Message
|
||||
MessageIndex []string
|
||||
MessageRIndex map[string]int
|
||||
}
|
||||
|
||||
// CreateInMemory creates a new in memory storage backend
|
||||
func CreateInMemory(c *config.Config) *InMemory {
|
||||
func CreateInMemory() *InMemory {
|
||||
return &InMemory{
|
||||
Config: c,
|
||||
Messages: make(map[string]*data.Message, 0),
|
||||
MessageIndex: make([]string, 0),
|
||||
MessageRIndex: make(map[string]int, 0),
|
||||
|
@ -32,15 +27,16 @@ func (memory *InMemory) Store(m *data.Message) (string, error) {
|
|||
}
|
||||
|
||||
// List lists stored messages by index
|
||||
func (memory *InMemory) List(start int, limit int) ([]*data.Message, error) {
|
||||
func (memory *InMemory) List(start int, limit int) (*data.Messages, error) {
|
||||
if limit > len(memory.MessageIndex) {
|
||||
limit = len(memory.MessageIndex)
|
||||
}
|
||||
var messages []*data.Message
|
||||
var messages []data.Message
|
||||
for _, m := range memory.MessageIndex[start:limit] {
|
||||
messages = append(messages, memory.Messages[m])
|
||||
messages = append(messages, *memory.Messages[m])
|
||||
}
|
||||
return messages, nil
|
||||
msgs := data.Messages(messages)
|
||||
return &msgs, nil
|
||||
}
|
||||
|
||||
// DeleteOne deletes an individual message by storage ID
|
||||
|
|
|
@ -3,7 +3,6 @@ package storage
|
|||
import (
|
||||
"log"
|
||||
|
||||
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
||||
"github.com/ian-kent/Go-MailHog/mailhog/data"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
|
@ -12,22 +11,20 @@ import (
|
|||
// MongoDB represents MongoDB backed storage backend
|
||||
type MongoDB struct {
|
||||
Session *mgo.Session
|
||||
Config *config.Config
|
||||
Collection *mgo.Collection
|
||||
}
|
||||
|
||||
// CreateMongoDB creates a MongoDB backed storage backend
|
||||
func CreateMongoDB(c *config.Config) *MongoDB {
|
||||
log.Printf("Connecting to MongoDB: %s\n", c.MongoUri)
|
||||
session, err := mgo.Dial(c.MongoUri)
|
||||
func CreateMongoDB(uri, db, coll string) *MongoDB {
|
||||
log.Printf("Connecting to MongoDB: %s\n", uri)
|
||||
session, err := mgo.Dial(uri)
|
||||
if err != nil {
|
||||
log.Printf("Error connecting to MongoDB: %s", err)
|
||||
return nil
|
||||
}
|
||||
return &MongoDB{
|
||||
Session: session,
|
||||
Config: c,
|
||||
Collection: session.DB(c.MongoDb).C(c.MongoColl),
|
||||
Collection: session.DB(db).C(coll),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
mailhog/storage/storage.go
Normal file
12
mailhog/storage/storage.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package storage
|
||||
|
||||
import "github.com/ian-kent/Go-MailHog/mailhog/data"
|
||||
|
||||
// Storage represents a storage backend
|
||||
type Storage interface {
|
||||
Store(m *data.Message) (string, error)
|
||||
List(start int, limit int) (*data.Messages, error)
|
||||
DeleteOne(id string) error
|
||||
DeleteAll() error
|
||||
Load(id string) (*data.Message, error)
|
||||
}
|
6
main.go
6
main.go
|
@ -46,17 +46,17 @@ func configure() {
|
|||
|
||||
if storage_type == "mongodb" {
|
||||
log.Println("Using MongoDB message storage")
|
||||
s := storage.CreateMongoDB(conf)
|
||||
s := storage.CreateMongoDB(conf.MongoUri, conf.MongoDb, conf.MongoColl)
|
||||
if s == nil {
|
||||
log.Println("MongoDB storage unavailable, reverting to in-memory storage")
|
||||
conf.Storage = storage.CreateInMemory(conf)
|
||||
conf.Storage = storage.CreateInMemory()
|
||||
} else {
|
||||
log.Println("Connected to MongoDB")
|
||||
conf.Storage = s
|
||||
}
|
||||
} else if storage_type == "memory" {
|
||||
log.Println("Using in-memory message storage")
|
||||
conf.Storage = storage.CreateInMemory(conf)
|
||||
conf.Storage = storage.CreateInMemory()
|
||||
} else {
|
||||
log.Fatalf("Invalid storage type %s", storage_type)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue