Blob


1 package main
3 import (
4 "archive/tar"
5 "errors"
6 "fmt"
7 "io"
8 "io/fs"
9 "log"
10 "net/http"
11 "os"
12 "path"
13 "time"
14 )
16 func cacheDir() (string, error) {
17 d, err := os.UserCacheDir()
18 return path.Join(d, "tarweb"), err
19 }
21 func Extract(r *tar.Reader, dir string) error {
22 for {
23 hdr, err := r.Next()
24 if err == io.EOF {
25 break // End of archive
26 }
27 if err != nil {
28 return err
29 }
30 fmt.Println(hdr.Name)
31 if hdr.FileInfo().IsDir() {
32 err := os.MkdirAll(path.Join(dir, hdr.Name), 0755)
33 if err != nil && !errors.Is(err, fs.ErrExist) {
34 return fmt.Errorf("extract %s: %w", hdr.Name, err)
35 }
36 continue
37 }
38 dst := path.Join(dir, hdr.Name)
39 f, err := os.Create(dst)
40 if err != nil {
41 return fmt.Errorf("extract %s: %v", hdr.Name, err)
42 }
43 if _, err := io.Copy(f, r); err != nil {
44 return fmt.Errorf("extract %s: %v", hdr.Name, err)
45 }
46 f.Close()
47 }
48 return nil
49 }
51 var urls []string = []string{"http://127.0.0.1:8000/test.tar"}
53 var archives = make(map[string]time.Time)
55 func getIfModified(url string, since time.Time) (*http.Response, error) {
56 req, err := http.NewRequest(http.MethodGet, url, nil)
57 if err != nil {
58 return nil, err
59 }
60 req.Header.Add("If-Modified-Since", since.UTC().Format(time.RFC1123Z))
61 return http.DefaultClient.Do(req)
62 }
64 func fetchloop(root string, sleep time.Duration) {
65 for {
66 for url, since := range archives {
67 resp, err := getIfModified(url, since)
68 if err != nil {
69 log.Println("get archive:", err)
70 continue
71 }
72 if resp.StatusCode == http.StatusNotModified {
73 log.Printf("%s unmodified", url)
74 continue
75 }
76 if resp.Header.Get("Last-Modified") != "" {
77 modified, err := time.Parse(time.RFC1123, resp.Header.Get("Last-Modified"))
78 if err != nil {
79 log.Printf("parse last modified time for %s: %v", url, err)
80 continue
81 }
82 archives[url] = modified
83 }
84 rd := tar.NewReader(resp.Body)
85 if err := Extract(rd, root); err != nil {
86 log.Printf("extract %s: %v", url, err)
87 }
88 resp.Body.Close()
89 }
90 time.Sleep(sleep)
91 }
92 }
94 func main() {
95 archives["http://127.0.0.1:8000/test.tar"] = time.Time{}
96 archives["http://127.0.0.1:8000/meerkat.tar"] = time.Time{}
97 cache, err := cacheDir()
98 if err != nil {
99 log.Fatal(err)
101 if err := os.MkdirAll(cache, 0755); err != nil {
102 log.Fatal(err)
104 log.Println("serving archives from", cache)
105 go fetchloop(cache, 20*time.Second)
106 log.Fatal(http.ListenAndServe(":6969", http.FileServer(http.FS(os.DirFS(cache)))))