Skip to content

Commit

Permalink
Remove valkey, use SQLite for cache
Browse files Browse the repository at this point in the history
  • Loading branch information
airforce270 committed Aug 17, 2024
1 parent 49761f1 commit 3b273c0
Show file tree
Hide file tree
Showing 18 changed files with 177 additions and 170 deletions.
65 changes: 1 addition & 64 deletions cache/cache.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// Package cache provides an interface to the local Redis cache.
// Package cache provides an interface to a cache.
package cache

import (
"context"
"time"

"github.com/valkey-io/valkey-go"
)

// A Cache stores and retrieves simple key-value data quickly.
Expand Down Expand Up @@ -44,63 +41,3 @@ const (
func GlobalSlowmodeKey(platformName string) string {
return "global_slowmode_" + platformName
}

// NewValkey creates a new Valkey-backed Cache.
func NewValkey() (Valkey, error) {
c, err := valkey.NewClient(valkey.ClientOption{InitAddress: []string{"cache:6379"}})
if err != nil {
return Valkey{}, err
}
return Valkey{c: c}, nil
}

// Valkey implements Cache for a real Valkey database.
type Valkey struct {
c valkey.Client
}

func (v *Valkey) StoreBool(key string, value bool) error {
return v.c.Do(context.TODO(), v.c.B().Set().Key(key).Value(strFromBool(value)).Build()).Error()
}

func (v *Valkey) StoreExpiringBool(key string, value bool, expiration time.Duration) error {
return v.c.Do(context.TODO(), v.c.B().Set().Key(key).Value(strFromBool(value)).Ex(expiration).Build()).Error()
}

func (v *Valkey) FetchBool(key string) (bool, error) {
resp, err := v.c.Do(context.TODO(), v.c.B().Get().Key(key).Build()).ToString()
if err != nil {
if valkey.IsValkeyNil(err) {
return false, nil
}
return false, err
}
return boolFromStr(resp), nil
}

func (v *Valkey) StoreString(key, value string) error {
return v.c.Do(context.TODO(), v.c.B().Set().Key(key).Value(value).Build()).Error()
}

func (v *Valkey) StoreExpiringString(key, value string, expiration time.Duration) error {
return v.c.Do(context.TODO(), v.c.B().Set().Key(key).Value(value).Ex(expiration).Build()).Error()
}

func (v *Valkey) FetchString(key string) (string, error) {
val, err := v.c.Do(context.TODO(), v.c.B().Get().Key(key).Build()).ToString()
if valkey.IsValkeyNil(err) {
return "", nil
}
return val, err
}

func strFromBool(b bool) string {
if b {
return "true"
}
return "false"
}

func boolFromStr(s string) bool {
return s == "true"
}
58 changes: 11 additions & 47 deletions cache/cachetest/cachetest.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,18 @@
package cachetest

import (
"sync"
"time"
)

// NewInMemory creates a new InMemoryCache for test.
func NewInMemory() *InMemory {
return &InMemory{d: map[string]any{}}
}
"testing"

// InMemory implements a simple map-based cache for testing.
type InMemory struct {
mtx sync.Mutex // protects writes to d
d map[string]any
}
"github.com/airforce270/airbot/cache"
"gorm.io/gorm"
)

