refactor: merge CSV/JSON handler pairs into one handler per event type + serveCSVOrJSON helper

Co-authored-by: coolaj86 <122831+coolaj86@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-02 08:04:05 +00:00
parent 7465f584d9
commit 0b05b30129

View File

@ -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)
serveCSVOrJSON(w, r, rows)
}
// 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
}
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
}
}
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) {