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 }