101 lines
2.3 KiB
Go
101 lines
2.3 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"mailsrv/mail"
|
|
"mailsrv/runtime"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
const (
|
|
TickerInterval time.Duration = 10 * time.Second
|
|
JSONSuffix string = ".json"
|
|
ErrorSuffix string = ".err"
|
|
)
|
|
|
|
type Watcher interface {
|
|
Watch()
|
|
Done() <-chan struct{}
|
|
}
|
|
|
|
// DirectoryWatch watches a directory every `tick` interval and collect email files.
|
|
type DirectoryWatch struct {
|
|
ctx context.Context
|
|
fnCancel context.CancelFunc
|
|
|
|
outboxPath string
|
|
queue *runtime.Queue
|
|
}
|
|
|
|
func NewDirectoryWatch(ctx context.Context, outboxPath string, queue *runtime.Queue) DirectoryWatch {
|
|
ctxChild, fnCancel := context.WithCancel(ctx)
|
|
|
|
return DirectoryWatch{
|
|
ctx: ctxChild,
|
|
fnCancel: fnCancel,
|
|
outboxPath: outboxPath,
|
|
queue: queue,
|
|
}
|
|
}
|
|
|
|
func (dw DirectoryWatch) Done() <-chan struct{} {
|
|
return dw.ctx.Done()
|
|
}
|
|
|
|
// Watch reads the `outbox` directory every `TickInterval` and put JSON format e-mail in the queue.
|
|
func (dw DirectoryWatch) Watch() {
|
|
log.Info().Str("outbox", dw.outboxPath).Msg("watching outbox directory...")
|
|
|
|
ticker := time.NewTicker(TickerInterval)
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-dw.Done():
|
|
log.Err(dw.ctx.Err()).Msg("context done")
|
|
return
|
|
case <-ticker.C:
|
|
log.Debug().Str("action", "retrieving json e-mail format...").Str("path", dw.outboxPath)
|
|
|
|
files, err := os.ReadDir(dw.outboxPath)
|
|
if err != nil && !os.IsExist(err) {
|
|
log.Err(err).Msg("outbox directory does not exist")
|
|
dw.fnCancel()
|
|
return
|
|
}
|
|
|
|
for _, file := range files {
|
|
filename := file.Name()
|
|
if !strings.HasSuffix(filename, JSONSuffix) {
|
|
continue
|
|
}
|
|
|
|
emailPath := path.Join(dw.outboxPath, filename)
|
|
email, err := mail.FromJSON(emailPath)
|
|
|
|
if err != nil {
|
|
log.Err(err).Str("path", emailPath).Msg("unable to parse JSON email")
|
|
|
|
// if JSON parsing failed the `path` is renamed with an error suffix to not watch it again
|
|
newPath := fmt.Sprintf("%s%s", emailPath, ErrorSuffix)
|
|
if err := os.Rename(emailPath, newPath); err != nil {
|
|
log.Err(err).Str("path", emailPath).Str("new path", newPath).Msg("unable to rename bad JSON email path")
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
email.Path = emailPath
|
|
dw.queue.Add(email)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|