summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorGrégoire Duchêne <gduchene@awhk.org>2021-07-04 17:20:50 +0100
committerGrégoire Duchêne <gduchene@awhk.org>2021-07-04 17:20:50 +0100
commitd95e8ce75cc193181fd8cf9272269fbfff911f66 (patch)
treef25e86b4768050d39b932bfb9e42970cfc5936e4 /cmd
parent03f9f907ed21a9c56b229668b28571969d988a8c (diff)
Simplify project structure
Diffstat (limited to 'cmd')
-rw-r--r--cmd/fwdsms/config.go44
-rw-r--r--cmd/fwdsms/config_test.go36
-rw-r--r--cmd/fwdsms/mailer.go122
-rw-r--r--cmd/fwdsms/mailer_test.go52
-rw-r--r--cmd/fwdsms/main.go89
5 files changed, 0 insertions, 343 deletions
diff --git a/cmd/fwdsms/config.go b/cmd/fwdsms/config.go
deleted file mode 100644
index 64a4a51..0000000
--- a/cmd/fwdsms/config.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-FileCopyrightText: © 2020 Grégoire Duchêne <gduchene@awhk.org>
-// SPDX-License-Identifier: ISC
-
-package main
-
-import (
- "io"
-
- "gopkg.in/yaml.v3"
-)
-
-type Config struct {
- Message Message `yaml:"message"`
- SMTP SMTP `yaml:"smtp"`
- Twilio Twilio `yaml:"twilio"`
-}
-
-type Message struct {
- From string `yaml:"from"`
- To string `yaml:"to"`
- Subject string `yaml:"subject"`
- Template string `yaml:"template"`
-}
-
-type SMTP struct {
- Address string `yaml:"hostname"`
- Username string `yaml:"username"`
- Password string `yaml:"password"`
-}
-
-type Twilio struct {
- Address string `yaml:"address"`
- AuthToken string `yaml:"authToken"`
- Endpoint string `yaml:"endpoint"`
-}
-
-func loadConfig(r io.Reader) (*Config, error) {
- dec := yaml.NewDecoder(r)
- cfg := &Config{}
- if err := dec.Decode(cfg); err != nil {
- return nil, err
- }
- return cfg, nil
-}
diff --git a/cmd/fwdsms/config_test.go b/cmd/fwdsms/config_test.go
deleted file mode 100644
index a303719..0000000
--- a/cmd/fwdsms/config_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package main
-
-import (
- "strings"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-const cfg string = `
-message:
- from: foo@example.com
- to: bar@example.com
- subject: New SMS From {{.From}} For {{.To}}
- template: |
- From: {{.From}}
- To: {{.To}}
- Date: {{.DateReceived.UTC}}
-
- {{.Message}}
-
-smtp:
- hostname: example.com:465
- username: bar
- password: some password
-
-twilio:
- address: /run/fwdsms/socket
- authToken: some token
- endpoint: /
-`
-
-func TestConfig(t *testing.T) {
- _, err := loadConfig(strings.NewReader(cfg))
- assert.NoError(t, err)
-}
diff --git a/cmd/fwdsms/mailer.go b/cmd/fwdsms/mailer.go
deleted file mode 100644
index cb687c9..0000000
--- a/cmd/fwdsms/mailer.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-FileCopyrightText: © 2020 Grégoire Duchêne <gduchene@awhk.org>
-// SPDX-License-Identifier: ISC
-
-package main
-
-import (
- "bytes"
- "context"
- "crypto/tls"
- "fmt"
- "log"
- "net"
- "net/smtp"
- "text/template"
- "time"
-
- "go.awhk.org/fwdsms/pkg/twilio"
-)
-
-type email struct {
- from, to string
- body []byte
-}
-
-type mailer struct {
- auth smtp.Auth
- hostname string
- sms <-chan twilio.SMS
- tmplFrom, tmplTo, tmplMsg *template.Template
-}
-
-func (m *mailer) sendEmail(e email) error {
- dialer := &net.Dialer{Timeout: time.Second}
- conn, err := tls.DialWithDialer(dialer, "tcp", m.hostname, nil)
- if err != nil {
- return err
- }
- if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
- log.Printf("Failed to set the SMTP connection deadline: %s.", err)
- }
- h, _, _ := net.SplitHostPort(m.hostname)
- c, err := smtp.NewClient(conn, h)
- if err != nil {
- conn.Close()
- return err
- }
- defer c.Close()
- if err := c.Auth(m.auth); err != nil {
- return err
- }
-
- if err := c.Mail(e.from); err != nil {
- return err
- }
- if err := c.Rcpt(e.to); err != nil {
- return err
- }
- w, err := c.Data()
- if err != nil {
- return err
- }
- if _, err := w.Write(e.body); err != nil {
- return err
- }
- if err = w.Close(); err != nil {
- return nil
- }
- return c.Quit()
-}
-
-func (m *mailer) newEmail(sms twilio.SMS) email {
- var from, to, msg bytes.Buffer
- if err := m.tmplFrom.Execute(&from, sms); err != nil {
- log.Printf("Failed to apply a template: %v.", err)
- }
- if err := m.tmplTo.Execute(&to, sms); err != nil {
- log.Printf("Failed to apply a template: %v.", err)
- }
- if err := m.tmplMsg.Execute(&msg, sms); err != nil {
- log.Printf("Failed to apply a template: %v.", err)
- }
- return email{from.String(), to.String(), msg.Bytes()}
-}
-
-func (m *mailer) start(ctx context.Context) {
- for {
- select {
- case <-ctx.Done():
- return
- case sms := <-m.sms:
- if err := m.sendEmail(m.newEmail(sms)); err != nil {
- log.Printf("Failed to send email: %v.", err)
- }
- }
- }
-}
-
-func newMailer(cfg *Config, sms <-chan twilio.SMS) *mailer {
- if cfg.Message.From == "" {
- log.Fatal("Missing From field.")
- }
- if cfg.Message.To == "" {
- log.Fatal("Missing To field.")
- }
- if cfg.Message.Subject == "" {
- log.Fatal("Missing Subject field.")
- }
- if cfg.Message.Template == "" {
- log.Fatal("Missing Template field.")
- }
- tmplMsg := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s\r\n",
- cfg.Message.From, cfg.Message.To, cfg.Message.Subject, cfg.Message.Template)
- host, _, _ := net.SplitHostPort(cfg.SMTP.Address)
- return &mailer{
- auth: smtp.PlainAuth("", cfg.SMTP.Username, cfg.SMTP.Password, host),
- hostname: cfg.SMTP.Address,
- sms: sms,
- tmplFrom: template.Must(template.New("from").Parse(cfg.Message.From)),
- tmplTo: template.Must(template.New("to").Parse(cfg.Message.To)),
- tmplMsg: template.Must(template.New("message").Parse(tmplMsg)),
- }
-}
diff --git a/cmd/fwdsms/mailer_test.go b/cmd/fwdsms/mailer_test.go
deleted file mode 100644
index e1376c3..0000000
--- a/cmd/fwdsms/mailer_test.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// SPDX-FileCopyrightText: © 2020 Grégoire Duchêne <gduchene@awhk.org>
-// SPDX-License-Identifier: ISC
-
-package main
-
-import (
- "strings"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-
- "go.awhk.org/fwdsms/pkg/twilio"
-)
-
-func TestMailer_newEmail(t *testing.T) {
- m := newMailer(&Config{
- Message: Message{
- From: "fwdsms@example.com",
- To: "sms{{.To}}@example.com",
- Subject: "New SMS From {{.From}}",
- Template: `From: {{.From}}
- To: {{.To}}
-Date: {{.DateReceived.UTC}}
-
-{{.Body}}`,
- }}, nil)
- // Reserved phone numbers, see Ofcom's website.
- sms := twilio.SMS{
- DateReceived: time.Unix(0, 0),
- From: "+442079460123",
- To: "+447700900123",
- Body: "Hello World!",
- }
- wants := email{
- from: "fwdsms@example.com",
- to: "sms+447700900123@example.com",
- body: []byte(strings.Join([]string{
- "From: fwdsms@example.com",
- "To: sms+447700900123@example.com",
- "Subject: New SMS From +442079460123",
- "",
- `From: +442079460123
- To: +447700900123
-Date: 1970-01-01 00:00:00 +0000 UTC
-
-Hello World!`,
- "",
- }, "\r\n")),
- }
- assert.Equal(t, wants, m.newEmail(sms))
-}
diff --git a/cmd/fwdsms/main.go b/cmd/fwdsms/main.go
deleted file mode 100644
index 090331f..0000000
--- a/cmd/fwdsms/main.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// SPDX-FileCopyrightText: © 2020 Grégoire Duchêne <gduchene@awhk.org>
-// SPDX-License-Identifier: ISC
-
-package main
-
-import (
- "context"
- "flag"
- "log"
- "net"
- "net/http"
- "os"
- "os/signal"
- "time"
-
- "github.com/gorilla/handlers"
- "github.com/gorilla/mux"
- "golang.org/x/sys/unix"
-
- "go.awhk.org/fwdsms/pkg/twilio"
-)
-
-var cfgFilename = flag.String("c", "/etc/fwdsms.yaml", "configuration file")
-
-func main() {
- flag.Parse()
- log.SetFlags(0)
- fd, err := os.Open(*cfgFilename)
- if err != nil {
- log.Fatalf("Could not open the configuration file: %v.", err)
- }
- cfg, err := loadConfig(fd)
- if err != nil {
- log.Fatalf("Could not load the configuration: %v.", err)
- }
-
- done := make(chan os.Signal, 1)
- signal.Notify(done, os.Interrupt, unix.SIGTERM)
-
- sms := make(chan twilio.SMS)
-
- r := mux.NewRouter()
- r.Path(cfg.Twilio.Endpoint).
- Methods(http.MethodPost).
- Handler(handlers.ProxyHeaders(&twilio.Filter{
- AuthToken: []byte(cfg.Twilio.AuthToken),
- Handler: &twilio.SMSTee{
- Chan: sms,
- Handler: twilio.EmptyResponseHandler,
- },
- }))
- srv := http.Server{Handler: r}
- go func() {
- var (
- l net.Listener
- err error
- )
- if cfg.Twilio.Address != "" && cfg.Twilio.Address[0] == '/' {
- if l, err = net.Listen("unix", cfg.Twilio.Address); err != nil {
- log.Fatalf("Could not set up UNIX listener: %v.", err)
- }
- if err = os.Chmod(cfg.Twilio.Address, 0666); err != nil {
- log.Fatalf("Could not set up permissions on UNIX socket: %v.", err)
- }
- } else {
- if cfg.Twilio.Address == "" {
- cfg.Twilio.Address = ":8080"
- }
- if l, err = net.Listen("tcp", cfg.Twilio.Address); err != nil {
- log.Fatalf("Could not set up TCP listener: %v.", err)
- }
- }
- if err = srv.Serve(l); err != nil && err != http.ErrServerClosed {
- log.Fatalf("Failed to serve HTTP: %v.", err)
- }
- }()
-
- mailer := newMailer(cfg, sms)
- ctx, cancel := context.WithCancel(context.Background())
- go mailer.start(ctx)
-
- <-done
- cancel()
- ctx, cancel = context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- if err := srv.Shutdown(ctx); err != nil && err != http.ErrServerClosed {
- log.Fatalf("Failed to properly shut down the HTTP server: %v.", err)
- }
-}