package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
)
var webhookSecret = os.Getenv("D3_WEBHOOK_SECRET")
func main() {
http.HandleFunc("/webhooks/d3", handleWebhook)
log.Println("Webhook server listening on :3000")
log.Fatal(http.ListenAndServe(":3000", nil))
}
func handleWebhook(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Bad request", http.StatusBadRequest)
return
}
defer r.Body.Close()
signature := r.Header.Get("X-Webhook-Signature")
if !verifySignature(body, signature, webhookSecret) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
var event map[string]interface{}
if err := json.Unmarshal(body, &event); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
eventType, _ := event["type"].(string)
switch eventType {
case "operation.completed":
handleOperationCompleted(event["payload"])
case "operation.failed":
handleOperationFailed(event["payload"])
case "fileTask.completed":
handleFileTaskCompleted(event["data"])
case "fileTask.failed":
handleFileTaskFailed(event["data"])
default:
log.Printf("Unhandled event type: %s\n", eventType)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]bool{"received": true})
}
func verifySignature(body []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(signature))
}
func handleOperationCompleted(payload interface{}) {
p, _ := payload.(map[string]interface{})
task, _ := p["main_task"].(map[string]interface{})
fmt.Printf("Operation %s completed\n", task["id"])
}
func handleOperationFailed(payload interface{}) {
p, _ := payload.(map[string]interface{})
task, _ := p["main_task"].(map[string]interface{})
fmt.Printf("Operation %s failed\n", task["id"])
}
func handleFileTaskCompleted(data interface{}) {
d, _ := data.(map[string]interface{})
fmt.Printf("File %s completed\n", d["file_key"])
}
func handleFileTaskFailed(data interface{}) {
d, _ := data.(map[string]interface{})
fmt.Printf("File %s failed: %s\n", d["file_key"], d["error"])
}