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)
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}()
 | |
| }
 |