package nvdmirror import ( "compress/gzip" "encoding/json" "io" "os" "time" "github.com/pablotron/cvez/atomictemp" ) // JSON file backed URL cache. type JsonCache struct { dirty bool // has the cache been modified? path string // backing JSON file vals map[string]Entry // entries } // Create new JSON cache. func NewJsonCache(path string) (JsonCache, error) { r := JsonCache { path: path, } // open path f, err := os.OpenFile(path, os.O_CREATE, 0640) if err != nil { return r, err } defer f.Close() // stat file st, err := f.Stat() if err != nil { return r, err } vals := make(map[string]Entry) if st.Size() > 0 { // create gzip reader zr, err := gzip.NewReader(f) if err != nil { return r, err } // read/decode json d := json.NewDecoder(zr) if err := d.Decode(&vals); err != nil { return r, err } } // save path and values r.path = path r.vals = vals // return success return r, nil } // Get cache entry func (me JsonCache) Get(s string) (map[string]string, bool) { if e, ok := me.vals[s]; ok { return e.Headers, ok } else { return nil, false } } // Set cache entry. func (me *JsonCache) Set(s string, headers map[string]string) error { // mark cache as dirty me.dirty = true // copy map to internal storage newHeaders := make(map[string]string) for k, v := range(headers) { newHeaders[k] = v } // update entry me.vals[s] = Entry { Time: time.Now(), Headers: newHeaders, } // return success return nil } // Remove cache entry, if it exists. func (me *JsonCache) Delete(s string) error { me.dirty = true delete(me.vals, s) return nil } // Save and close cache. func (me *JsonCache) Close() error { if !me.dirty { // return success return nil } // open temp output file err := atomictemp.Create(me.path, func(w io.Writer) error { // encode/compress JSON zw := gzip.NewWriter(w) e := json.NewEncoder(zw) if err := e.Encode(me.vals); err != nil { return err } // flush changes if err := zw.Flush(); err != nil { return err } // return success return nil }) if err != nil { return err } // Mark cache as clean, return success. me.dirty = false return nil }