diff --git a/msgerrors/msgerror.go b/msgerrors/msgerror.go new file mode 100644 index 00000000..b172e656 --- /dev/null +++ b/msgerrors/msgerror.go @@ -0,0 +1,46 @@ +package msgerrors + +import ( + "errors" + "strings" +) + +// MsgError wraps a slice of errors and provides convenient +// syntax for processing individual errors without breaking +// the service +type MsgError struct { + err []string +} + +// New instantiates a MsgError with a nil Err field +func New() *MsgError { + return &MsgError{err: make([]string, 0, 0)} +} + +// Append safely adds a new error to our list +func (m *MsgError) Append(err error) { + if err != nil { + m.err = append(m.err, err.Error()) + } +} + +// Error provides the string output of our error +// This allows MsgError to implement the core "error" +// interface +func (m *MsgError) Error() string { + if len(m.err) == 0 { + return "" + } + return strings.Join(m.err, "\n") +} + +// Errors provides conventient syntax for returning +// an error containing all information about the +// accumulated errors in code. It will return +// nil if no errors have been collated +func (m *MsgError) Errors() error { + if len(m.err) == 0 { + return nil + } + return errors.New(m.Error()) +} diff --git a/msgerrors/msgerror_test.go b/msgerrors/msgerror_test.go new file mode 100644 index 00000000..1f2c0938 --- /dev/null +++ b/msgerrors/msgerror_test.go @@ -0,0 +1,36 @@ +package msgerrors + +import ( + "errors" + "strings" + "testing" +) + +func TestMsgError(t *testing.T) { + msgErr := New() + + if msgErr.Error() != "" { + t.Errorf("Expected empty string. Recieved %s", msgErr.Error()) + } + if msgErr.Errors() != nil { + t.Errorf("Expected nil. Recieved %s", msgErr.Errors()) + } + + err1 := errors.New("Error 1") + err2 := errors.New("Error 2") + msgErr.Append(err1) + msgErr.Append(err2) + + if len(msgErr.err) != 2 { + t.Errorf("Expected length 2. Recieved %d", len(msgErr.err)) + } + + concatenatedErr := strings.Join([]string{"Error 1", "Error 2"}, "\n") + if msgErr.Error() != concatenatedErr { + t.Errorf("Expected %s. \n Recieved %s", concatenatedErr, msgErr.Error()) + } + + if msgErr.Errors() == nil { + t.Errorf("Expected %s. \n Recieved %s", errors.New(concatenatedErr), msgErr.Errors()) + } +} diff --git a/service/discord/discord.go b/service/discord/discord.go index 0c2d96cf..7703129b 100644 --- a/service/discord/discord.go +++ b/service/discord/discord.go @@ -2,6 +2,7 @@ package discord import ( "github.com/bwmarrin/discordgo" + "github.com/nikoksr/notify/msgerrors" "github.com/pkg/errors" ) @@ -90,13 +91,14 @@ func (d *Discord) AddReceivers(channelIDs ...string) { // 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 - + msgErr := msgerrors.New() for _, channelID := range d.channelIDs { _, err := d.client.ChannelMessageSend(channelID, fullMessage) if err != nil { - return errors.Wrapf(err, "failed to send message to Discord channel '%s'", channelID) + err = errors.Wrapf(err, "failed to send message to Discord channel '%s'", channelID) + msgErr.Append(err) } } - return nil + return msgErr.Errors() } diff --git a/service/mail/mail.go b/service/mail/mail.go index 55901bb4..6ae96a3a 100644 --- a/service/mail/mail.go +++ b/service/mail/mail.go @@ -53,8 +53,8 @@ func (m Mail) Send(subject, message string) error { err := msg.Send(m.smtpHostAddr, m.smtpAuth) if err != nil { - err = errors.Wrap(err, "failed to send mail") + return errors.Wrap(err, "failed to send mail") } - return err + return nil } diff --git a/service/msteams/ms_teams.go b/service/msteams/ms_teams.go index 7e484767..cce9dc55 100644 --- a/service/msteams/ms_teams.go +++ b/service/msteams/ms_teams.go @@ -2,6 +2,7 @@ package msteams import ( goteamsnotify "github.com/atc0005/go-teams-notify/v2" + "github.com/nikoksr/notify/msgerrors" "github.com/pkg/errors" ) @@ -47,13 +48,13 @@ func (m MSTeams) Send(subject, message string) error { msgCard := goteamsnotify.NewMessageCard() msgCard.Title = subject msgCard.Text = message - + msgErr := msgerrors.New() for _, webHook := range m.webHooks { err := m.client.Send(webHook, msgCard) if err != nil { - return errors.Wrapf(err, "failed to send message to Microsoft Teams via webhook '%s'", webHook) + err := errors.Wrapf(err, "failed to send message to Microsoft Teams via webhook '%s'", webHook) + msgErr.Append(err) } } - - return nil + return msgErr.Errors() } diff --git a/service/pushbullet/pushbullet.go b/service/pushbullet/pushbullet.go index e4c3a18e..d20d4d6f 100644 --- a/service/pushbullet/pushbullet.go +++ b/service/pushbullet/pushbullet.go @@ -2,6 +2,7 @@ package pushbullet import ( "github.com/cschomburg/go-pushbullet" + "github.com/nikoksr/notify/msgerrors" "github.com/pkg/errors" ) @@ -36,17 +37,20 @@ func (pb *Pushbullet) AddReceivers(deviceNicknames ...string) { // (android, chrome, firefox, windows) // see https://www.pushbullet.com/apps func (pb Pushbullet) Send(subject, message string) error { + msgErr := msgerrors.New() for _, deviceNickname := range pb.deviceNicknames { dev, err := pb.client.Device(deviceNickname) if err != nil { - return errors.Wrapf(err, "failed to find Pushbullet device with nickname '%s'", deviceNickname) + err = errors.Wrapf(err, "failed to find Pushbullet device with nickname '%s'", deviceNickname) + msgErr.Append(err) + continue } err = dev.PushNote(subject, message) if err != nil { - return errors.Wrapf(err, "failed to send message to Pushbullet device with nickname '%s'", deviceNickname) + err = errors.Wrapf(err, "failed to send message to Pushbullet device with nickname '%s'", deviceNickname) + msgErr.Append(err) } } - - return nil + return msgErr.Errors() } diff --git a/service/pushbullet/sms.go b/service/pushbullet/sms.go index 75087601..33907900 100644 --- a/service/pushbullet/sms.go +++ b/service/pushbullet/sms.go @@ -2,6 +2,7 @@ package pushbullet import ( "github.com/cschomburg/go-pushbullet" + "github.com/nikoksr/notify/msgerrors" "github.com/pkg/errors" ) @@ -49,13 +50,13 @@ func (sms SMS) Send(subject, message string) error { if err != nil { return errors.Wrapf(err, "failed to find valid pushbullet user") } - + msgErr := msgerrors.New() for _, phoneNumber := range sms.phoneNumbers { err = sms.client.PushSMS(user.Iden, sms.deviceIdentifier, phoneNumber, fullMessage) if err != nil { - return errors.Wrapf(err, "failed to send SMS message to %s via Pushbullet", phoneNumber) + err = errors.Wrapf(err, "failed to send SMS message to %s via Pushbullet", phoneNumber) + msgErr.Append(err) } } - - return nil + return msgErr.Errors() } diff --git a/service/slack/slack.go b/service/slack/slack.go index 875de91a..74cf757b 100644 --- a/service/slack/slack.go +++ b/service/slack/slack.go @@ -1,6 +1,7 @@ package slack import ( + "github.com/nikoksr/notify/msgerrors" "github.com/pkg/errors" "github.com/slack-go/slack" ) @@ -36,16 +37,16 @@ func (s *Slack) AddReceivers(channelIDs ...string) { // see https://api.slack.com/ func (s Slack) Send(subject, message string) error { fullMessage := subject + "\n" + message // Treating subject as message title - + msgErr := msgerrors.New() for _, channelID := range s.channelIDs { id, timestamp, err := s.client.PostMessage( channelID, slack.MsgOptionText(fullMessage, false), ) if err != nil { - return errors.Wrapf(err, "failed to send message to Slack channel '%s' at time '%s'", id, timestamp) + err = errors.Wrapf(err, "failed to send message to Slack channel '%s' at time '%s'", id, timestamp) + msgErr.Append(err) } } - - return nil + return msgErr.Errors() } diff --git a/service/telegram/telegram.go b/service/telegram/telegram.go index 4c4528ff..be65daa3 100644 --- a/service/telegram/telegram.go +++ b/service/telegram/telegram.go @@ -4,6 +4,7 @@ import ( "strconv" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" + "github.com/nikoksr/notify/msgerrors" "github.com/pkg/errors" ) @@ -50,14 +51,14 @@ func (t Telegram) Send(subject, message string) error { msg := tgbotapi.NewMessage(0, fullMessage) msg.ParseMode = defaultParseMode - + msgErr := msgerrors.New() for _, chatID := range t.chatIDs { msg.ChatID = chatID _, err := t.client.Send(msg) if err != nil { - return errors.Wrapf(err, "failed to send message to Telegram chat '%d'", chatID) + err = errors.Wrapf(err, "failed to send message to Telegram chat '%d'", chatID) + msgErr.Append(err) } } - - return nil + return msgErr.Errors() }