MailHog/vendor/github.com/mailhog/storage/memory.go
2017-04-16 23:41:32 +01:00

199 lines
4.5 KiB
Go

package storage
import (
"errors"
"strings"
"sync"
"github.com/mailhog/data"
)
// InMemory is an in memory storage backend
type InMemory struct {
MessageIDIndex map[string]int
Messages []*data.Message
mu sync.Mutex
}
// CreateInMemory creates a new in memory storage backend
func CreateInMemory() *InMemory {
return &InMemory{
MessageIDIndex: make(map[string]int),
Messages: make([]*data.Message, 0),
}
}
// Store stores a message and returns its storage ID
func (memory *InMemory) Store(m *data.Message) (string, error) {
memory.mu.Lock()
defer memory.mu.Unlock()
memory.Messages = append(memory.Messages, m)
memory.MessageIDIndex[string(m.ID)] = len(memory.Messages) - 1
return string(m.ID), nil
}
// Count returns the number of stored messages
func (memory *InMemory) Count() int {
return len(memory.Messages)
}
// Search finds messages matching the query
func (memory *InMemory) Search(kind, query string, start, limit int) (*data.Messages, int, error) {
// FIXME needs optimising, or replacing with a proper db!
query = strings.ToLower(query)
var filteredMessages = make([]*data.Message, 0)
for _, m := range memory.Messages {
doAppend := false
switch kind {
case "to":
for _, to := range m.To {
if strings.Contains(strings.ToLower(to.Mailbox+"@"+to.Domain), query) {
doAppend = true
break
}
}
if !doAppend {
if hdr, ok := m.Content.Headers["To"]; ok {
for _, to := range hdr {
if strings.Contains(strings.ToLower(to), query) {
doAppend = true
break
}
}
}
}
case "from":
if strings.Contains(strings.ToLower(m.From.Mailbox+"@"+m.From.Domain), query) {
doAppend = true
}
if !doAppend {
if hdr, ok := m.Content.Headers["From"]; ok {
for _, from := range hdr {
if strings.Contains(strings.ToLower(from), query) {
doAppend = true
break
}
}
}
}
case "containing":
if strings.Contains(strings.ToLower(m.Content.Body), query) {
doAppend = true
}
if !doAppend {
for _, hdr := range m.Content.Headers {
for _, v := range hdr {
if strings.Contains(strings.ToLower(v), query) {
doAppend = true
}
}
}
}
}
if doAppend {
filteredMessages = append(filteredMessages, m)
}
}
var messages = make([]data.Message, 0)
if len(filteredMessages) == 0 || start > len(filteredMessages) {
msgs := data.Messages(messages)
return &msgs, 0, nil
}
if start+limit > len(filteredMessages) {
limit = len(filteredMessages) - start
}
start = len(filteredMessages) - start - 1
end := start - limit
if start < 0 {
start = 0
}
if end < -1 {
end = -1
}
for i := start; i > end; i-- {
//for _, m := range memory.MessageIndex[start:end] {
messages = append(messages, *filteredMessages[i])
}
msgs := data.Messages(messages)
return &msgs, len(filteredMessages), nil
}
// List lists stored messages by index
func (memory *InMemory) List(start int, limit int) (*data.Messages, error) {
var messages = make([]data.Message, 0)
if len(memory.Messages) == 0 || start > len(memory.Messages) {
msgs := data.Messages(messages)
return &msgs, nil
}
if start+limit > len(memory.Messages) {
limit = len(memory.Messages) - start
}
start = len(memory.Messages) - start - 1
end := start - limit
if start < 0 {
start = 0
}
if end < -1 {
end = -1
}
for i := start; i > end; i-- {
//for _, m := range memory.MessageIndex[start:end] {
messages = append(messages, *memory.Messages[i])
}
msgs := data.Messages(messages)
return &msgs, nil
}
// DeleteOne deletes an individual message by storage ID
func (memory *InMemory) DeleteOne(id string) error {
memory.mu.Lock()
defer memory.mu.Unlock()
var index int
var ok bool
if index, ok = memory.MessageIDIndex[id]; !ok && true {
return errors.New("message not found")
}
delete(memory.MessageIDIndex, id)
for k, v := range memory.MessageIDIndex {
if v > index {
memory.MessageIDIndex[k] = v - 1
}
}
memory.Messages = append(memory.Messages[:index], memory.Messages[index+1:]...)
return nil
}
// DeleteAll deletes all in memory messages
func (memory *InMemory) DeleteAll() error {
memory.mu.Lock()
defer memory.mu.Unlock()
memory.Messages = make([]*data.Message, 0)
memory.MessageIDIndex = make(map[string]int)
return nil
}
// Load returns an individual message by storage ID
func (memory *InMemory) Load(id string) (*data.Message, error) {
if idx, ok := memory.MessageIDIndex[id]; ok {
return memory.Messages[idx], nil
}
return nil, nil
}