From efb75f74cb75b5129e66cf0dad975a1de3d3d487 Mon Sep 17 00:00:00 2001 From: Bel LaPointe <153096461+breel-render@users.noreply.github.com> Date: Mon, 28 Apr 2025 21:36:24 -0600 Subject: [PATCH] test /v1/vpntor calls vpntor nicely --- src/cmd/server/handler.go | 70 ++++++++++++++++++++++++++++++- src/cmd/server/handler_test.go | 77 ++++++++++++++++++++++++++++++++++ src/cmd/server/main.go | 2 +- 3 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/cmd/server/handler_test.go diff --git a/src/cmd/server/handler.go b/src/cmd/server/handler.go index c441b52..dc5e7a2 100644 --- a/src/cmd/server/handler.go +++ b/src/cmd/server/handler.go @@ -1,15 +1,24 @@ package server import ( + "bytes" "context" + "encoding/json" + "fmt" "io" + "io/ioutil" "net/http" + "time" ) type Handler struct { ctx context.Context } +func NewHandler(ctx context.Context) Handler { + return Handler{ctx: ctx} +} + func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err := h.serveHTTP(w, r); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -17,5 +26,64 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } func (h Handler) serveHTTP(w http.ResponseWriter, r *http.Request) error { - return io.EOF + switch r.URL.Path { + case "/v1/vpntor": + return h.vpntor(r.Context(), r.Body) + default: + http.NotFound(w, r) + } + return nil +} + +func (h Handler) vpntor(ctx context.Context, r io.Reader) error { + var form struct { + Magnet string + Dir string + URL string + } + if err := json.NewDecoder(r).Decode(&form); err != nil { + return err + } + if form.Magnet == "" || form.Dir == "" || form.URL == "" { + return fmt.Errorf("did not specify all of .Magnet, .Dir, .URL") + } + + c := http.Client{ + Timeout: time.Minute, + Transport: &http.Transport{DisableKeepAlives: true}, + } + sresp, err := c.Get(form.URL) + if err != nil { + return err + } + defer sresp.Body.Close() + defer io.Copy(io.Discard, sresp.Body) + + b, _ := json.Marshal(map[string]any{ + "method": "torrent-add", + "arguments": map[string]string{ + "filename": form.Magnet, + "download-dir": form.Dir, + }, + }) + + req, err := http.NewRequest(http.MethodPost, form.URL, bytes.NewReader(b)) + if err != nil { + return err + } + req = req.WithContext(ctx) + req.Header.Add("X-Transmission-Session-Id", sresp.Header.Get("X-Transmission-Session-Id")) + + resp, err := c.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + defer io.Copy(io.Discard, resp.Body) + + if b, _ := ioutil.ReadAll(resp.Body); resp.StatusCode > 220 || !bytes.Contains(b, []byte(`success`)) { + return fmt.Errorf("(%d) %s", resp.StatusCode, b) + } + + return nil } diff --git a/src/cmd/server/handler_test.go b/src/cmd/server/handler_test.go new file mode 100644 index 0000000..434a672 --- /dev/null +++ b/src/cmd/server/handler_test.go @@ -0,0 +1,77 @@ +package server_test + +import ( + "context" + "fmt" + "io" + "net/http" + "net/http/httptest" + "show-rss/src/cmd/server" + "show-rss/src/db" + "strings" + "testing" +) + +func TestHandler(t *testing.T) { + h := server.NewHandler(db.Test(t, context.Background())) + + t.Run("404", func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, "/not-found", nil) + h.ServeHTTP(w, r) + if w.Code != http.StatusNotFound { + t.Errorf("%+v", w) + } + }) + + t.Run("vpntor", func(t *testing.T) { + t.Run("no body", func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, "/v1/vpntor", nil) + h.ServeHTTP(w, r) + if w.Code != http.StatusInternalServerError { + t.Errorf("%+v", w) + } + }) + + t.Run("bad body", func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodPost, "/v1/vpntor", strings.NewReader(`{}`)) + h.ServeHTTP(w, r) + t.Logf("%s", w.Body.Bytes()) + if w.Code != http.StatusInternalServerError { + t.Errorf("%+v", w.Code) + } + if !strings.Contains(string(w.Body.Bytes()), `.Magnet, .Dir, .URL`) { + t.Errorf("%+v", string(w.Body.Bytes())) + } + }) + + t.Run("doit", func(t *testing.T) { + calls := 0 + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + b, _ := io.ReadAll(r.Body) + t.Logf("%s | %s", r.Header.Get("X-Transmission-Session-Id"), b) + calls += 1 + w.Header().Set("X-Transmission-Session-Id", "session") + w.Write([]byte(`success`)) + })) + defer s.Close() + + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodPost, "/v1/vpntor", strings.NewReader(fmt.Sprintf(`{ + "Magnet": %q, + "Dir": %q, + "URL": %q + }`, "magnet", "dir", s.URL))) + h.ServeHTTP(w, r) + if w.Code != http.StatusOK { + t.Errorf("%+v", w.Code) + } + + if calls != 2 { + t.Errorf("expected 2 but got %d calls", calls) + } + }) + }) +} diff --git a/src/cmd/server/main.go b/src/cmd/server/main.go index 3f5c1bf..bb295e8 100644 --- a/src/cmd/server/main.go +++ b/src/cmd/server/main.go @@ -24,7 +24,7 @@ func Run(ctx context.Context, listen string) error { s := http.Server{ Addr: listen, - Handler: Handler{ctx: ctx}, + Handler: NewHandler(ctx), BaseContext: func(net.Listener) context.Context { return ctx }, } defer s.Close()