summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--cache/cache.go54
-rw-r--r--cache/cache_test.go72
-rw-r--r--version/version.go2
4 files changed, 128 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index f82cc30..d1b3232 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
# Copyright © 2022 siddharth ravikumar <s@ricketyspace.net>
MOD=ricketyspace.net/peach
-PKGS=${MOD}/client ${MOD}/nws ${MOD}/photon
+PKGS=${MOD}/cache ${MOD}/client ${MOD}/nws ${MOD}/photon
CSS=static/peach.min.css
peach: fix fmt ${CSS}
diff --git a/cache/cache.go b/cache/cache.go
new file mode 100644
index 0000000..fbc763e
--- /dev/null
+++ b/cache/cache.go
@@ -0,0 +1,54 @@
+// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net>
+// SPDX-License-Identifier: ISC
+
+// A simple in-memory cache store.
+package cache
+
+import "time"
+
+// An item in the key-value cache store.
+type item struct {
+ value string
+ expires time.Time // Time when the key-value expires
+}
+
+// A key-value cache store.
+type Cache struct {
+ store map[string]item
+}
+
+// Returns a new empty cache store.
+func NewCache() *Cache {
+ c := new(Cache)
+ c.store = make(map[string]item)
+ return c
+}
+
+// Set the (key,value) item to the cache store. This item will be
+// considered expired after time `expires`.
+//
+// Cache.Get will return an empty string once `expires` is past the
+// current time.
+func (c *Cache) Set(key, value string, expires time.Time) {
+ c.store[key] = item{
+ value: value,
+ expires: expires,
+ }
+}
+
+// Get an (key,value) item from the cache store by key.
+//
+// An empty string will be returned when if the key does not exist or
+// if the item corresponding to the key has expired. An expired
+// (key,value) item will be removed from the cache store.
+func (c *Cache) Get(key string) string {
+ if _, ok := c.store[key]; !ok {
+ return ""
+ }
+ // Check if the item expired.
+ if time.Until(c.store[key].expires).Seconds() < 0 {
+ delete(c.store, key)
+ return ""
+ }
+ return c.store[key].value
+}
diff --git a/cache/cache_test.go b/cache/cache_test.go
new file mode 100644
index 0000000..41e0d25
--- /dev/null
+++ b/cache/cache_test.go
@@ -0,0 +1,72 @@
+// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net>
+// SPDX-License-Identifier: ISC
+
+package cache
+
+import (
+ "testing"
+ "time"
+)
+
+func TestNewCache(t *testing.T) {
+ c := NewCache()
+ if c == nil {
+ t.Errorf("cache is nil")
+ return
+ }
+ if c.store == nil {
+ t.Errorf("cache.store is nil")
+ return
+ }
+ // Try manually adding an item.
+ c.store["foo"] = item{
+ value: "bar",
+ expires: time.Now().Add(time.Second * 10),
+ }
+ if c.store["foo"].value != "bar" {
+ t.Errorf("cache.store['foo'] is not bar")
+ return
+ }
+}
+
+func TestCacheSet(t *testing.T) {
+ c := NewCache()
+ if c == nil {
+ t.Errorf("cache is nil")
+ return
+ }
+ exp := time.Now().Add(time.Second * 10)
+ c.Set("foo", "bar", exp)
+ if c.store["foo"].value != "bar" {
+ t.Errorf("cache.store['foo'] is not bar")
+ return
+ }
+ if c.store["foo"].expires.Unix() != exp.Unix() {
+ t.Errorf("cache.store['foo'].expires no set correctly")
+ return
+ }
+}
+
+func TestCacheGet(t *testing.T) {
+ c := NewCache()
+ if c == nil {
+ t.Errorf("cache is nil")
+ return
+ }
+
+ // Test 1
+ exp := time.Now().Add(time.Second * 10)
+ c.Set("foo", "bar", exp)
+ if c.Get("foo") != "bar" {
+ t.Errorf("cache.Get(foo) is not bar")
+ return
+ }
+
+ // Test 2
+ exp = time.Now().Add(time.Second * -10)
+ c.Set("sna", "fu", exp)
+ if c.Get("sna") != "" {
+ t.Errorf("cache.Get(sna) is not empty: %s", c.Get("sna"))
+ return
+ }
+}
diff --git a/version/version.go b/version/version.go
index 36def98..ca288f9 100644
--- a/version/version.go
+++ b/version/version.go
@@ -4,4 +4,4 @@
// Peach version.
package version
-const Version = "0.3.1.dev1"
+const Version = "0.3.1.dev2"