Skip to content

Commit 8f502f1

Browse files
authored
Draft: refactor cache to use an interface (#1)
* refactor cache to use an interface * bump action versions Signed-off-by: circa10a <caleblemoine@gmail.com> * fix api response types Signed-off-by: circa10a <caleblemoine@gmail.com> --------- Signed-off-by: circa10a <caleblemoine@gmail.com>
1 parent 21c6d94 commit 8f502f1

File tree

12 files changed

+375
-197
lines changed

12 files changed

+375
-197
lines changed

.github/workflows/release.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ jobs:
1414
runs-on: ubuntu-latest
1515
steps:
1616
- name: Checkout
17-
uses: actions/checkout@v3
17+
uses: actions/checkout@v4
1818
- name: Unshallow
1919
run: git fetch --prune --unshallow
2020
- name: Install Go
21-
uses: actions/setup-go@v3
21+
uses: actions/setup-go@v5
2222
- name: Run GoReleaser
23-
uses: goreleaser/goreleaser-action@v3
23+
uses: goreleaser/goreleaser-action@v6
2424
with:
2525
version: latest
26-
args: release --rm-dist
26+
args: release --clean
2727
env:
2828
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2929
- name: GoReportCard

.github/workflows/tag.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
with:
1616
fetch-depth: '0'
1717
- name: Install Go
18-
uses: actions/setup-go@v3
18+
uses: actions/setup-go@v5
1919
- name: Bump version and push tag
2020
uses: anothrNick/github-tag-action@1.61.0
2121
id: tagging

.github/workflows/test.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ jobs:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- name: Install Go
13-
uses: actions/setup-go@v3
13+
uses: actions/setup-go@v5
1414
- name: Checkout code
15-
uses: actions/checkout@v3
15+
uses: actions/checkout@v4
1616
- name: Test
1717
run: make test
1818
golangci-lint:
1919
runs-on: ubuntu-latest
2020
steps:
21-
- uses: actions/checkout@v3
21+
- uses: actions/checkout@v4
2222
- name: Install Go
23-
uses: actions/setup-go@v3
23+
uses: actions/setup-go@v5
2424
- name: golangci-lint
25-
uses: golangci/golangci-lint-action@v3
25+
uses: golangci/golangci-lint-action@v6

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ By default, the library will use an in-memory cache that will be used to reduce
6161

6262
### Persistent
6363

64-
If you need a persistent cache to live outside of your application, [Redis](https://redis.io/) is supported by this library. To have the library cache address proximity using a Redis instance, simply provide a `redis.RedisOptions` struct to `geofence.Config.RedisOptions`. If `RedisOptions` is configured, the in-memory cache will not be used.
64+
If you need a persistent cache to live outside of your application, [Redis](https://redis.io/) is supported by this library. To have the library cache address proximity using a Redis instance, simply provide a `RedisOptions` struct using the `cache` package to `geofence.Config.RedisOptions`. If `RedisOptions` is configured, the in-memory cache will not be used.
6565

6666
> Note: Only Redis 7 is currently supported at the time of this writing.
6767
@@ -76,7 +76,7 @@ import (
7676
"time"
7777

7878
"github.com/circa10a/go-geofence"
79-
"github.com/go-redis/redis/v9"
79+
geofencecache "github.com/circa10a/go-geofence/cache"
8080
)
8181

8282
func main() {
@@ -87,7 +87,7 @@ func main() {
8787
AllowPrivateIPAddresses: true,
8888
CacheTTL: 7 * (24 * time.Hour), // 1 week
8989
// Use Redis for caching
90-
RedisOptions: &redis.Options{
90+
RedisOptions: &geofencecache.RedisOptions{
9191
Addr: "localhost:6379",
9292
Password: "", // no password set
9393
DB: 0, // use default DB
@@ -100,6 +100,7 @@ func main() {
100100
if err != nil {
101101
log.Fatal(err)
102102
}
103+
103104
// Address nearby: false
104105
fmt.Println("Address nearby: ", isAddressNearby)
105106
}

cache/cache.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package cache
2+
3+
import (
4+
"context"
5+
)
6+
7+
// Cache is an interface for caching ip addresses
8+
type Cache interface {
9+
Get(context.Context, string) (bool, bool, error)
10+
Set(context.Context, string, bool) error
11+
}

cache/memory.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package cache
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
gocache "github.com/patrickmn/go-cache"
8+
)
9+
10+
const (
11+
deleteExpiredCacheItemsInternal = 10 * time.Minute
12+
)
13+
14+
// MemoryCache is used to store/fetch ip proximity from an in-memory cache.
15+
type MemoryCache struct {
16+
memoryClient *gocache.Cache
17+
memoryOptions *MemoryOptions
18+
}
19+
20+
// MemoryOptions holds in-memory cache configuration parameters.
21+
type MemoryOptions struct {
22+
TTL time.Duration
23+
}
24+
25+
// NewRedisCache provides a new in-memory cache client.
26+
func NewMemoryCache(memoryOptions *MemoryOptions) *MemoryCache {
27+
return &MemoryCache{
28+
memoryClient: gocache.New(memoryOptions.TTL, deleteExpiredCacheItemsInternal),
29+
memoryOptions: memoryOptions,
30+
}
31+
}
32+
33+
// Get gets value from the in-memory cache.
34+
func (m *MemoryCache) Get(ctx context.Context, key string) (bool, bool, error) {
35+
if isIPAddressNear, found := m.memoryClient.Get(key); found {
36+
return isIPAddressNear.(bool), found, nil
37+
}
38+
return false, false, nil
39+
}
40+
41+
// Set sets k/v in the in-memory cache.
42+
func (m *MemoryCache) Set(ctx context.Context, key string, value bool) error {
43+
m.memoryClient.Set(key, value, m.memoryOptions.TTL)
44+
return nil
45+
}

cache/redis.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package cache
2+
3+
import (
4+
"context"
5+
"strconv"
6+
"time"
7+
8+
"github.com/redis/go-redis/v9"
9+
)
10+
11+
// RedisCache is used to store/fetch ip proximity from redis.
12+
type RedisCache struct {
13+
redisClient *redis.Client
14+
redisOptions *RedisOptions
15+
}
16+
17+
// RedisOptions holds redis configuration parameters.
18+
type RedisOptions struct {
19+
Addr string
20+
Password string
21+
DB int
22+
TTL time.Duration
23+
}
24+
25+
// NewRedisCache provides a new redis cache client.
26+
func NewRedisCache(redisOpts *RedisOptions) *RedisCache {
27+
return &RedisCache{
28+
redisClient: redis.NewClient(&redis.Options{
29+
Addr: redisOpts.Addr,
30+
Password: redisOpts.Password,
31+
DB: redisOpts.DB,
32+
}),
33+
redisOptions: redisOpts,
34+
}
35+
}
36+
37+
// Get gets value from redis.
38+
func (r *RedisCache) Get(ctx context.Context, key string) (bool, bool, error) {
39+
val, err := r.redisClient.Get(ctx, key).Result()
40+
if err != nil {
41+
// If key is not in redis
42+
if err == redis.Nil {
43+
return false, false, nil
44+
}
45+
return false, false, err
46+
}
47+
isIPAddressNear, err := strconv.ParseBool(val)
48+
if err != nil {
49+
return false, false, err
50+
}
51+
52+
return isIPAddressNear, true, nil
53+
}
54+
55+
// Set sets k/v in redis.
56+
func (r *RedisCache) Set(ctx context.Context, key string, value bool) error {
57+
// Redis stores false as 0 for whatever reason, so we'll store as a string and parse it out
58+
return r.redisClient.Set(ctx, key, strconv.FormatBool(value), r.redisOptions.TTL).Err()
59+
}

0 commit comments

Comments
 (0)