hotalert/alert/discord.go

84 lines
2.6 KiB
Go
Raw Permalink Normal View History

2022-11-03 20:04:14 +00:00
package alert
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"hotalert/logging"
"net/http"
"strings"
)
// DiscordWebhookAlerter is a struct that implements alerting on Discord via webhooks.
type DiscordWebhookAlerter struct {
// webhook is the Discord webhook URL.
webhook string
// messageTemplate is the message that is going to be posted when the alert conditions match.
messageTemplate string
// HttpClient is the http client used when executing requests.
HttpClient *http.Client
}
// DiscordWebhookAlerterOptions are the options for the DiscordWebhookAlerter
type DiscordWebhookAlerterOptions struct {
// Webhook is the discord webhook.
Webhook string `mapstructure:"webhook"`
// MessageTemplate is the message template that is going to be posted.
MessageTemplate string `mapstructure:"message"`
}
// Validate validates the DiscordWebhookAlerterOptions, returns an error on invalid options.
func (o *DiscordWebhookAlerterOptions) Validate() error {
if o.Webhook == "" || o.MessageTemplate == "" {
return errors.New("invalid configuration for webhook_discord")
}
if !strings.Contains(o.Webhook, "http://") && !strings.Contains(o.Webhook, "https://") {
return errors.New(fmt.Sprintf("invalid webhook schema for %s", o.Webhook))
}
return nil
}
// NewDiscordWebhookAlerter returns a new DiscordWebhookAlerter instance.
func NewDiscordWebhookAlerter(options DiscordWebhookAlerterOptions) (*DiscordWebhookAlerter, error) {
if err := options.Validate(); err != nil {
return nil, err
}
return &DiscordWebhookAlerter{
webhook: options.Webhook,
messageTemplate: options.MessageTemplate,
HttpClient: http.DefaultClient,
}, nil
}
// PostAlert posts the alert on Discord via webhooks.
func (d *DiscordWebhookAlerter) PostAlert(ctx context.Context, matchedKeywords []string) {
alertMessage := strings.Replace(d.messageTemplate, "$keywords", strings.Join(matchedKeywords, ","), -1)
var postBody = map[string]interface{}{
"content": alertMessage,
"embeds": nil,
"attachments": nil,
}
postBodyBytes, err := json.Marshal(postBody)
if err != nil {
logging.SugaredLogger.Errorf("Failed to marshall postBody: %v", err)
return
}
postRequest, err := http.NewRequest("POST", d.webhook, bytes.NewBuffer(postBodyBytes))
if err != nil {
logging.SugaredLogger.Errorf("Failed to create alert request.")
return
}
postRequest.Header["Content-Type"] = []string{"application/json"}
_, err = d.HttpClient.Do(postRequest.WithContext(ctx))
if err != nil {
logging.SugaredLogger.Errorf("Failed to post alert to discord!")
return
}
logging.SugaredLogger.Infof("Alert posted:\nBEGIN\n%s\nEND", alertMessage)
}