func (c *InMemory) StoreBool(key string, value bool) error {
c.store(key, value)
return nil
}
func (c *InMemory) StoreExpiringBool(key string, value bool, expiration time.Duration) error {
c.store(key, value)
return nil
}
func (c *InMemory) FetchBool(key string) (bool, error) {
val, found := c.d[key]
if !found {
return false, nil
// NewSQLite creates a new cache for test.
func NewSQLite(t *testing.T, db *gorm.DB) cache.Cache {
t.Helper()
c, err := cache.NewSQLite(db)
if err != nil {
t.Fatalf("Failed to create cache for test: %v", err)
}
return val.(bool), nil
}
func (c *InMemory) StoreString(key, value string) error {
c.store(key, value)
return nil
}
func (c *InMemory) StoreExpiringString(key, value string, expiration time.Duration) error {
c.store(key, value)
return nil
}
func (c *InMemory) FetchString(key string) (string, error) {
val, found := c.d[key]
if !found {
return "", nil
}
return val.(string), nil
}

func (c *InMemory) store(key string, value any) {
c.mtx.Lock()
c.d[key] = value
c.mtx.Unlock()
return &c
}
101 changes: 101 additions & 0 deletions cache/sqlite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package cache

import (
"fmt"
"time"

"github.com/airforce270/airbot/database/models"
"gorm.io/gorm"
)

// NewSQLite creates a new SQLite-backed Cache.
func NewSQLite(db *gorm.DB) (SQLite, error) {
return SQLite{db}, nil
}

// SQLite implements Cache for a SQLite database.
type SQLite struct {
db *gorm.DB
}

func (v *SQLite) StoreBool(key string, value bool) error {
item := models.CacheBoolItem{
Key: key,
Value: value,
}

if err := v.db.Save(&item).Error; err != nil {
return fmt.Errorf("failed to store %s=%v: %w", key, value, err)
}

return nil
}

func (v *SQLite) StoreExpiringBool(key string, value bool, expiration time.Duration) error {
item := models.CacheBoolItem{
Key: key,
Value: value,
ExpiresAt: time.Now().Add(expiration),
}

if err := v.db.Save(&item).Error; err != nil {
return fmt.Errorf("failed to store %q=%t: %w", key, value, err)
}

return nil
}

func (v *SQLite) FetchBool(key string) (bool, error) {
var item models.CacheBoolItem

if err := v.db.First(&item, "key = ?", key).Error; err != nil {
return false, fmt.Errorf("failed to fetch %q: %w", key, err)
}

if !item.ExpiresAt.IsZero() && item.ExpiresAt.Before(time.Now()) {
return false, nil
}

return item.Value, nil
}

func (v *SQLite) StoreString(key, value string) error {
item := models.CacheStringItem{
Key: key,
Value: value,
}

if err := v.db.Save(&item).Error; err != nil {
return fmt.Errorf("failed to store %q=%q: %w", key, value, err)
}

return nil
}

func (v *SQLite) StoreExpiringString(key, value string, expiration time.Duration) error {
item := models.CacheStringItem{
Key: key,
Value: value,
ExpiresAt: time.Now().Add(expiration),
}

if err := v.db.Save(&item).Error; err != nil {
return fmt.Errorf("failed to store %q=%q: %w", key, value, err)
}

return nil
}

func (v *SQLite) FetchString(key string) (string, error) {
var item models.CacheStringItem

if err := v.db.First(&item, "key = ?", key).Error; err != nil {
return "", fmt.Errorf("failed to fetch %q: %w", key, err)
}

if !item.ExpiresAt.IsZero() && item.ExpiresAt.Before(time.Now()) {
return "", nil
}

return item.Value, nil
}
4 changes: 2 additions & 2 deletions commands/admin/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,9 @@ func TestReloadConfig(t *testing.T) {
ctx := context.Background()

db := databasetest.New(t)
cdb := cachetest.NewInMemory()
cdb := cachetest.NewSQLite(t, db)

platform := twitch.NewForTesting(server.URL(t).String(), db)
platform := twitch.NewForTesting(t, server.URL(t).String(), db)

const want = "something-specific"
cfg := func() string {
Expand Down
14 changes: 7 additions & 7 deletions commands/botinfo/botinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestEchoCommands(t *testing.T) {
Prefix: "$",
PermissionLevel: permission.Normal,
Resources: base.Resources{
Platform: twitch.NewForTesting("forsen", databasetest.New(t)),
Platform: twitch.NewForTesting(t, "forsen", databasetest.New(t)),
},
},
Platform: commandtest.TwitchPlatform,
Expand Down Expand Up @@ -54,7 +54,7 @@ func TestEchoCommands(t *testing.T) {
Prefix: "$",
PermissionLevel: permission.Normal,
Resources: base.Resources{
Platform: twitch.NewForTesting("forsen", databasetest.New(t)),
Platform: twitch.NewForTesting(t, "forsen", databasetest.New(t)),
},
},
Platform: commandtest.TwitchPlatform,
Expand All @@ -77,7 +77,7 @@ func TestEchoCommands(t *testing.T) {
Prefix: "$",
PermissionLevel: permission.Normal,
Resources: base.Resources{
Platform: twitch.NewForTesting("forsen", databasetest.New(t)),
Platform: twitch.NewForTesting(t, "forsen", databasetest.New(t)),
},
},
Platform: commandtest.TwitchPlatform,
Expand All @@ -100,7 +100,7 @@ func TestEchoCommands(t *testing.T) {
Prefix: "$",
PermissionLevel: permission.Normal,
Resources: base.Resources{
Platform: twitch.NewForTesting("forsen", databasetest.New(t)),
Platform: twitch.NewForTesting(t, "forsen", databasetest.New(t)),
},
},
Platform: commandtest.TwitchPlatform,
Expand All @@ -123,7 +123,7 @@ func TestEchoCommands(t *testing.T) {
Prefix: "$",
PermissionLevel: permission.Normal,
Resources: base.Resources{
Platform: twitch.NewForTesting("forsen", databasetest.New(t)),
Platform: twitch.NewForTesting(t, "forsen", databasetest.New(t)),
},
},
Platform: commandtest.TwitchPlatform,
Expand All @@ -146,7 +146,7 @@ func TestEchoCommands(t *testing.T) {
Prefix: "??",
PermissionLevel: permission.Normal,
Resources: base.Resources{
Platform: twitch.NewForTesting("forsen", databasetest.New(t)),
Platform: twitch.NewForTesting(t, "forsen", databasetest.New(t)),
},
},
Platform: commandtest.TwitchPlatform,
Expand Down Expand Up @@ -190,7 +190,7 @@ func TestEchoCommands(t *testing.T) {
Prefix: "$",
PermissionLevel: permission.Normal,
Resources: base.Resources{
Platform: twitch.NewForTesting("forsen", databasetest.New(t)),
Platform: twitch.NewForTesting(t, "forsen", databasetest.New(t)),
},
},
Platform: commandtest.TwitchPlatform,
Expand Down
4 changes: 2 additions & 2 deletions commands/bulk/bulk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestBulkCommands(t *testing.T) {
Prefix: "$",
PermissionLevel: permission.Mod,
Resources: base.Resources{
Platform: twitch.NewForTesting("forsen", databasetest.New(t)),
Platform: twitch.NewForTesting(t, "forsen", databasetest.New(t)),
},
},
Platform: commandtest.TwitchPlatform,
Expand Down Expand Up @@ -75,7 +75,7 @@ func TestBulkCommands(t *testing.T) {
Prefix: "$",
PermissionLevel: permission.Mod,
Resources: base.Resources{
Platform: twitch.NewForTesting("forsen", databasetest.New(t)),
Platform: twitch.NewForTesting(t, "forsen", databasetest.New(t)),
},
},
Platform: commandtest.TwitchPlatform,
Expand Down
4 changes: 2 additions & 2 deletions commands/commandtest/commandtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ func Run(t *testing.T, tests []Case) {
server.Resps = tc.apiResps

db := databasetest.New(t)
cdb := cachetest.NewInMemory()
cdb := cachetest.NewSQLite(t, db)

var platform base.Platform
switch tc.platform {
case TwitchPlatform:
platform = twitch.NewForTesting(server.URL(t).String(), db)
platform = twitch.NewForTesting(t, server.URL(t).String(), db)
default:
t.Fatal("Platform must be set.")
}
Expand Down
Loading

0 comments on commit 3b273c0

Please sign in to comment.