Skip to content

Commit

Permalink
cache rendered svgs when serving
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Menet committed Aug 21, 2023
1 parent 00700b8 commit c5d402d
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 5 deletions.
46 changes: 46 additions & 0 deletions cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package main

import (
"time"
)

type cache struct {
timeout time.Duration
store map[string]cacheElement
}

func NewCache(timeout time.Duration) *cache {
return &cache{
timeout: timeout,
store: map[string]cacheElement{},
}
}

func (c *cache) Add(key string, data []byte) {
c.store[key] = cacheElement{
cachedAt: time.Now(),
data: data,
}
}

func (c *cache) Get(key string) ([]byte, bool) {
elem, ok := c.store[key]
if !ok {
return nil, false
}
age := time.Since(elem.cachedAt)
if age >= c.timeout {
delete(c.store, key)
return nil, false
}
return elem.data, true
}

func (c *cache) Purge() {
c.store = make(map[string]cacheElement)
}

type cacheElement struct {
data []byte
cachedAt time.Time
}
93 changes: 93 additions & 0 deletions cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package main

import (
"bytes"
"testing"
"time"
)

func TestCache_Add(t *testing.T) {
// Create a new cache instance
cache := NewCache(time.Minute)

// Add a cache element with a key and data
key := "test"
data := []byte("test data")
cache.Add(key, data)

// Check if the cache element exists in the store
if _, ok := cache.store[key]; !ok {
t.Errorf("Cache element with key '%s' not found", key)
}

// Check if the data of the cache element is correct
if got := cache.store[key].data; !bytes.Equal(got, data) {
t.Errorf("Cache element data mismatch, got %v, want %v", got, data)
}
}

func TestCache_Get(t *testing.T) {
// Create a new cache instance
cache := NewCache(time.Minute)

// Add a cache element with a key and data
key := "test"
data := []byte("test data")
cache.Add(key, data)

// Retrieve the cache element using the Get method
got, ok := cache.Get(key)

// Check if the cache element is found
if !ok {
t.Errorf("Cache element with key '%s' not found", key)
}

// Check if the retrieved data is correct
if string(got) != string(data) {
t.Errorf("Retrieved data mismatch, got %s, want %s", got, data)
}
}

func TestCache_Get_Expired(t *testing.T) {
// Create a new cache instance with a short timeout duration
cache := NewCache(1 * time.Millisecond)

// Add a cache element with a key and data
key := "test"
data := []byte("test data")
cache.Add(key, data)

// Wait for the cache element to expire
time.Sleep(2 * time.Millisecond)

// Retrieve the cache element using the Get method
got, ok := cache.Get(key)

// Check if the cache element is not found
if ok {
t.Errorf("Cache element with key '%s' found, expected not found", key)
}

// Check if the retrieved data is nil
if got != nil {
t.Errorf("Retrieved data mismatch, got %v, want nil", got)
}
}

func TestCache_Purge(t *testing.T) {
// Create a new cache instance
cache := NewCache(time.Minute)

// Add multiple cache elements
cache.Add("key1", []byte("data1"))
cache.Add("key2", []byte("data2"))

// Purge the cache
cache.Purge()

// Check if the store is empty
if len(cache.store) != 0 {
t.Errorf("Cache store is not empty after purging")
}
}
7 changes: 5 additions & 2 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ type App struct {
out string
}
serve struct {
renderer string
listener string
renderer string
listener string
cacheTimeout string
}
}

Expand Down Expand Up @@ -82,6 +83,7 @@ called 'custom' using the following URL: http://localhost:8080/A.AB+C?renderer=c
}
serveCmd.PersistentFlags().StringVar(&a.flags.serve.listener, "listener", "127.0.0.1:8080", "listener to be used by the http server")
serveCmd.PersistentFlags().StringVar(&a.flags.serve.renderer, "renderer", "serve", "name of the default renderer to be used")
serveCmd.PersistentFlags().StringVar(&a.flags.serve.cacheTimeout, "cache-timeout", "10m", "timeout of the internal cache")
rootCmd.AddCommand(serveCmd)

// version
Expand Down Expand Up @@ -147,6 +149,7 @@ func (a *App) serveCmd(cmd *cobra.Command, args []string) {
a.flags.configfile,
a.flags.base,
a.flags.glob,
a.flags.serve.cacheTimeout,
)
exitOnErr(err)
err = s.Run()
Expand Down
19 changes: 16 additions & 3 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"strings"
"text/template"
"time"
)

//go:embed server/templates/*
Expand All @@ -23,17 +24,22 @@ type server struct {
configfile string
base string
glob string
cache cache
}

func NewServer(listener, defaultRenderer, configfile, base, glob string) (*server, error) {
func NewServer(listener, defaultRenderer, configfile, base, glob, cacheTimeout string) (*server, error) {
durr, err := time.ParseDuration(cacheTimeout)
if err != nil {
return nil, err
}
s := &server{
listener: listener,
defaultRenderer: defaultRenderer,
configfile: configfile,
base: base,
glob: glob,
cache: *NewCache(durr),
}
var err error
s.indexTemplate, err = template.ParseFS(templateFS, "server/templates/index.html.tmpl")
return s, err
}
Expand All @@ -56,6 +62,11 @@ func (s *server) Run() error {
}

func (s *server) HandleIndex(w http.ResponseWriter, r *http.Request) {
key := r.URL.RawQuery
if cached, ok := s.cache.Get(key); ok {
_, _ = w.Write(cached)
return
}
focusElems := r.URL.Query().Get("focus")
focus := strings.Split(focusElems, "_")

Expand Down Expand Up @@ -113,5 +124,7 @@ func (s *server) HandleIndex(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(err.Error()))
return
}
_, _ = w.Write(buf.Bytes())
data := buf.Bytes()
s.cache.Add(key, data)
_, _ = w.Write(data)
}

0 comments on commit c5d402d

Please sign in to comment.