code.pablomurad.com

indiedesk

Adds opted-in pages from personal sites to a topicless feed, served as Atom and JF2

Shorten the replies the relay sends.

author
Pablo Murad
date
commit
4507ba942068a27b7bd246f60be5f4163a848d5c
parent
9dcc92e05464c3314c946f610575c99f1625e18c
changes
6 files +26 −26
@@ -37,7 +37,7 @@ }() 	}
 	wg.Wait()
 	before := readJob(t, s, source)
-	if w := rootNotify(a, source, target); w.Code != 202 || !strings.Contains(w.Body.String(), "Existing processing continues") {
+	if w := rootNotify(a, source, target); w.Code != 202 || !strings.Contains(w.Body.String(), "already in the queue") {
 		t.Fatal(w.Code, w.Body.String())
 	}
 	if w := rootNotify(a, source, "https://other.example/"); w.Code != 400 {
@@ -22,10 +22,10 @@ } func (c Config) Validate() error {
 	u, e := url.Parse(c.PublicURL)
 	if e != nil || u == nil || (u.Scheme != "http" && u.Scheme != "https") || u.Hostname() == "" || u.User != nil || u.RawQuery != "" || u.ForceQuery || u.Fragment != "" || u.RawPath != "" || (u.Path != "" && u.Path != "/") {
-		return fmt.Errorf("PUBLIC_URL must be an HTTP(S) root URL without credentials, query, or fragment (a trailing / is optional)")
+		return fmt.Errorf("PUBLIC_URL has to be an http or https root, no user, query, or fragment. A trailing slash is fine.")
 	}
 	if c.DataDir == "" || c.Listen == "" || c.FetchTimeout <= 0 || c.MaxBody <= 0 || c.MaxForm <= 0 || c.Redirects <= 0 || c.Workers <= 0 || c.Queue <= 0 || c.FeedLimit <= 0 || c.Attempts <= 0 || c.Retention <= 0 {
-		return fmt.Errorf("a data directory and finite positive resource limits are required")
+		return fmt.Errorf("DATA_DIR is missing, or a limit is not positive")
 	}
 	return nil
 }
@@ -27,17 +27,17 @@ func sourceURL(raw string) (*url.URL, error) {
 	u, e := url.Parse(raw)
 	if e != nil || u == nil || (u.Scheme != "http" && u.Scheme != "https") || u.Hostname() == "" || u.User != nil {
-		return nil, fmt.Errorf("fetch URL has an invalid scheme, host, or credentials")
+		return nil, fmt.Errorf("bad fetch url")
 	}
 	if p := u.Port(); p != "" && p != "80" && p != "443" {
-		return nil, fmt.Errorf("port is not allowed")
+		return nil, fmt.Errorf("port not allowed")
 	}
 	return u, nil
 }
 func redirectCheck(max int) func(*http.Request, []*http.Request) error {
 	return func(r *http.Request, via []*http.Request) error {
 		if len(via) > max {
-			return fmt.Errorf("redirect limit")
+			return fmt.Errorf("too many redirects")
 		}
 		_, e := sourceURL(r.URL.String())
 		return e
@@ -45,7 +45,7 @@ } }
 func NewSafeFetcher(c Config) (*SafeFetcher, error) {
 	if c.FetchTimeout <= 0 || c.MaxBody <= 0 || c.Redirects <= 0 {
-		return nil, fmt.Errorf("fetch limits are invalid")
+		return nil, fmt.Errorf("bad fetch limits")
 	}
 	tr := &http.Transport{Proxy: nil, ForceAttemptHTTP2: true, ResponseHeaderTimeout: c.FetchTimeout, TLSHandshakeTimeout: c.FetchTimeout, IdleConnTimeout: 30 * time.Second, MaxIdleConns: 4, MaxIdleConnsPerHost: 2, MaxResponseHeaderBytes: 32 << 10}
 	cfg := safeurl.GetConfigBuilder().SetAllowedSchemes("http", "https").SetAllowedPorts(80, 443).EnableIPv6(true).SetTimeout(c.FetchTimeout).SetCheckRedirect(redirectCheck(c.Redirects)).SetTransport(tr).Build()
@@ -72,14 +72,14 @@ return p, nil 	}
 	media, _, err := mime.ParseMediaType(res.Header.Get("Content-Type"))
 	if err != nil || (media != "text/html" && media != "application/xhtml+xml") {
-		return Page{}, fmt.Errorf("source Content-Type must be HTML")
+		return Page{}, fmt.Errorf("not html")
 	}
 	body, e := io.ReadAll(io.LimitReader(res.Body, f.limit+1))
 	if e != nil {
 		return Page{}, e
 	}
 	if int64(len(body)) > f.limit {
-		return Page{}, fmt.Errorf("decoded body exceeds the size limit")
+		return Page{}, fmt.Errorf("body too big")
 	}
 	p.Body = body
 	return p, nil
@@ -21,7 +21,7 @@ func landingDocument(publicURL string) ([]byte, error) {
 	base, e := url.Parse(publicURL)
 	if e != nil || base.Scheme == "" || base.Host == "" {
-		return nil, fmt.Errorf("cannot use public URL as base: %q", publicURL)
+		return nil, fmt.Errorf("bad public url %q", publicURL)
 	}
 	entry, e := renderEntry(landingMarkdown, base)
 	if e != nil {
@@ -42,7 +42,7 @@ return nil, e 	}
 	name, rest := splitEntry(doc)
 	if name == nil {
-		return nil, fmt.Errorf("missing primary heading")
+		return nil, fmt.Errorf("landing has no h1")
 	}
 	name.SetAttributeString("class", "p-name")
 	var buf bytes.Buffer
@@ -12,7 +12,7 @@ "strings" 	"willnorris.com/go/microformats"
 )
 
-var ErrIneligible = errors.New("post is ineligible")
+var ErrIneligible = errors.New("not a post")
 var urnPattern = regexp.MustCompile(`^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`)
 
 func Collection(raw string) (string, error) {
@@ -30,7 +30,7 @@ if e := c.Validate(); e != nil { 		return nil, e
 	}
 	if s == nil || f == nil {
-		return nil, fmt.Errorf("processing dependencies are required")
+		return nil, fmt.Errorf("need a store and a fetcher")
 	}
 	landing, e := landingDocument(c.PublicURL)
 	if e != nil {
@@ -98,7 +98,7 @@ return 					}
 					if e = a.Store.Finish(ctx, j, e, a.Config.Attempts, time.Now()); e != nil {
 						a.unhealthy.Store(true)
-						log.Print("failed to store mention processing state")
+						log.Print("could not save the job")
 					}
 				}
 			}
