package notify import ( "bytes" "encoding/json" "fmt" "net/http" "net/smtp" "text/template" "time" "godump/config" "godump/logger" ) type DBResult struct { Name string `json:"name"` Size int64 `json:"size"` Result string `json:"result"` } type Payload struct { InstanceName string `json:"instance_name"` OverallResult string `json:"overall_result"` Time time.Time `json:"time"` Databases []DBResult `json:"databases"` } func shouldSend(global config.NotificationEventsConfig, local *config.NotificationEventsConfig, result string) bool { events := global if local != nil { events = *local } if result == "success" && !events.OnSuccess { return false } if (result == "failed" || result == "partial") && !events.OnFailure { return false } return true } func Send(cfg config.NotificationsConfig, payload Payload) { if cfg.Webhook.Enabled && shouldSend(cfg.Events, cfg.Webhook.Events, payload.OverallResult) { go sendWebhook(cfg.Webhook, payload) } for _, w := range cfg.Webhooks { if w.Enabled && shouldSend(cfg.Events, w.Events, payload.OverallResult) { go sendWebhook(w, payload) } } if cfg.Email.Enabled && shouldSend(cfg.Events, cfg.Email.Events, payload.OverallResult) { go sendEmail(cfg.Email, payload) } } func sendWebhook(cfg config.WebhookConfig, payload Payload) { message := fmt.Sprintf("**GoDump Backup Result**\nInstance: %s\nResult: %s\nTime: %s\n\nDatabases:\n", payload.InstanceName, payload.OverallResult, payload.Time.Format("2006-01-02 15:04:05")) for _, db := range payload.Databases { message += fmt.Sprintf("- %s: %s (%s)\n", db.Name, db.Result, formatBytes(db.Size)) } webhookPayload := map[string]interface{}{ "content": message, "text": message, "title": fmt.Sprintf("GoDump Backup Result: %s", payload.InstanceName), "message": message, } data, err := json.Marshal(webhookPayload) if err != nil { logger.Error(payload.InstanceName, "Failed to marshal webhook payload: %v", err) return } req, err := http.NewRequest("POST", cfg.URL, bytes.NewBuffer(data)) if err != nil { logger.Error(payload.InstanceName, "Failed to create webhook request: %v", err) return } req.Header.Set("Content-Type", "application/json") for k, v := range cfg.Headers { req.Header.Set(k, v) } client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { logger.Error(payload.InstanceName, "Failed to send webhook: %v", err) return } defer resp.Body.Close() if resp.StatusCode >= 400 { logger.Error(payload.InstanceName, "Webhook returned error status: %d", resp.StatusCode) } else { logger.Info(payload.InstanceName, "Webhook notification sent successfully") } } func formatBytes(b int64) string { const unit = 1024 if b < unit { return fmt.Sprintf("%d B", b) } div, exp := int64(unit), 0 for n := b / unit; n >= unit; n /= unit { div *= unit exp++ } return fmt.Sprintf("%.1f %ciB", float64(b)/float64(div), "KMGTPE"[exp]) } const emailTmplStr = `
Overall Result: {{.OverallResult}}
Time: {{.Time.Format "2006-01-02 15:04:05"}}
| Database | Size | Result |
|---|---|---|
| {{.Name}} | {{formatBytes .Size}} | {{.Result}} |