mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-12 03:14:09 +00:00
feat: support webhook (#1187)
This commit is contained in:
1 parent
5bb8541385
commit
9d9f1caaaa
15 files changed
+1361
-33
No files matched your search
@@ -389,3 +389,14 @@ func getServerConfig() *base.DownloaderStoreConfig {
|
||||
cfg, _ := Downloader.GetConfig()
|
||||
return cfg
|
||||
}
|
||||
|
||||
func TestWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
var req model.TestWebhookReq
|
||||
if ReadJson(r, w, &req) {
|
||||
if err := Downloader.TestWebhookUrl(req.URL); err != nil {
|
||||
WriteJson(w, model.NewErrorResult(err.Error()))
|
||||
return
|
||||
}
|
||||
WriteJson(w, model.NewNilResult())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
// TestWebhookReq is the request body for testing a single webhook URL
|
||||
type TestWebhookReq struct {
|
||||
URL string `json:"url"`
|
||||
}
|
||||
@@ -141,6 +141,7 @@ func BuildServer(startCfg *model.StartConfig) (*http.Server, net.Listener, error
|
||||
r.Methods(http.MethodDelete).Path("/api/v1/extensions/{identity}").HandlerFunc(DeleteExtension)
|
||||
r.Methods(http.MethodGet).Path("/api/v1/extensions/{identity}/update").HandlerFunc(UpdateCheckExtension)
|
||||
r.Methods(http.MethodPost).Path("/api/v1/extensions/{identity}/update").HandlerFunc(UpdateExtension)
|
||||
r.Methods(http.MethodPost).Path("/api/v1/webhook/test").HandlerFunc(TestWebhook)
|
||||
r.Path("/api/v1/proxy").HandlerFunc(DoProxy)
|
||||
|
||||
enableApiToken := startCfg.ApiToken != ""
|
||||
|
||||
+115
-4
@@ -6,10 +6,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/GopeedLab/gopeed/internal/test"
|
||||
"github.com/GopeedLab/gopeed/pkg/base"
|
||||
"github.com/GopeedLab/gopeed/pkg/download"
|
||||
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -20,6 +16,11 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/GopeedLab/gopeed/internal/test"
|
||||
"github.com/GopeedLab/gopeed/pkg/base"
|
||||
"github.com/GopeedLab/gopeed/pkg/download"
|
||||
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -606,6 +607,116 @@ func TestDoProxy(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestTestWebhook(t *testing.T) {
|
||||
doTest(func() {
|
||||
// Set up a mock webhook server
|
||||
webhookReceived := false
|
||||
var receivedData map[string]interface{}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
webhookServer := http.Server{
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &receivedData); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Check Content-Type
|
||||
if r.Header.Get("Content-Type") != "application/json" {
|
||||
t.Errorf("TestWebhook() Content-Type got = %v, want %v", r.Header.Get("Content-Type"), "application/json")
|
||||
}
|
||||
|
||||
webhookReceived = true
|
||||
w.WriteHeader(http.StatusOK)
|
||||
wg.Done()
|
||||
}),
|
||||
}
|
||||
|
||||
// Start webhook server
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
webhookPort := listener.Addr().(*net.TCPAddr).Port
|
||||
webhookURL := fmt.Sprintf("http://127.0.0.1:%d/webhook", webhookPort)
|
||||
|
||||
go webhookServer.Serve(listener)
|
||||
defer webhookServer.Close()
|
||||
|
||||
// Test with valid webhook URL
|
||||
httpRequestCheckOk[any](http.MethodPost, "/api/v1/webhook/test", &model.TestWebhookReq{
|
||||
URL: webhookURL,
|
||||
})
|
||||
|
||||
// Wait for webhook to be received
|
||||
wg.Wait()
|
||||
|
||||
if !webhookReceived {
|
||||
t.Error("TestWebhook() webhook was not received")
|
||||
}
|
||||
|
||||
// Verify webhook data structure
|
||||
if receivedData["event"] == nil {
|
||||
t.Error("TestWebhook() missing 'event' field")
|
||||
}
|
||||
if receivedData["time"] == nil {
|
||||
t.Error("TestWebhook() missing 'time' field")
|
||||
}
|
||||
if receivedData["payload"] == nil {
|
||||
t.Error("TestWebhook() missing 'payload' field")
|
||||
}
|
||||
|
||||
// Test with invalid webhook URL
|
||||
code, _ := httpRequest[any](http.MethodPost, "/api/v1/webhook/test", &model.TestWebhookReq{
|
||||
URL: "http://invalid-webhook-url-that-does-not-exist.local:99999/webhook",
|
||||
})
|
||||
checkCode(code, model.CodeError)
|
||||
|
||||
// Test with empty URL
|
||||
code, _ = httpRequest[any](http.MethodPost, "/api/v1/webhook/test", &model.TestWebhookReq{
|
||||
URL: "",
|
||||
})
|
||||
checkCode(code, model.CodeError)
|
||||
|
||||
// Test with webhook server returning non-200 status
|
||||
wg.Add(1)
|
||||
badWebhookServer := http.Server{
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
wg.Done()
|
||||
}),
|
||||
}
|
||||
badListener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
badWebhookPort := badListener.Addr().(*net.TCPAddr).Port
|
||||
badWebhookURL := fmt.Sprintf("http://127.0.0.1:%d/webhook", badWebhookPort)
|
||||
|
||||
go badWebhookServer.Serve(badListener)
|
||||
defer badWebhookServer.Close()
|
||||
|
||||
code, _ = httpRequest[any](http.MethodPost, "/api/v1/webhook/test", &model.TestWebhookReq{
|
||||
URL: badWebhookURL,
|
||||
})
|
||||
checkCode(code, model.CodeError)
|
||||
|
||||
wg.Wait()
|
||||
})
|
||||
}
|
||||
|
||||
func TestApiToken(t *testing.T) {
|
||||
var cfg = &model.StartConfig{}
|
||||
cfg.Init()
|
||||
|
||||
Reference in new issue
Block a user