From 280703edd8e27fdd971604a85a04a91938ba608c Mon Sep 17 00:00:00 2001 From: blank X Date: Tue, 10 Aug 2021 16:07:09 +0700 Subject: [PATCH] Store permanent errors --- main.go | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/main.go b/main.go index 8417416..bb26ebf 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "bufio" "errors" "context" + "strconv" "strings" "net/url" "crypto/x509" @@ -23,6 +24,7 @@ var ( hosts tofu.KnownHosts hostsfile *tofu.HostWriter predirs map[string]*url.URL + perrors map[string]PError ) func xdgDataHome() string { @@ -48,6 +50,11 @@ func init() { if err != nil { log.Fatal(err) } + + err = populatePErrors() + if err != nil { + log.Fatal(err) + } } func populatePRedirs() error { @@ -114,6 +121,80 @@ func savePRedirs() error { return writer.Flush() } +func populatePErrors() error { + file, err := os.OpenFile(filepath.Join(xdgDataHome(), "konbata", "perrors"), os.O_RDONLY|os.O_CREATE, 0600) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + perrors = make(map[string]PError) + unescaper := strings.NewReplacer("\\n", "\n", "\\\\", "\\") + for scanner.Scan() { + values := strings.SplitN(scanner.Text(), " ", 3) + if len(values) != 3 { + continue + } + url, err := url.Parse(values[0]) + if err != nil { + continue + } + if url.Scheme != "gemini" { + continue + } + code, err := strconv.Atoi(values[1]) + if err != nil { + continue + } + perrors[url.String()] = PError{ + code: gemini.Status(code), + message: unescaper.Replace(values[2]), + } + } + return nil +} + +func savePErrors() error { + file, err := os.OpenFile(filepath.Join(xdgDataHome(), "konbata", "perrors"), os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + return err + } + defer file.Close() + err = file.Truncate(0) + if err != nil { + return err + } + writer := bufio.NewWriter(file) + escaper := strings.NewReplacer("\\", "\\\\", "\n", "\\n") + for url, perror := range perrors { + _, err = writer.WriteString(url) + if err != nil { + return err + } + _, err = writer.WriteRune(' ') + if err != nil { + return err + } + _, err = writer.WriteString(strconv.Itoa(int(perror.code))) + if err != nil { + return err + } + _, err = writer.WriteRune(' ') + if err != nil { + return err + } + _, err = escaper.WriteString(writer, perror.message) + if err != nil { + return err + } + _, err = writer.WriteRune('\n') + if err != nil { + return err + } + } + return writer.Flush() +} + func trustCertificate(hostname string, cert *x509.Certificate) error { host := tofu.NewHost(hostname, cert.Raw) knownHost, ok := hosts.Lookup(hostname) @@ -141,6 +222,9 @@ func do(client gemini.Client, ctx context.Context, req *gemini.Request, via []*g redirect.URL = target return do(client, ctx, &redirect, via) } + if perror, exists := perrors[req.URL.String()]; exists { + return nil, req, errors.New(fmt.Sprintf("%d %s", perror.code, perror.message)) + } resp, err := client.Do(ctx, req) if err != nil { return resp, req, err @@ -161,6 +245,16 @@ func do(client gemini.Client, ctx context.Context, req *gemini.Request, via []*g return resp, req, err } } + if resp.Status.Class() == gemini.StatusPermanentFailure { + perrors[req.URL.String()] = PError{ + code: resp.Status, + message: resp.Meta, + } + err = savePErrors() + if err != nil { + return resp, req, err + } + } if resp.Status.Class() == gemini.StatusRedirect { via = append(via, req) if len(via) > 5 { @@ -304,6 +398,11 @@ func (a ByTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +type PError struct { + code gemini.Status + message string +} + type AtomWriter struct { Title string Items []FeedItem