cc590524c4
Also * Added decode of LoginStart message * Add metrics backend constants * Updated usage section * Documented MaxFrameLength
149 lines
3.7 KiB
Go
149 lines
3.7 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/sirupsen/logrus"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// WebhookNotifier implements ConnectionNotifier by sending a POST request to a webhook URL.
|
|
// The payload is a JSON object defined by WebhookNotifierPayload.
|
|
type WebhookNotifier struct {
|
|
url string
|
|
requireUser bool
|
|
|
|
client *http.Client
|
|
}
|
|
|
|
const (
|
|
WebhookEventConnecting = "connect"
|
|
)
|
|
|
|
const (
|
|
WebhookStatusMissingBackend = "missing-backend"
|
|
WebhookStatusFailedBackendConnection = "failed-backend-connection"
|
|
WebhookStatusSuccess = "success"
|
|
)
|
|
|
|
type WebhookNotifierPayload struct {
|
|
Event string `json:"event"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Status string `json:"status"`
|
|
Client *ClientInfo `json:"client"`
|
|
Server string `json:"server"`
|
|
PlayerInfo *PlayerInfo `json:"player,omitempty"`
|
|
BackendHostPort string `json:"backend,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
func NewWebhookNotifier(url string, requireUser bool) *WebhookNotifier {
|
|
|
|
return &WebhookNotifier{
|
|
url: url,
|
|
requireUser: requireUser,
|
|
client: &http.Client{
|
|
Timeout: 30 * time.Second,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (w *WebhookNotifier) NotifyMissingBackend(ctx context.Context, clientAddr net.Addr, server string, playerInfo *PlayerInfo) error {
|
|
if w.requireUser && playerInfo == nil {
|
|
return nil
|
|
}
|
|
|
|
payload := &WebhookNotifierPayload{
|
|
Event: WebhookEventConnecting,
|
|
Timestamp: time.Now(),
|
|
Status: WebhookStatusMissingBackend,
|
|
Client: ClientInfoFromAddr(clientAddr),
|
|
Server: server,
|
|
PlayerInfo: playerInfo,
|
|
Error: "No backend found",
|
|
}
|
|
|
|
return w.send(ctx, payload)
|
|
}
|
|
|
|
func (w *WebhookNotifier) NotifyFailedBackendConnection(ctx context.Context, clientAddr net.Addr, server string,
|
|
playerInfo *PlayerInfo, backendHostPort string, err error) error {
|
|
if w.requireUser && playerInfo == nil {
|
|
return nil
|
|
}
|
|
|
|
payload := &WebhookNotifierPayload{
|
|
Event: WebhookEventConnecting,
|
|
Timestamp: time.Now(),
|
|
Status: WebhookStatusFailedBackendConnection,
|
|
Client: ClientInfoFromAddr(clientAddr),
|
|
Server: server,
|
|
PlayerInfo: playerInfo,
|
|
BackendHostPort: backendHostPort,
|
|
Error: err.Error(),
|
|
}
|
|
|
|
return w.send(ctx, payload)
|
|
}
|
|
|
|
func (w *WebhookNotifier) NotifyConnected(ctx context.Context, clientAddr net.Addr, serverAddress string, playerInfo *PlayerInfo, backendHostPort string) error {
|
|
if w.requireUser && playerInfo == nil {
|
|
return nil
|
|
}
|
|
|
|
payload := &WebhookNotifierPayload{
|
|
Event: WebhookEventConnecting,
|
|
Timestamp: time.Now(),
|
|
Status: WebhookStatusSuccess,
|
|
Client: ClientInfoFromAddr(clientAddr),
|
|
Server: serverAddress,
|
|
PlayerInfo: playerInfo,
|
|
BackendHostPort: backendHostPort,
|
|
}
|
|
|
|
return w.send(ctx, payload)
|
|
}
|
|
|
|
func (w *WebhookNotifier) send(ctx context.Context, payload *WebhookNotifierPayload) error {
|
|
jsonPayload, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal webhook payload: %v", err)
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(
|
|
ctx,
|
|
http.MethodPost,
|
|
w.url,
|
|
bytes.NewBuffer(jsonPayload),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create webhook request: %v", err)
|
|
}
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
go func() {
|
|
resp, err := w.client.Do(req)
|
|
if err != nil {
|
|
// Handle error
|
|
log.Printf("Failed to send webhook notification: %v", err)
|
|
return
|
|
}
|
|
_ = resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 400 {
|
|
logrus.
|
|
WithField("status", resp.StatusCode).
|
|
Warn("webhook receiver responded with an error")
|
|
}
|
|
|
|
}()
|
|
|
|
return nil
|
|
}
|