diff --git a/cmd/daemon/service.go b/cmd/daemon/service.go index f2230df..a80045d 100644 --- a/cmd/daemon/service.go +++ b/cmd/daemon/service.go @@ -1,11 +1,13 @@ package main import ( + "flag" "os" "os/signal" "time" "git.ewintr.nl/go-kit/log" + "git.ewintr.nl/gte/internal/configuration" "git.ewintr.nl/gte/internal/process" "git.ewintr.nl/gte/internal/task" "git.ewintr.nl/gte/pkg/msend" @@ -14,25 +16,30 @@ import ( func main() { logger := log.New(os.Stdout) - logger.Info("started") - msgStore := mstore.NewIMAP(&mstore.IMAPConfig{ - IMAPURL: os.Getenv("IMAP_URL"), - IMAPUsername: os.Getenv("IMAP_USERNAME"), - IMAPPassword: os.Getenv("IMAP_PASSWORD"), - }) - msgSender := msend.NewSSLSMTP(&msend.SSLSMTPConfig{ - URL: os.Getenv("SMTP_URL"), - Username: os.Getenv("SMTP_USERNAME"), - Password: os.Getenv("SMTP_PASSWORD"), - From: os.Getenv("SMTP_FROM"), - To: os.Getenv("SMTP_TO"), - }) + configPath := flag.String("c", "~/.config/gte/gte.conf", "path to configuration file") + daysAhead := flag.Int("d", 6, "generate for this amount of days from now") + flag.Parse() + + logger.With(log.Fields{ + "config": *configPath, + "daysAhead": *daysAhead, + }).Info("started") + + configFile, err := os.Open(*configPath) + if err != nil { + logger.WithErr(err).Error("could not open config file") + os.Exit(1) + } + config := configuration.New(configFile) + + msgStore := mstore.NewIMAP(config.IMAP()) + mailSend := msend.NewSSLSMTP(config.SMTP()) repo := task.NewRepository(msgStore) - disp := task.NewDispatcher(msgSender) + disp := task.NewDispatcher(mailSend) inboxProc := process.NewInbox(repo) - recurProc := process.NewRecur(repo, disp, 6) + recurProc := process.NewRecur(repo, disp, *daysAhead) go Run(inboxProc, recurProc, logger) @@ -44,7 +51,7 @@ func main() { func Run(inboxProc *process.Inbox, recurProc *process.Recur, logger log.Logger) { logger = logger.WithField("func", "run") - inboxTicker := time.NewTicker(10 * time.Second) + inboxTicker := time.NewTicker(30 * time.Second) recurTicker := time.NewTicker(time.Hour) oldToday := task.Today diff --git a/cmd/generate-recurring/main.go b/cmd/generate-recurring/main.go index 72a0b1b..58bfae9 100644 --- a/cmd/generate-recurring/main.go +++ b/cmd/generate-recurring/main.go @@ -1,10 +1,11 @@ package main import ( + "flag" "os" - "strconv" "git.ewintr.nl/go-kit/log" + "git.ewintr.nl/gte/internal/configuration" "git.ewintr.nl/gte/internal/process" "git.ewintr.nl/gte/internal/task" "git.ewintr.nl/gte/pkg/msend" @@ -13,35 +14,24 @@ import ( func main() { logger := log.New(os.Stdout).WithField("cmd", "generate-recurring") - IMAPConfig := &mstore.IMAPConfig{ - IMAPURL: os.Getenv("IMAP_URL"), - IMAPUsername: os.Getenv("IMAP_USERNAME"), - IMAPPassword: os.Getenv("IMAP_PASSWORD"), - } - msgStore := mstore.NewIMAP(IMAPConfig) - SMTPConfig := &msend.SSLSMTPConfig{ - URL: os.Getenv("SMTP_URL"), - Username: os.Getenv("SMTP_USERNAME"), - Password: os.Getenv("SMTP_PASSWORD"), - From: os.Getenv("SMTP_FROM"), - To: os.Getenv("SMTP_TO"), - } - if !SMTPConfig.Valid() { - logger.Error("please set SMTP_URL, SMTP_USERNAME, etc environment variables") + configPath := flag.String("c", "~/.config/gte/gte.conf", "path to configuration file") + daysAhead := flag.Int("d", 6, "generate for this amount of days from now") + flag.Parse() + + configFile, err := os.Open(*configPath) + if err != nil { + logger.WithErr(err).Error("could not open config file") os.Exit(1) } - mailSend := msend.NewSSLSMTP(SMTPConfig) - - daysAhead, err := strconv.Atoi(os.Getenv("GTE_DAYS_AHEAD")) - if err != nil { - daysAhead = 0 - } + config := configuration.New(configFile) + msgStore := mstore.NewIMAP(config.IMAP()) + mailSend := msend.NewSSLSMTP(config.SMTP()) taskRepo := task.NewRepository(msgStore) taskDisp := task.NewDispatcher(mailSend) + recur := process.NewRecur(taskRepo, taskDisp, *daysAhead) - recur := process.NewRecur(taskRepo, taskDisp, daysAhead) result, err := recur.Process() if err != nil { logger.WithErr(err).Error("unable to process recurring") diff --git a/cmd/process-inbox/main.go b/cmd/process-inbox/main.go index ba19369..71fa25d 100644 --- a/cmd/process-inbox/main.go +++ b/cmd/process-inbox/main.go @@ -1,9 +1,11 @@ package main import ( + "flag" "os" "git.ewintr.nl/go-kit/log" + "git.ewintr.nl/gte/internal/configuration" "git.ewintr.nl/gte/internal/process" "git.ewintr.nl/gte/internal/task" "git.ewintr.nl/gte/pkg/mstore" @@ -11,14 +13,19 @@ import ( func main() { logger := log.New(os.Stdout).WithField("cmd", "process-inbox") - config := &mstore.IMAPConfig{ - IMAPURL: os.Getenv("IMAP_URL"), - IMAPUsername: os.Getenv("IMAP_USERNAME"), - IMAPPassword: os.Getenv("IMAP_PASSWORD"), - } - msgStore := mstore.NewIMAP(config) + configPath := flag.String("c", "~/.config/gte/gte.conf", "path to configuration file") + flag.Parse() + + configFile, err := os.Open(*configPath) + if err != nil { + logger.WithErr(err).Error("could not open config file") + os.Exit(1) + } + config := configuration.New(configFile) + msgStore := mstore.NewIMAP(config.IMAP()) inboxProcessor := process.NewInbox(task.NewRepository(msgStore)) + result, err := inboxProcessor.Process() if err != nil { logger.WithErr(err).Error("unable to process inbox") diff --git a/internal/configuration/configuration.go b/internal/configuration/configuration.go new file mode 100644 index 0000000..268cc93 --- /dev/null +++ b/internal/configuration/configuration.go @@ -0,0 +1,87 @@ +package configuration + +import ( + "bufio" + "errors" + "io" + "strings" + + "git.ewintr.nl/gte/pkg/msend" + "git.ewintr.nl/gte/pkg/mstore" +) + +var ( + ErrUnableToRead = errors.New("unable to read configuration") +) + +type Configuration struct { + IMAPURL string + IMAPUsername string + IMAPPassword string + + SMTPURL string + SMTPUsername string + SMTPPassword string + + FromName string + FromAddress string + + ToName string + ToAddress string +} + +func New(src io.Reader) *Configuration { + conf := &Configuration{} + scanner := bufio.NewScanner(src) + for scanner.Scan() { + line := strings.Split(scanner.Text(), "=") + if len(line) != 2 { + + continue + } + + key, value := strings.TrimSpace(line[0]), strings.TrimSpace(line[1]) + switch key { + case "imap_url": + conf.IMAPURL = value + case "imap_username": + conf.IMAPUsername = value + case "imap_password": + conf.IMAPPassword = value + case "smtp_url": + conf.SMTPURL = value + case "smtp_username": + conf.SMTPUsername = value + case "smtp_password": + conf.SMTPPassword = value + case "to_name": + conf.ToName = value + case "to_address": + conf.ToAddress = value + case "from_name": + conf.FromName = value + case "from_address": + conf.FromAddress = value + } + } + + return conf +} + +func (c *Configuration) IMAP() *mstore.IMAPConfig { + return &mstore.IMAPConfig{ + IMAPURL: c.IMAPURL, + IMAPUsername: c.IMAPUsername, + IMAPPassword: c.IMAPPassword, + } +} + +func (c *Configuration) SMTP() *msend.SSLSMTPConfig { + return &msend.SSLSMTPConfig{ + URL: c.SMTPURL, + Username: c.SMTPUsername, + Password: c.SMTPPassword, + From: c.FromAddress, + To: c.ToAddress, + } +} diff --git a/internal/configuration/configuration_test.go b/internal/configuration/configuration_test.go new file mode 100644 index 0000000..87c508c --- /dev/null +++ b/internal/configuration/configuration_test.go @@ -0,0 +1,111 @@ +package configuration_test + +import ( + "strings" + "testing" + + "git.ewintr.nl/go-kit/test" + "git.ewintr.nl/gte/internal/configuration" + "git.ewintr.nl/gte/pkg/msend" + "git.ewintr.nl/gte/pkg/mstore" +) + +func TestNew(t *testing.T) { + for _, tc := range []struct { + name string + source string + exp *configuration.Configuration + }{ + { + name: "empty", + exp: &configuration.Configuration{}, + }, + { + name: "lines without values", + source: "test\n\n876\nkey=", + exp: &configuration.Configuration{}, + }, + { + name: "trim space", + source: " imap_url\t= value", + exp: &configuration.Configuration{ + IMAPURL: "value", + }, + }, + { + name: "value with space", + source: "imap_url=one two three", + exp: &configuration.Configuration{ + IMAPURL: "one two three", + }, + }, + { + name: "imap", + source: "imap_url=url\nimap_username=username\nimap_password=password", + exp: &configuration.Configuration{ + IMAPURL: "url", + IMAPUsername: "username", + IMAPPassword: "password", + }, + }, + { + name: "smtp", + source: "smtp_url=url\nsmtp_username=username\nsmtp_password=password", + exp: &configuration.Configuration{ + SMTPURL: "url", + SMTPUsername: "username", + SMTPPassword: "password", + }, + }, + { + name: "addresses", + source: "to_name=to_name\nto_address=to_address\nfrom_name=from_name\nfrom_address=from_address", + exp: &configuration.Configuration{ + ToName: "to_name", + ToAddress: "to_address", + FromName: "from_name", + FromAddress: "from_address", + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + test.Equals(t, tc.exp, configuration.New(strings.NewReader(tc.source))) + }) + } +} + +func TestConfigs(t *testing.T) { + conf := &configuration.Configuration{ + IMAPURL: "imap_url", + IMAPUsername: "imap_username", + IMAPPassword: "imap_password", + SMTPURL: "smtp_url", + SMTPUsername: "smtp_username", + SMTPPassword: "smtp_password", + ToName: "to_name", + ToAddress: "to_address", + FromName: "from_name", + FromAddress: "from_address", + } + + t.Run("imap", func(t *testing.T) { + exp := &mstore.IMAPConfig{ + IMAPURL: "imap_url", + IMAPUsername: "imap_username", + IMAPPassword: "imap_password", + } + + test.Equals(t, exp, conf.IMAP()) + }) + + t.Run("smtp", func(t *testing.T) { + exp := &msend.SSLSMTPConfig{ + URL: "smtp_url", + Username: "smtp_username", + Password: "smtp_password", + To: "to_address", + From: "from_address", + } + test.Equals(t, exp, conf.SMTP()) + }) +} diff --git a/pkg/mstore/imap.go b/pkg/mstore/imap.go index 4a4a2ae..a352ebf 100644 --- a/pkg/mstore/imap.go +++ b/pkg/mstore/imap.go @@ -98,7 +98,9 @@ func (im *IMAP) Close() { } func (im *IMAP) Folders() ([]string, error) { - im.Connect() + if err := im.Connect(); err != nil { + return []string{}, err + } defer im.Close() boxes, done := make(chan *imap.MailboxInfo), make(chan error) @@ -134,7 +136,9 @@ func (im *IMAP) selectFolder(folder string) error { } func (im *IMAP) Messages(folder string) ([]*Message, error) { - im.Connect() + if err := im.Connect(); err != nil { + return []*Message{}, err + } defer im.Close() if err := im.selectFolder(folder); err != nil { @@ -210,7 +214,9 @@ func (im *IMAP) Messages(folder string) ([]*Message, error) { } func (im *IMAP) Add(folder, subject, body string) error { - im.Connect() + if err := im.Connect(); err != nil { + return err + } defer im.Close() msgStr := fmt.Sprintf(`From: todo @@ -232,7 +238,10 @@ func (im *IMAP) Remove(msg *Message) error { if msg == nil || !msg.Valid() { return ErrInvalidMessage } - im.Connect() + + if err := im.Connect(); err != nil { + return err + } defer im.Close() if err := im.selectFolder(msg.Folder); err != nil {