Files
worker/internal/sender/mattermost.go
Gleb Tv 2c884c5612
Некоторые проверки не удались
CI / test (push) Successful in 2m5s
Docker / Build and publish worker image (push) Failing after 31s
refactor: adopt worker module path
2026-07-13 17:56:12 +03:00

156 строки
3.7 KiB
Go

package sender
import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"log"
"net/http"
"time"
"rocketgit.ru/rsmon/worker/app/models"
"rocketgit.ru/rsmon/worker/internal/wire"
)
// messageKindUp is the canonical string the notifier uses for "monitor
// just came back up" events. Lives here as a package-level constant so
// the goconst linter stops flagging the literal "up" appearing three
// times across the sender package.
const messageKindUp = "up"
// MattermostPayload provides functionality.
type MattermostPayload struct {
Channel *string `json:"channel,omitempty"`
Username *string `json:"username,omitempty"`
IconURL *string `json:"icon_url,omitempty"`
Text *string `json:"text,omitempty"`
}
// RunMattermost provides functionality.
func RunMattermost(message *models.Message) (*string, error) {
_, _, markdownBody, _ := GetContent(message, time.Now())
s := "@channel "
if message.Kind == messageKindUp {
s += ":white_check_mark: "
} else {
s += ":warning: "
}
s = s + "\n\n" + markdownBody.String()
color := "green"
if message.Kind == "down" {
color = "red"
}
un := "RSMon"
icon := "https://rsmon.ru/" + color + "_logo.svg"
payload := MattermostPayload{
Text: &s,
Username: &un,
IconURL: &icon,
}
body, err := json.Marshal(payload)
if err != nil {
return nil, err
}
log.Println("send mattermost:", message.Contact.Value)
// log.Println(string(body))
resp, err := httpClient.Post(
message.Contact.Value,
"application/json",
bytes.NewBuffer(body),
)
if err != nil {
return nil, err
}
defer resp.Body.Close() //nolint:errcheck
body, err = io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
str := string(body)
return &str, nil
}
// SendMattermostWithCredential delivers a Mattermost notification using the
// supplied wire credential block (which carries the default username +
// icon URL). The webhook URL is per-task; the credential block only sets
// the cosmetic defaults. This mirrors what the legacy RunMattermost did with
// secrets + a hardcoded RSMon username / icon.
func SendMattermostWithCredential(
contactValue, messageKind, subject, markdownBody string,
cred *wire.MattermostCredential,
) (*string, error) {
return SendMattermostWithCredentialContext(context.Background(), contactValue, messageKind, subject, markdownBody, cred)
}
func SendMattermostWithCredentialContext(
ctx context.Context, contactValue, messageKind, subject, markdownBody string,
cred *wire.MattermostCredential,
) (*string, error) {
if contactValue == "" {
return nil, errors.New("mattermost contact value is empty")
}
s := "@channel "
if messageKind == messageKindUp {
s += ":white_check_mark: "
} else {
s += ":warning: "
}
s = s + "\n\n" + subject + "\n\n" + markdownBody
color := "green"
if messageKind == "down" {
color = "red"
}
username := "RSMon"
iconURL := "https://rsmon.ru/" + color + "_logo.svg"
if cred != nil {
if cred.DefaultUsername != "" {
username = cred.DefaultUsername
}
if cred.DefaultIconURL != "" {
iconURL = cred.DefaultIconURL
}
}
payload := MattermostPayload{
Text: &s,
Username: &username,
IconURL: &iconURL,
}
body, err := json.Marshal(payload)
if err != nil {
return nil, err
}
client := &http.Client{Timeout: 60 * time.Second}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, contactValue, bytes.NewBuffer(body))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close() //nolint:errcheck
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
str := string(respBody)
return &str, nil
}