carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package assetcache
2
3import (
4 "encoding/json"
5 "fmt"
6 "math"
7 "net/http"
8 "time"
9)
10
11// Meta is what the store keeps beside an entry's body files. GzipSize is
12// zero when there is no gzip copy. Version names the body files, so a
13// commit never overwrites bytes an older Meta still points at.
14type Meta struct {
15 Key Key
16 Version string
17 Header http.Header
18 Lifetime time.Duration
19 Expires time.Time
20 StoredAt time.Time
21 Size int64
22 GzipSize int64
23}
24
25// Age is how long ago, by its lifetime, the entry was fresh from the origin:
26// Lifetime minus the time left until Expires. It is never below zero, so an
27// entry stored "in the future" before a clock step reports age zero.
28func (m Meta) Age(now time.Time) time.Duration {
29 if a := m.Lifetime - m.Expires.Sub(now); a > 0 {
30 return a
31 }
32 return 0
33}
34
35func encodeMeta(m Meta) ([]byte, error) {
36 return json.Marshal(m)
37}
38
39// decodeMeta parses a .meta file. Fields it does not know are ignored, so a
40// file written by a newer binary still loads.
41func decodeMeta(raw []byte) (Meta, error) {
42 var m Meta
43 if err := json.Unmarshal(raw, &m); err != nil {
44 return Meta{}, err
45 }
46 if !validVersion(m.Version) {
47 return Meta{}, fmt.Errorf("version %q is not a file name part", m.Version)
48 }
49 if m.Size < 0 || m.GzipSize < 0 || m.Size > math.MaxInt64-m.GzipSize {
50 return Meta{}, fmt.Errorf("sizes %d and %d are not usable", m.Size, m.GzipSize)
51 }
52 return m, nil
53}
54
55// validVersion accepts the short alphanumeric tokens the store draws, and
56// nothing that could change which file a name refers to.
57func validVersion(v string) bool {
58 if v == "" || len(v) > 64 {
59 return false
60 }
61 for _, c := range v {
62 switch {
63 case c >= '0' && c <= '9', c >= 'a' && c <= 'z', c >= 'A' && c <= 'Z':
64 default:
65 return false
66 }
67 }
68 return true
69}
70
71func metaName(id string) string { return id + ".meta" }
72func bodyName(id, version string) string { return id + "." + version + ".body" }
73func gzipName(id, version string) string { return id + "." + version + ".gz" }
74