commit 1a048c00522449ec807fb494150b25fdde344ce1 from: Oliver Lowe date: Tue Nov 15 00:27:07 2022 UTC initial commit 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))))) +}