diff --git a/src/concurrent_map.go b/src/concurrent_map.go index 339fb919..8e2dc2db 100644 --- a/src/concurrent_map.go +++ b/src/concurrent_map.go @@ -3,24 +3,24 @@ package main import "sync" type concurrentMap struct { - values map[string]string + values map[string]interface{} lock sync.RWMutex } func newConcurrentMap() *concurrentMap { return &concurrentMap{ - values: make(map[string]string), + values: make(map[string]interface{}), lock: sync.RWMutex{}, } } -func (c *concurrentMap) set(key, value string) { +func (c *concurrentMap) set(key string, value interface{}) { c.lock.Lock() defer c.lock.Unlock() c.values[key] = value } -func (c *concurrentMap) get(key string) (string, bool) { +func (c *concurrentMap) get(key string) (interface{}, bool) { c.lock.RLock() defer c.lock.RUnlock() if val, ok := c.values[key]; ok { @@ -28,3 +28,13 @@ func (c *concurrentMap) get(key string) (string, bool) { } return "", false } + +func (c *concurrentMap) remove(key string) { + c.lock.RLock() + defer c.lock.RUnlock() + delete(c.values, key) +} + +func (c *concurrentMap) list() map[string]interface{} { + return c.values +} diff --git a/src/environment.go b/src/environment.go index 2837614b..f2ca67e2 100644 --- a/src/environment.go +++ b/src/environment.go @@ -52,7 +52,8 @@ type cache interface { init(home string) close() get(key string) (string, bool) - set(key, value string) + // ttl in seconds + set(key, value string, ttl int64) } type environmentInfo interface { @@ -97,7 +98,14 @@ func (c *commandCache) set(command, path string) { } func (c *commandCache) get(command string) (string, bool) { - return c.commands.get(command) + cmd, found := c.commands.get(command) + if !found { + return "", false + } + if command, ok := cmd.(string); ok { + return command, true + } + return "", false } type tracer struct { diff --git a/src/environment_cache.go b/src/environment_cache.go index 385f569e..006bffb4 100644 --- a/src/environment_cache.go +++ b/src/environment_cache.go @@ -1,15 +1,21 @@ package main import ( - "fmt" + "encoding/json" "io/ioutil" - "strings" + "time" ) const ( cachePath = "/.omp.cache" ) +type cacheObject struct { + Value string `json:"value"` + Timestamp int64 `json:"timestamp"` + TTL int64 `json:"ttl"` +} + type fileCache struct { cache *concurrentMap home string @@ -18,32 +24,49 @@ type fileCache struct { func (fc *fileCache) init(home string) { fc.cache = newConcurrentMap() fc.home = home - content, err := ioutil.ReadFile(home + cachePath) + content, err := ioutil.ReadFile(fc.home + cachePath) if err != nil { return } - for _, line := range strings.Split(string(content), "\n") { - if len(line) == 0 || !strings.Contains(line, "=") { - continue - } - kv := strings.SplitN(line, "=", 2) - fc.set(kv[0], kv[1]) + + var list map[string]*cacheObject + if err := json.Unmarshal(content, &list); err != nil { + return + } + + for key, co := range list { + fc.cache.set(key, co) } } func (fc *fileCache) close() { - var sb strings.Builder - for key, value := range fc.cache.values { - cacheEntry := fmt.Sprintf("%s=%s\n", key, value) - sb.WriteString(cacheEntry) + fc.set("hello", "world", 200) + if dump, err := json.Marshal(fc.cache.list()); err == nil { + _ = ioutil.WriteFile(fc.home+cachePath, dump, 0644) } - _ = ioutil.WriteFile(fc.home+cachePath, []byte(sb.String()), 0644) } func (fc *fileCache) get(key string) (string, bool) { - return fc.cache.get(key) + val, found := fc.cache.get(key) + if !found { + return "", false + } + co, ok := val.(*cacheObject) + if !ok { + return "", false + } + expired := time.Now().Unix() >= (co.Timestamp + co.TTL*60) + if expired { + fc.cache.remove(key) + return "", false + } + return co.Value, true } -func (fc *fileCache) set(key, value string) { - fc.cache.set(key, value) +func (fc *fileCache) set(key, value string, ttl int64) { + fc.cache.set(key, &cacheObject{ + Value: value, + Timestamp: time.Now().Unix(), + TTL: ttl, + }) }