xt/http.go
2025-02-24 17:28:09 -07:00

95 lines
2.0 KiB
Go

package main
import (
"errors"
"fmt"
"net/http"
"slices"
"sort"
"strings"
"time"
"go.sour.is/xt/internal/otel"
)
func httpServer(c *console, app *appState) error {
otel.Info("start http server")
db, err := app.DB()
if err != nil {
otel.Info("missing db", err)
return err
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write([]byte("ok"))
})
http.HandleFunc("/conv/{hash}", func(w http.ResponseWriter, r *http.Request) {
hash := r.PathValue("hash")
if (len(hash) < 6 || len(hash) > 8) && !notAny(hash, "abcdefghijklmnopqrstuvwxyz234567") {
w.WriteHeader(http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write([]byte(hash))
rows, err := db.QueryContext(r.Context(), "SELECT feed_id, hash, conv, dt, text FROM twt WHERE hash = $1 or conv = $1", hash)
if err != nil {
otel.Info("error", err)
return
}
defer rows.Close()
for rows.Next() {
var twt struct {
FeedID string
Hash string
Conv string
Dt time.Time
Text string
}
err = rows.Scan(&twt.FeedID, &twt.Hash, &twt.Conv, &twt.Dt, &twt.Text)
if err != nil {
otel.Error(err)
return
}
}
})
http.HandleFunc("/feeds", func(w http.ResponseWriter, r *http.Request) {
lis := slices.Collect(app.queue.Iter())
sort.Slice(lis, func(i, j int) bool {
return lis[i].LastScanOn.Time.Before(lis[j].LastScanOn.Time)
})
for _, feed := range lis {
fmt.Fprintln(w, feed.State, feed.LastScanOn.Time.Format(time.RFC3339), feed.Nick, feed.URI)
}
})
srv := &http.Server{
Addr: app.args.Listen,
Handler: http.DefaultServeMux,
}
c.AddCancel(srv.Shutdown)
err = srv.ListenAndServe()
if !errors.Is(err, http.ErrServerClosed) {
otel.Error(err)
return err
}
return nil
}
func notAny(s string, chars string) bool {
for _, c := range s {
if !strings.ContainsRune(chars, c) {
return false
}
}
return true
}