Commit Diff


commit - /dev/null
commit + 1a048c00522449ec807fb494150b25fdde344ce1
blob - /dev/null
blob + 452b7480f2db1d6947eb2e0db79994890b98cec0 (mode 644)
--- /dev/null
+++ go.mod
@@ -0,0 +1,3 @@
+module olowe.co/tarweb
+
+go 1.18
blob - /dev/null
blob + 9cd5671a333ef9e7f03e7f87bf3ed793b8f44d6e (mode 644)
--- /dev/null
+++ tarweb.go
@@ -0,0 +1,107 @@
+package main
+
+import (
+	"archive/tar"
+	"errors"
+	"fmt"
+	"io"
+	"io/fs"
+	"log"
+	"net/http"
+	"os"
+	"path"
+	"time"
+)
+
+func cacheDir() (string, error) {
+	d, err := os.UserCacheDir()
+	return path.Join(d, "tarweb"), err
+}
+
+func Extract(r *tar.Reader, dir string) error {
+	for {
+		hdr, err := r.Next()
+		if err == io.EOF {
+			break // End of archive
+		}
+		if err != nil {
+			return err
+		}
+		fmt.Println(hdr.Name)
+		if hdr.FileInfo().IsDir() {
+			err := os.MkdirAll(path.Join(dir, hdr.Name), 0755)
+			if err != nil && !errors.Is(err, fs.ErrExist) {
+				return fmt.Errorf("extract %s: %w", hdr.Name, err)
+			}
+			continue
+		}
+		dst := path.Join(dir, hdr.Name)
+		f, err := os.Create(dst)
+		if err != nil {
+			return fmt.Errorf("extract %s: %v", hdr.Name, err)
+		}
+		if _, err := io.Copy(f, r); err != nil {
+			return fmt.Errorf("extract %s: %v", hdr.Name, err)
+		}
+		f.Close()
+	}
+	return nil
+}
+
+var urls []string = []string{"http://127.0.0.1:8000/test.tar"}
+
+var archives = make(map[string]time.Time)
+
+func getIfModified(url string, since time.Time) (*http.Response, error) {
+	req, err := http.NewRequest(http.MethodGet, url, nil)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Add("If-Modified-Since", since.UTC().Format(time.RFC1123Z))
+	return http.DefaultClient.Do(req)
+}
+
+func fetchloop(root string, sleep time.Duration) {
+	for {
+		for url, since := range archives {
+			resp, err := getIfModified(url, since)
+			if err != nil {
+				log.Println("get archive:", err)
+				continue
+			}
+			if resp.StatusCode == http.StatusNotModified {
+				log.Printf("%s unmodified", url)
+				continue
+			}
+			if resp.Header.Get("Last-Modified") != "" {
+				modified, err := time.Parse(time.RFC1123, resp.Header.Get("Last-Modified"))
+				if err != nil {
+					log.Printf("parse last modified time for %s: %v", url, err)
+					continue
+				}
+				archives[url] = modified
+			}
+			rd := tar.NewReader(resp.Body)
+			if err := Extract(rd, root); err != nil {
+				log.Printf("extract %s: %v", url, err)
+			}
+			resp.Body.Close()
+		}
+		time.Sleep(sleep)
+	}
+}
+
+func main() {
+	archives["http://127.0.0.1:8000/test.tar"] = time.Time{}
+	archives["http://127.0.0.1:8000/meerkat.tar"] = time.Time{}
+	cache, err := cacheDir()
+	if err != nil {
+		log.Fatal(err)
+	}
+	if err := os.MkdirAll(cache, 0755); err != nil {
+		log.Fatal(err)
+	}
+	log.Println("serving archives from", cache)
+	go fetchloop(cache, 20*time.Second)
+	log.Fatal(http.ListenAndServe(":6969", http.FileServer(http.FS(os.DirFS(cache)))))
+}