aboutsummaryrefslogtreecommitdiff
path: root/nvdmirror/jsoncache.go
blob: 7bcd0ca3db23a6568f92ec24f0fb03a341201ace (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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
}