feat: publish standalone worker
Separate worker packaging and service lifecycle from the control plane.
Этот коммит содержится в:
155
internal/sender/mattermost.go
Обычный файл
155
internal/sender/mattermost.go
Обычный файл
@@ -0,0 +1,155 @@
|
||||
package sender
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"rsgit.ru/rsmon/rsmon/app/models"
|
||||
"rsgit.ru/rsmon/rsmon/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
|
||||
}
|
||||
Ссылка в новой задаче
Block a user