commit - /dev/null
commit + 1a048c00522449ec807fb494150b25fdde344ce1
blob - /dev/null
blob + 452b7480f2db1d6947eb2e0db79994890b98cec0 (mode 644)
--- /dev/null
+++ go.mod
+module olowe.co/tarweb
+
+go 1.18
blob - /dev/null
blob + 9cd5671a333ef9e7f03e7f87bf3ed793b8f44d6e (mode 644)
--- /dev/null
+++ tarweb.go
+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)))))
+}