mailsrv/services/watcher.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)
}
}
}
}()
}