icinga2-matrix-notification/internal/matrix/message.go

97 lines
2.6 KiB
Go
Raw Normal View History

2024-09-26 14:45:04 +02:00
// Copyright Jan Dittberner
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2024-09-26 14:45:04 +02:00
package matrix
import (
"bytes"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)
const transactionIDLength = 16
type Message struct {
Type string `json:"msgtype"`
Body string `json:"body"`
FormattedBody string `json:"formatted_body"`
Format string `json:"format"`
}
func SendMessage(server *url.URL, room string, token string, message string) error {
messageBytes, err := json.Marshal(Message{
Type: TextMessage,
Body: message,
FormattedBody: message,
Format: HTMLFormat,
})
if err != nil {
return fmt.Errorf("could not build JSON message: %w", err)
}
transaction, err := generateTransactionID()
if err != nil {
return err
}
postURL := server.JoinPath("/_matrix/client/r0/rooms/", room, "/send/m.room.message/", transaction)
request, err := http.NewRequest(http.MethodPut, postURL.String(), bytes.NewBuffer(messageBytes))
if err != nil {
return fmt.Errorf("could not build request: %w", err)
}
request.Header.Set("Accept", "application/json")
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Authorization", "Bearer "+token)
response, err := http.DefaultClient.Do(request)
if err != nil {
return fmt.Errorf("could not send request: %w", err)
}
defer func() {
_ = response.Body.Close()
}()
if response.StatusCode > http.StatusBadRequest {
responseBody, err := io.ReadAll(response.Body)
if err != nil {
return fmt.Errorf("received an error: %s, could not read response body: %w", response.Status, err)
}
return fmt.Errorf("received an error: %s %s", response.Status, string(responseBody))
}
return nil
}
func generateTransactionID() (string, error) {
IDBytes := make([]byte, transactionIDLength)
_, err := rand.Read(IDBytes)
if err != nil {
return "", fmt.Errorf("could not generate transaction id: %w", err)
}
return base64.RawURLEncoding.EncodeToString(IDBytes), nil
}