@@ -134,16 +134,16 @@ }) 	m.HandleFunc("POST /webmention", func(w http.ResponseWriter, r *http.Request) {
 		media, _, e := mime.ParseMediaType(r.Header.Get("Content-Type"))
 		if e != nil || media != "application/x-www-form-urlencoded" {
-			http.Error(w, "form content type is required", 400)
+			http.Error(w, "need a urlencoded form", 400)
 			return
 		}
 		r.Body = http.MaxBytesReader(w, r.Body, a.Config.MaxForm)
 		if e = r.ParseForm(); e != nil {
-			http.Error(w, "form is invalid or exceeds the size limit", 400)
+			http.Error(w, "bad form", 400)
 			return
 		}
 		if len(r.PostForm["source"]) != 1 || len(r.PostForm["target"]) != 1 {
-			http.Error(w, "source and target are each required once", 400)
+			http.Error(w, "source and target, once each", 400)
 			return
 		}
 		source, target := r.PostForm.Get("source"), r.PostForm.Get("target")
@@ -151,7 +151,7 @@ u, sourceErr := sourceURL(source) 		t, targetErr := url.Parse(target)
 		public, _ := url.Parse(a.Config.PublicURL)
 		if sourceErr != nil || targetErr != nil || rootURLString(t) != rootURLString(public) {
-			http.Error(w, "source or target is invalid", 400)
+			http.Error(w, "bad source or target", 400)
 			return
 		}
 		u.Fragment = ""
@@ -163,13 +163,13 @@ } 		e = a.Store.Enqueue(r.Context(), source, rootURLString(t), a.Config.Queue, time.Now())
 		if errors.Is(e, ErrStored) {
 			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
-			fmt.Fprintln(w, "Kept the stored snapshot. The relay does not refetch or change it.")
+			fmt.Fprintln(w, "already stored")
 			return
 		}
 		if errors.Is(e, ErrOutstanding) {
 			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 			w.WriteHeader(202)
-			fmt.Fprintln(w, "The mention is already durably accepted. Existing processing continues. Publication follows source verification.")
+			fmt.Fprintln(w, "already in the queue")
 			return
 		}
 		if errors.Is(e, ErrFull) {
@@ -177,12 +177,12 @@ http.Error(w, "mention queue is full", 503) 			return
 		}
 		if e != nil {
-			http.Error(w, "durable acceptance failed", 503)
+			http.Error(w, "could not save the mention", 503)
 			return
 		}
 		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 		w.WriteHeader(202)
-		fmt.Fprintln(w, "Durably accepted the mention. Publication follows source verification.")
+		fmt.Fprintln(w, "accepted")
 	})
 	m.HandleFunc("GET /collections/{name}", func(w http.ResponseWriter, r *http.Request) {
 		w.Header().Set("Access-Control-Allow-Origin", "*")
@@ -209,13 +209,13 @@ http.NotFound(w, r) 			return
 		}
 		if e != nil {
-			http.Error(w, "failed to read stored data", 503)
+			http.Error(w, "could not read the feed", 503)
 			return
 		}
 		if suffix == ".jf2" {
 			b, e := JF2(a.Config.PublicURL, id, posts, a.Config.FeedLimit)
 			if e != nil {
-				http.Error(w, "failed to build JF2", 500)
+				http.Error(w, "could not build the jf2", 500)
 				return
 			}
 			w.Header().Set("Content-Type", "application/jf2feed+json")
@@ -224,7 +224,7 @@ return 		}
 		b, e := Atom(a.Config.PublicURL, id, updated, posts, a.Config.FeedLimit)
 		if e != nil {
-			http.Error(w, "failed to build Atom", 500)
+			http.Error(w, "could not build the atom", 500)
 			return
 		}
 		w.Header().Set("Content-Type", "application/atom+xml; charset=utf-8")
@@ -234,7 +234,7 @@ m.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) { 		ctx, cancel := context.WithTimeout(r.Context(), time.Second)
 		defer cancel()
 		if a.active.Load() != int32(a.Config.Workers) || a.unhealthy.Load() || a.Store.Health(ctx) != nil {
-			http.Error(w, "worker or storage is unavailable", 503)
+			http.Error(w, "not healthy", 503)
 			return
 		}
 		fmt.Fprintln(w, "ok")