From b9c0efe21f81ba96579484fae717b4e314e67b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20K=C3=B6ser?= Date: Mon, 25 Jan 2021 05:05:28 +0100 Subject: [PATCH] refactor(lib): comment and clean up code --- notify.go | 31 ++++++++--------- send.go | 5 +-- service/discord/discord.go | 5 +++ service/mail/mail.go | 64 +++++++++++++++++++----------------- service/pseudo/pseudo.go | 3 ++ service/telegram/telegram.go | 10 ++++-- use.go | 47 +++++++------------------- 7 files changed, 78 insertions(+), 87 deletions(-) diff --git a/notify.go b/notify.go index cebdc29..fc50186 100644 --- a/notify.go +++ b/notify.go @@ -4,31 +4,32 @@ import ( "github.com/pkg/errors" ) -type Notifier struct { - Disabled bool - services []Service +const defaultDisabled = false // Notifier is enabled by default + +// Notify is the central struct for managing notification services and sending messages to them. +type Notify struct { + Disabled bool + notifiers []Notifier } -const defaultDisabled = false - +// ErrSendNotification signals that the notifier failed to send a notification. var ErrSendNotification = errors.New("Send notification") -// Service implements a Listen and a Send method. The Listen method makes the notification Service listens -// for external commands and will answer to these commands if supported. For example, our telegram Notifier listens for -// commands like /info and will answer with basic information about the server. The Send command simply sends a -// message string to the internal destination Service. E.g for telegram it sends the message to the specified group -// chat. -type Service interface { +// Notifier defines the behavior for notification services. The Send command simply sends a message string to the +// internal destination Notifier. E.g for telegram it sends the message to the specified group chat. +type Notifier interface { Send(string, string) error } -func New() *Notifier { - notifier := &Notifier{ +// New returns a new instance of Notify. Defaulting to being not disabled and using the pseudo notification +// service under the hood. +func New() *Notify { + notifier := &Notify{ Disabled: defaultDisabled, } - // Use the pseudo Service to prevent from nil reference bugs when using the Notifier Service. In case no services - // are provided or the creation of all other services failed, the pseudo Service will be used under the hood + // Use the pseudo Notifier to prevent from nil reference bugs when using the Notify Notifier. In case no notifiers + // are provided or the creation of all other notifiers failed, the pseudo Notifier will be used under the hood // doing nothing but preventing nil-reference errors. notifier.usePseudo() diff --git a/send.go b/send.go index 09784a8..66e8a9d 100644 --- a/send.go +++ b/send.go @@ -5,14 +5,15 @@ import ( "golang.org/x/sync/errgroup" ) -func (n Notifier) Send(subject, message string) error { +// Send calls the underlying notification services to send the given message to their respective endpoints. +func (n Notify) Send(subject, message string) error { if n.Disabled { return nil } var eg errgroup.Group - for _, service := range n.services { + for _, service := range n.notifiers { if service != nil { s := service eg.Go(func() error { diff --git a/service/discord/discord.go b/service/discord/discord.go index 74d6787..c2bb8bf 100644 --- a/service/discord/discord.go +++ b/service/discord/discord.go @@ -5,11 +5,13 @@ import ( "github.com/pkg/errors" ) +// Discord struct holds necessary data to communicate with the Discord API. type Discord struct { client *discordgo.Session channelIDs []string } +// New takes a Discord API token and returns a new instance of a Discord notification service. func New(apiToken string) (*Discord, error) { client, err := discordgo.New("Bot " + apiToken) if err != nil { @@ -24,10 +26,13 @@ func New(apiToken string) (*Discord, error) { return d, nil } +// AddReceivers takes Telegram channel IDs and adds them to the internal channel ID list. The Send method will send +// a given message to all those channels. func (d *Discord) AddReceivers(channelIDs ...string) { d.channelIDs = append(d.channelIDs, channelIDs...) } +// Send takes a message subject and a message body and sends them to all previously set chats. func (d Discord) Send(subject, message string) error { fullMessage := subject + "\n" + message // Treating subject as message title diff --git a/service/mail/mail.go b/service/mail/mail.go index 9f641a4..5a5b754 100644 --- a/service/mail/mail.go +++ b/service/mail/mail.go @@ -1,55 +1,57 @@ package mail import ( + "net/smtp" + "net/textproto" + + "github.com/jordan-wright/email" "github.com/pkg/errors" - gomail "gopkg.in/mail.v2" -) - -const ( - headerFrom = "From" - headerTo = "To" - headerSubject = "Subject" - bodyContentType = "text/plain" ) +// Mail struct holds necessary data to send emails. type Mail struct { - client *gomail.Dialer + senderAddress string + smtpHostAddr string + smtpAuth smtp.Auth receiverAddresses []string } -func New(host, userName, password string, port int) (*Mail, error) { - client := gomail.NewDialer(host, port, userName, password) - - m := &Mail{ - client: client, +// New returns a new instance of a Mail notification service. +func New(senderAddress, smtpHostAddress string) *Mail { + return &Mail{ + senderAddress: senderAddress, + smtpHostAddr: smtpHostAddress, receiverAddresses: []string{}, } - - return m, nil } +// AuthenticateSMTP authenticates you to send emails via smtp. +// Example values: "", "test@gmail.com", "password123", "smtp.gmail.com" +func (m *Mail) AuthenticateSMTP(identity, userName, password, host string) { + m.smtpAuth = smtp.PlainAuth(identity, userName, password, host) +} + +// AddReceivers takes email addresses and adds them to the internal address list. The Send method will send +// a given message to all those addresses. func (m *Mail) AddReceivers(addresses ...string) { m.receiverAddresses = append(m.receiverAddresses, addresses...) } +// Send takes a message subject and a message body and sends them to all previously set chats. Message body supports +// html as markup language. func (m Mail) Send(subject, message string) error { - msg := gomail.NewMessage() + msg := &email.Email{ + To: m.receiverAddresses, + From: m.senderAddress, + Subject: subject, + // Text: []byte("Text Body is, of course, supported!"), + HTML: []byte(message), + Headers: textproto.MIMEHeader{}, + } - // Set E-Mail sender - msg.SetHeader(headerFrom, m.client.Host) - - // Set E-Mail receivers - msg.SetHeader(headerTo, m.receiverAddresses...) - - // Set E-Mail subject - msg.SetHeader(headerSubject, subject) - - // Set E-Mail body - msg.SetBody(bodyContentType, message) - - err := m.client.DialAndSend(msg) + err := msg.Send(m.smtpHostAddr, m.smtpAuth) if err != nil { - err = errors.Wrap(err, "failed to dial and send mail") + err = errors.Wrap(err, "failed to send mail") } return err diff --git a/service/pseudo/pseudo.go b/service/pseudo/pseudo.go index 26abc1d..e00d1c6 100644 --- a/service/pseudo/pseudo.go +++ b/service/pseudo/pseudo.go @@ -2,10 +2,13 @@ package pseudo type Pseudo struct{} +// New returns a new instance of a Pseudo notification service. This is used internally to initialize +// notification services list and prevent nil-reference errors. func New() *Pseudo { return &Pseudo{} } +// Send basically does nothing. Just here to conform the notify.Notifier interface. func (Pseudo) Send(string, string) error { return nil } diff --git a/service/telegram/telegram.go b/service/telegram/telegram.go index b92df30..f2aae94 100644 --- a/service/telegram/telegram.go +++ b/service/telegram/telegram.go @@ -5,16 +5,16 @@ import ( "github.com/pkg/errors" ) -const ( - defaultParseMode = tgbotapi.ModeHTML -) +const defaultParseMode = tgbotapi.ModeHTML +// Telegram struct holds necessary data to communicate with the Telegram API. type Telegram struct { client *tgbotapi.BotAPI listener *tgbotapi.BotAPI chatIDs []int64 } +// New returns a new instance of a Telegram notification service. func New(apiToken string) (*Telegram, error) { client, err := tgbotapi.NewBotAPI(apiToken) if err != nil { @@ -29,10 +29,14 @@ func New(apiToken string) (*Telegram, error) { return t, nil } +// AddReceivers takes Telegram chat IDs and adds them to the internal chat ID list. The Send method will send +// a given message to all those chats. func (t *Telegram) AddReceivers(chatIDs ...int64) { t.chatIDs = append(t.chatIDs, chatIDs...) } +// Send takes a message subject and a message body and sends them to all previously set chats. Message body supports +// html as markup language. func (t Telegram) Send(subject, message string) error { fullMessage := subject + "\n" + message // Treating subject as message title diff --git a/use.go b/use.go index c1cf021..c3acf41 100644 --- a/use.go +++ b/use.go @@ -4,55 +4,30 @@ import ( "github.com/nikoksr/notify/service/pseudo" ) -func (n *Notifier) useService(service Service) { +// useService adds a given service to the notifiers services list. If the list still contains +// a pseudo service we remove it before adding the 'real' service. +func (n *Notify) useService(service Notifier) { if service == nil { return } // Remove pseudo service in case a 'real' service will be added - if len(n.services) > 0 { - _, isPseudo := n.services[0].(*pseudo.Pseudo) + if len(n.notifiers) > 0 { + _, isPseudo := n.notifiers[0].(*pseudo.Pseudo) if isPseudo { - n.services = n.services[1:] + n.notifiers = n.notifiers[1:] } } - n.services = append(n.services, service) + n.notifiers = append(n.notifiers, service) } -// usePseudo adds a pseudo Service to the Service list. -func (n *Notifier) usePseudo() { +// usePseudo adds a pseudo notification service to the notifiers services list. +func (n *Notify) usePseudo() { n.useService(pseudo.New()) } -func (n *Notifier) UseService(service Service) { +// UseService adds a given service to the notifiers services list. +func (n *Notify) UseService(service Notifier) { n.useService(service) } - -/* -func (n *Notifier) UseTelegram(apiToken string, chatID int64) error { - telegramService, err := telegram.New(apiToken) - if err != nil { - return err - } - - telegramService.AddReceivers(chatID) - - n.useService(telegramService) - - return nil -} - -func (n *Notifier) UseDiscordService(apiToken, channelID string) error { - discordService, err := discord.New(apiToken) - if err != nil { - return err - } - - discordService.AddReceivers(channelID) - - n.useService(discordService) - - return nil -} -*/