From 0b05b30129e6918a276929a1536df323efaf90e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 08:04:05 +0000 Subject: [PATCH] refactor: merge CSV/JSON handler pairs into one handler per event type + serveCSVOrJSON helper Co-authored-by: coolaj86 <122831+coolaj86@users.noreply.github.com> --- cmd/smsapid/main.go | 124 ++++++++------------------------------------ 1 file changed, 23 insertions(+), 101 deletions(-) diff --git a/cmd/smsapid/main.go b/cmd/smsapid/main.go index 372b240..7f7d3d6 100644 --- a/cmd/smsapid/main.go +++ b/cmd/smsapid/main.go @@ -118,12 +118,12 @@ func main() { // Protected routes under /api/smsgw, each guarded by its specific sms:* permission. smsgw := mwpkg.WithMux(mux) - smsgw.With(requireSMSPermission("sms:received")).HandleFunc("GET /api/smsgw/received.csv", handlerReceivedCSV) - smsgw.With(requireSMSPermission("sms:received")).HandleFunc("GET /api/smsgw/received.json", handlerReceivedJSON) - smsgw.With(requireSMSPermission("sms:sent")).HandleFunc("GET /api/smsgw/sent.csv", handlerSentCSV) - smsgw.With(requireSMSPermission("sms:sent")).HandleFunc("GET /api/smsgw/sent.json", handlerSentJSON) - smsgw.With(requireSMSPermission("sms:ping")).HandleFunc("GET /api/smsgw/ping.csv", handlerPingCSV) - smsgw.With(requireSMSPermission("sms:ping")).HandleFunc("GET /api/smsgw/ping.json", handlerPingJSON) + smsgw.With(requireSMSPermission("sms:received")).HandleFunc("GET /api/smsgw/received.csv", handlerReceived) + smsgw.With(requireSMSPermission("sms:received")).HandleFunc("GET /api/smsgw/received.json", handlerReceived) + smsgw.With(requireSMSPermission("sms:sent")).HandleFunc("GET /api/smsgw/sent.csv", handlerSent) + smsgw.With(requireSMSPermission("sms:sent")).HandleFunc("GET /api/smsgw/sent.json", handlerSent) + smsgw.With(requireSMSPermission("sms:ping")).HandleFunc("GET /api/smsgw/ping.csv", handlerPing) + smsgw.With(requireSMSPermission("sms:ping")).HandleFunc("GET /api/smsgw/ping.json", handlerPing) addr := "localhost:8088" fmt.Printf("Listening on %s...\n\n", addr) @@ -196,7 +196,7 @@ func parseSinceLimit(r *http.Request) (time.Time, int) { return since, limit } -func handlerReceivedCSV(w http.ResponseWriter, r *http.Request) { +func handlerReceived(w http.ResponseWriter, r *http.Request) { since, limit := parseSinceLimit(r) webhookMux.Lock() @@ -216,42 +216,10 @@ func handlerReceivedCSV(w http.ResponseWriter, r *http.Request) { } webhookMux.Unlock() - b, err := csvutil.Marshal(rows) - if err != nil { - http.Error(w, `{"error":"failed to encode CSV"}`, http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", "text/csv; charset=utf-8") - _, _ = w.Write(b) + serveCSVOrJSON(w, r, rows) } -func handlerReceivedJSON(w http.ResponseWriter, r *http.Request) { - since, limit := parseSinceLimit(r) - - webhookMux.Lock() - rows := make([]*androidsmsgateway.WebhookReceived, 0, min(len(webhookEvents), limit)) - for _, event := range webhookEvents { - recv, ok := event.(*androidsmsgateway.WebhookReceived) - if !ok { - continue - } - if !since.IsZero() && !recv.Payload.ReceivedAt.After(since) { - continue - } - rows = append(rows, recv) - if len(rows) >= limit { - break - } - } - webhookMux.Unlock() - - w.Header().Set("Content-Type", "application/json") - enc := json.NewEncoder(w) - enc.SetEscapeHTML(false) - _ = enc.Encode(rows) -} - -func handlerSentCSV(w http.ResponseWriter, r *http.Request) { +func handlerSent(w http.ResponseWriter, r *http.Request) { since, limit := parseSinceLimit(r) webhookMux.Lock() @@ -271,42 +239,10 @@ func handlerSentCSV(w http.ResponseWriter, r *http.Request) { } webhookMux.Unlock() - b, err := csvutil.Marshal(rows) - if err != nil { - http.Error(w, `{"error":"failed to encode CSV"}`, http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", "text/csv; charset=utf-8") - _, _ = w.Write(b) + serveCSVOrJSON(w, r, rows) } -func handlerSentJSON(w http.ResponseWriter, r *http.Request) { - since, limit := parseSinceLimit(r) - - webhookMux.Lock() - rows := make([]*androidsmsgateway.WebhookSent, 0, min(len(webhookEvents), limit)) - for _, event := range webhookEvents { - sent, ok := event.(*androidsmsgateway.WebhookSent) - if !ok { - continue - } - if !since.IsZero() && !sent.Payload.SentAt.After(since) { - continue - } - rows = append(rows, sent) - if len(rows) >= limit { - break - } - } - webhookMux.Unlock() - - w.Header().Set("Content-Type", "application/json") - enc := json.NewEncoder(w) - enc.SetEscapeHTML(false) - _ = enc.Encode(rows) -} - -func handlerPingCSV(w http.ResponseWriter, r *http.Request) { +func handlerPing(w http.ResponseWriter, r *http.Request) { since, limit := parseSinceLimit(r) webhookMux.Lock() @@ -326,39 +262,25 @@ func handlerPingCSV(w http.ResponseWriter, r *http.Request) { } webhookMux.Unlock() - b, err := csvutil.Marshal(rows) - if err != nil { - http.Error(w, `{"error":"failed to encode CSV"}`, http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", "text/csv; charset=utf-8") - _, _ = w.Write(b) + serveCSVOrJSON(w, r, rows) } -func handlerPingJSON(w http.ResponseWriter, r *http.Request) { - since, limit := parseSinceLimit(r) - - webhookMux.Lock() - rows := make([]*androidsmsgateway.WebhookPing, 0, min(len(pingEvents), limit)) - for _, ping := range pingEvents { - pingedAt := ping.PingedAt - if pingedAt.IsZero() { - pingedAt = time.UnixMilli(ping.XTimestamp).UTC() - } - if !since.IsZero() && !pingedAt.After(since) { - continue - } - rows = append(rows, ping) - if len(rows) >= limit { - break +// serveCSVOrJSON writes v as CSV when the request path ends with ".csv", otherwise as JSON. +func serveCSVOrJSON[T any](w http.ResponseWriter, r *http.Request, v []T) { + if strings.HasSuffix(r.URL.Path, ".csv") { + b, err := csvutil.Marshal(v) + if err != nil { + http.Error(w, `{"error":"failed to encode CSV"}`, http.StatusInternalServerError) + return } + w.Header().Set("Content-Type", "text/csv; charset=utf-8") + _, _ = w.Write(b) + return } - webhookMux.Unlock() - w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) enc.SetEscapeHTML(false) - _ = enc.Encode(rows) + _ = enc.Encode(v) } func HandleOK(w http.ResponseWriter, r *http.Request) {