feat: implement webhook notification system and integrate into queue manager
Build / Build and Push (push) Successful in 51s

This commit is contained in:
2026-06-08 16:41:22 +01:00
parent 71e066fe0d
commit e23a0dd292
7 changed files with 76 additions and 4 deletions
+8 -2
View File
@@ -52,12 +52,17 @@ type AuthConfig struct {
Password string `yaml:"password"`
}
type NotificationsConfig struct {
WebhookURL string `yaml:"webhook_url"`
}
type Config struct {
Server ServerConfig `yaml:"server"`
Auth AuthConfig `yaml:"auth"`
Database DatabaseConfig `yaml:"database"`
Encoder EncoderConfig `yaml:"encoder"`
Logging LoggingConfig `yaml:"logging"`
Encoder EncoderConfig `yaml:"encoder"`
Logging LoggingConfig `yaml:"logging"`
Notifications NotificationsConfig `yaml:"notifications"`
}
func LoadConfig(path string) (*Config, error) {
@@ -84,6 +89,7 @@ func LoadConfig(path string) (*Config, error) {
cfg.Encoder.FFmpegPath = getEnvStr("GOENCODE_FFMPEG_PATH", cfg.Encoder.FFmpegPath)
cfg.Encoder.TempDir = getEnvStr("GOENCODE_ENCODER_TEMP", cfg.Encoder.TempDir)
cfg.Logging.Level = getEnvStr("GOENCODE_LOG_LEVEL", cfg.Logging.Level)
cfg.Notifications.WebhookURL = getEnvStr("GOENCODE_WEBHOOK_URL", cfg.Notifications.WebhookURL)
// Defaults if missing entirely
if cfg.Server.Port == 0 {
+54
View File
@@ -0,0 +1,54 @@
package notify
import (
"bytes"
"encoding/json"
"log"
"net/http"
"time"
)
type WebhookPayload struct {
Title string `json:"title"`
Message string `json:"message"`
Time string `json:"time"`
}
func SendWebhook(url, title, message string) {
if url == "" {
return
}
payload := WebhookPayload{
Title: title,
Message: message,
Time: time.Now().Format(time.RFC3339),
}
data, err := json.Marshal(payload)
if err != nil {
log.Printf("Failed to marshal webhook payload: %v", err)
return
}
go func() {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
if err != nil {
log.Printf("Failed to create webhook request: %v", err)
return
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
log.Printf("Failed to send webhook: %v", err)
return
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
log.Printf("Webhook returned error status: %d", resp.StatusCode)
}
}()
}
+3 -1
View File
@@ -14,18 +14,20 @@ type Manager struct {
TriggerChan chan struct{}
StopChan chan struct{}
Broadcast func(string, interface{})
WebhookURL string
encoder *encoder.FFmpegManager
isProcessing bool
mu sync.Mutex
}
func NewManager(ffmpegPath, tempDir string, broadcast func(string, interface{})) *Manager {
func NewManager(ffmpegPath, tempDir, webhookURL string, broadcast func(string, interface{})) *Manager {
return &Manager{
FFmpegPath: ffmpegPath,
TempDir: tempDir,
TriggerChan: make(chan struct{}, 1),
StopChan: make(chan struct{}),
Broadcast: broadcast,
WebhookURL: webhookURL,
encoder: encoder.NewManager(ffmpegPath),
}
}
+4
View File
@@ -13,6 +13,7 @@ import (
"goencode/internal/db"
"goencode/internal/encoder"
"goencode/internal/notify"
"io"
)
@@ -98,6 +99,9 @@ func (m *Manager) processNextJob() {
db.AddJobReport(job, "failed", 0, 0, 0)
db.DeleteJob(job.ID)
m.NotifySSE("job_failed", map[string]interface{}{"id": job.ID, "error": err.Error()})
if m.WebhookURL != "" {
notify.SendWebhook(m.WebhookURL, "Encoding Job Failed", fmt.Sprintf("File: %s\nError: %s", job.FilePath, err.Error()))
}
} else {
log.Printf("Job %d succeeded", job.ID)
db.DeleteJob(job.ID)