about summary refs log tree commit diff stats
path: root/internal/fetcher/http.go
diff options
context:
space:
mode:
authorAlan Pearce2024-05-16 23:41:57 +0200
committerAlan Pearce2024-05-16 23:41:57 +0200
commita5e758d41c151c17ed03b39454470ba8dd0c3b99 (patch)
tree386333b5020477eabcf490773113b029e47a21ef /internal/fetcher/http.go
parentd558039919b6198a246a6a3fd007276191cb4b2f (diff)
downloadsearchix-a5e758d41c151c17ed03b39454470ba8dd0c3b99.tar.lz
searchix-a5e758d41c151c17ed03b39454470ba8dd0c3b99.tar.zst
searchix-a5e758d41c151c17ed03b39454470ba8dd0c3b99.zip
refactor: separate fetch and import logic
Diffstat (limited to 'internal/fetcher/http.go')
-rw-r--r--internal/fetcher/http.go70
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/fetcher/http.go b/internal/fetcher/http.go
new file mode 100644
index 0000000..9afbbc0
--- /dev/null
+++ b/internal/fetcher/http.go
@@ -0,0 +1,70 @@
+package fetcher
+
+import (
+	"context"
+	"fmt"
+	"log/slog"
+	"net/http"
+	"os"
+	"searchix/internal/config"
+	"searchix/internal/file"
+	"strings"
+	"time"
+
+	"github.com/pkg/errors"
+)
+
+func fetchFileIfNeeded(ctx context.Context, path string, url string) (needed bool, err error) {
+	stat, err := file.StatIfExists(path)
+	if err != nil {
+		return false, errors.WithMessagef(err, "could not stat file %s", path)
+	}
+
+	var mtime string
+	if stat != nil {
+		mtime = strings.Replace(stat.ModTime().UTC().Format(time.RFC1123), "UTC", "GMT", 1)
+	}
+
+	req, err := http.NewRequestWithContext(ctx, "GET", url, http.NoBody)
+	if err != nil {
+		return false, errors.WithMessagef(err, "could not create HTTP request for %s", url)
+	}
+
+	req.Header.Set("User-Agent", fmt.Sprintf("Searchix %s", config.ShortSHA))
+
+	if mtime != "" {
+		req.Header.Set("If-Modified-Since", mtime)
+	}
+	res, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return false, errors.WithMessagef(err, "could not make HTTP request to %s", url)
+	}
+	defer res.Body.Close()
+
+	switch res.StatusCode {
+	case http.StatusNotModified:
+		needed = false
+	case http.StatusOK:
+		newMtime, err := time.Parse(time.RFC1123, res.Header.Get("Last-Modified"))
+		if err != nil {
+			slog.Warn(
+				"could not parse Last-Modified header from response",
+				"value",
+				res.Header.Get("Last-Modified"),
+			)
+		}
+		err = file.WriteToFile(path, res.Body)
+		if err != nil {
+			return false, errors.WithMessagef(err, "could not write response body to file %s", path)
+		}
+		err = os.Chtimes(path, time.Time{}, newMtime)
+		if err != nil {
+			slog.Warn("could not update mtime on file", "file", path)
+		}
+		needed = true
+	default:
+		return false, fmt.Errorf("got response code %d, don't know what to do", res.StatusCode)
+	}
+
+	return needed, nil
+}