package main import ( "fmt" "io" "net/http" "net/url" "strconv" "strings" "time" "go.sour.is/xt/internal/otel" "go.yarn.social/lextwt" "go.yarn.social/types" ) type HTML struct { app *appState db db hostname string } func (a *HTML) healthcheck(w http.ResponseWriter, r *http.Request) { _, span := otel.Span(r.Context()) defer span.End() w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Write([]byte("ok")) } func (a *HTML) home(w http.ResponseWriter, r *http.Request) { ctx, span := otel.Span(r.Context()) defer span.End() w.Header().Set("Content-Type", "text/html; charset=utf-8") uri := r.URL.Query().Get("uri") limit := 100 if v, ok := strconv.Atoi(r.URL.Query().Get("limit")); ok == nil { limit = v } limit = min(100, max(1, limit)) var offset int64 = 0 if v, ok := strconv.ParseInt(r.URL.Query().Get("offset"), 10, 64); ok == nil { offset = v } twts, offset, end, err := fetchTwts(ctx, a.db, uri, limit, offset) span.RecordError(err) if err != nil { http.Error(w, "ERR", 500) return } preamble := mkPreamble(a.hostname, uri, "", limit, int64(len(twts)), offset, end) reg := &HTWriter{ lextwt.NewTwtRegistry(preamble, reverse(twts)), } reg.WriteTo(w) } func (a *HTML) conv(w http.ResponseWriter, r *http.Request) { ctx, span := otel.Span(r.Context()) defer span.End() w.Header().Set("Content-Type", "text/html; charset=utf-8") hash := r.PathValue("hash") // if (len(hash) < 6 || len(hash) > 8) && !notAny(hash, "abcdefghijklmnopqrstuvwxyz234567") { // w.WriteHeader(http.StatusBadRequest) // return // } limit := 100 if v, ok := strconv.Atoi(r.URL.Query().Get("limit")); ok == nil { limit = v } var offset int64 = 0 if v, ok := strconv.ParseInt(r.URL.Query().Get("offset"), 10, 64); ok == nil { offset = v } twts, offset, end, err := fetchConv(ctx, a.db, hash, limit, offset) span.RecordError(err) if err != nil { http.Error(w, "ERR", 500) return } preamble := mkPreamble(a.hostname, "", "/conv/"+hash, limit, int64(len(twts)), offset, end) reg := &HTWriter{ lextwt.NewTwtRegistry(preamble, twts), } reg.WriteTo(w) } type reg interface { Preamble() lextwt.Comments Twts() types.Twts } type HTWriter struct { reg } func (r *HTWriter) WriteTo(w io.Writer) (int64, error) { var output int64 i, err := fmt.Fprintln(w, ` The Watcher
	`)
	output += int64(i)
	if err != nil {
		return output, err
	}

	for _, c := range r.Preamble() {
		if key := c.Key(); key != "" {
			value := mkValue(c.Value())
			i, err = fmt.Fprintf(w, "# %s = %s\n", key, value)
		} else {
			i, err = fmt.Fprintln(w, c.Text())
		}

		output += int64(i)
		if err != nil {
			return output, err
		}
	}

	i, err = fmt.Fprintln(w, "
") output += int64(i) for _, twt := range r.Twts() { twter := twt.Twter() uri, err := url.Parse(twter.URI) if err != nil { uri = &url.URL{ Scheme: "HTTPS", Host: "unknown.txt", } } subject := "" if s := twt.Subject(); s != nil { if tag, ok := s.Tag().(*lextwt.Tag); ok { subject = tag.Text() } } i, err = fmt.Fprintf(w, `
%-h
`, "/?uri="+twter.URI, twter.Avatar, "/?uri="+twter.URI, twter.Nick, twter.URI, uri.Host, "/conv/"+subject, fmt.Sprintf("", twt.Created().Format(time.RFC3339), twt.Created().Format(time.RFC822)), "/conv/"+subject, twt, ) output += int64(i) if err != nil { return output, err } } i, err = fmt.Fprintln(w, `
`) output += int64(i) return output, err } func mkValue(v string) string { if strings.HasPrefix(v, "http") { return fmt.Sprintf(`%s`, v, v) } return v } func reverse[T any](s []T) []T { for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { s[i], s[j] = s[j], s[i] } return s }