Skip to content

Commit 43d7a1e

Browse files
committed
feat: use in-memory cache instead of Redis
1 parent f163a43 commit 43d7a1e

File tree

7 files changed

+41
-101
lines changed

7 files changed

+41
-101
lines changed

README.md

-4
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,11 @@ env CGO_ENABLED=0 go install -trimpath -ldflags="-s -w" github.com/RoyXiang/plex
2828

2929
1. Configure environment variables in your preferred way
3030
- `PLEX_BASEURL` (Required, e.g. `http://127.0.0.1:32400`)
31-
- `REDIS_URL` (Optional, e.g. `redis://127.0.0.1:6379`)
32-
* If you need a cache layer, set a value for it
3331
- `PLAXT_URL` (Optional, e.g. `https://plaxt.astandke.com/api?id=generate-your-own-silly`)
3432
* `PLEX_TOKEN` is required
3533
* Set it if you run an instance of [Plaxt](https://github.com/XanderStrike/goplaxt)
3634
* Or, you can set it to [the official one](https://plaxt.astandke.com/)
3735
- `PLEX_TOKEN` (Optional, if you need it, see [here](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/))
38-
- `STATIC_CACHE_TTL` (Optional, default: `1h`, which controls the cache TTL of static files)
39-
- `DYNAMIC_CACHE_TTL` (Optional, default: `1s`, which controls the cache TTL of dynamic requests)
4036
- `REDIRECT_WEB_APP` (Optional, default: `true`)
4137
- `DISABLE_TRANSCODE` (Optional, default: `true`)
4238
- `NO_REQUEST_LOGS` (Optional, default: `false`)

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ module github.com/RoyXiang/plexproxy
33
go 1.17
44

55
require (
6+
github.com/bluele/gcache v0.0.2
67
github.com/go-chi/chi/v5 v5.0.10
7-
github.com/go-redis/redis/v8 v8.11.5
88
github.com/gorilla/handlers v1.5.2
99
github.com/gorilla/mux v1.8.1
1010
github.com/jrudio/go-plex-client v0.0.0-20220106065909-9e1d590b99aa
1111
github.com/xanderstrike/plexhooks v0.0.0-20200926011736-c63bcd35fe3e
1212
)
1313

1414
require (
15-
github.com/cespare/xxhash/v2 v2.1.2 // indirect
16-
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
1715
github.com/felixge/httpsnoop v1.0.3 // indirect
1816
github.com/google/uuid v1.3.0 // indirect
1917
github.com/gorilla/websocket v1.5.0 // indirect
18+
github.com/onsi/ginkgo v1.16.5 // indirect
19+
github.com/onsi/gomega v1.18.1 // indirect
2020
)
2121

2222
replace github.com/jrudio/go-plex-client v0.0.0-20220106065909-9e1d590b99aa => github.com/RoyXiang/go-plex-client v0.0.0-20220313053419-e24ff7ada173

go.sum

+2-7
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
44
github.com/RoyXiang/go-plex-client v0.0.0-20220313053419-e24ff7ada173 h1:/GJ+g7nvyg3HjY+J4p5Ag+TUoWjIrJxpHWzdbA4Phzw=
55
github.com/RoyXiang/go-plex-client v0.0.0-20220313053419-e24ff7ada173/go.mod h1:twidbPLE4eUk3CgDno5uCzpnPRboBTElH+iJrQO7S4w=
66
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
7-
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
7+
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
8+
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
89
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
910
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
10-
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
11-
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
1211
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
1312
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
1413
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -22,8 +21,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
2221
github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M=
2322
github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug=
2423
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
25-
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
26-
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
2724
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
2825
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
2926
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
@@ -32,8 +29,6 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
3229
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
3330
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
3431
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
35-
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
36-
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
3732
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
3833
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
3934
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=

handler/main.go

+17-31
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,12 @@ import (
66
"os"
77

88
"github.com/go-chi/chi/v5/middleware"
9-
"github.com/go-redis/redis/v8"
109
"github.com/gorilla/handlers"
1110
"github.com/gorilla/mux"
1211
)
1312

1413
var (
15-
plexClient *PlexClient
16-
redisClient *redis.Client
14+
plexClient *PlexClient
1715

1816
emptyStruct = struct{}{}
1917
)
@@ -23,23 +21,13 @@ func init() {
2321
BaseUrl: os.Getenv("PLEX_BASEURL"),
2422
Token: os.Getenv("PLEX_TOKEN"),
2523
PlaxtUrl: os.Getenv("PLAXT_URL"),
26-
StaticCacheTtl: os.Getenv("STATIC_CACHE_TTL"),
27-
DynamicCacheTtl: os.Getenv("DYNAMIC_CACHE_TTL"),
2824
RedirectWebApp: os.Getenv("REDIRECT_WEB_APP"),
2925
DisableTranscode: os.Getenv("DISABLE_TRANSCODE"),
3026
NoRequestLogs: os.Getenv("NO_REQUEST_LOGS"),
3127
})
3228
if plexClient == nil {
3329
log.Fatalln("Please configure PLEX_BASEURL as a valid URL at first")
3430
}
35-
36-
redisUrl := os.Getenv("REDIS_URL")
37-
if redisUrl != "" {
38-
options, err := redis.ParseURL(redisUrl)
39-
if err == nil {
40-
redisClient = redis.NewClient(options)
41-
}
42-
}
4331
}
4432

4533
func NewRouter() http.Handler {
@@ -50,24 +38,22 @@ func NewRouter() http.Handler {
5038
}
5139
r.Use(wrapMiddleware, middleware.Recoverer, trafficMiddleware)
5240

53-
if redisClient != nil {
54-
// bypass cache
55-
r.PathPrefix("/:/").Handler(plexClient)
56-
r.PathPrefix("/library/parts/").Handler(plexClient)
57-
58-
staticRouter := r.Methods(http.MethodGet).Subrouter()
59-
staticRouter.Use(staticMiddleware)
60-
staticRouter.Path("/library/media/{key}/chapterImages/{id}").Handler(plexClient)
61-
staticRouter.Path("/library/metadata/{key}/art/{id}").Handler(plexClient)
62-
staticRouter.Path("/library/metadata/{key}/thumb/{id}").Handler(plexClient)
63-
staticRouter.Path("/photo/:/transcode").Handler(plexClient)
64-
staticRouter.PathPrefix("/web/js/").Handler(plexClient)
65-
staticRouter.PathPrefix("/web/static/").Handler(plexClient)
66-
67-
dynamicRouter := r.Methods(http.MethodGet).Subrouter()
68-
dynamicRouter.Use(dynamicMiddleware)
69-
dynamicRouter.PathPrefix("/").Handler(plexClient)
70-
}
41+
// bypass cache
42+
r.PathPrefix("/:/").Handler(plexClient)
43+
r.PathPrefix("/library/parts/").Handler(plexClient)
44+
45+
staticRouter := r.Methods(http.MethodGet).Subrouter()
46+
staticRouter.Use(staticMiddleware)
47+
staticRouter.Path("/library/media/{key}/chapterImages/{id}").Handler(plexClient)
48+
staticRouter.Path("/library/metadata/{key}/art/{id}").Handler(plexClient)
49+
staticRouter.Path("/library/metadata/{key}/thumb/{id}").Handler(plexClient)
50+
staticRouter.Path("/photo/:/transcode").Handler(plexClient)
51+
staticRouter.PathPrefix("/web/js/").Handler(plexClient)
52+
staticRouter.PathPrefix("/web/static/").Handler(plexClient)
53+
54+
dynamicRouter := r.Methods(http.MethodGet).Subrouter()
55+
dynamicRouter.Use(dynamicMiddleware)
56+
dynamicRouter.PathPrefix("/").Handler(plexClient)
7157

7258
r.PathPrefix("/").Handler(plexClient)
7359
return r

handler/middleware.go

+12-13
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import (
88
"io"
99
"net/http"
1010
"net/http/httptest"
11+
"net/http/httputil"
1112
"net/url"
1213
"path/filepath"
1314
"strconv"
1415
"strings"
1516
"time"
1617

1718
"github.com/RoyXiang/plexproxy/common"
19+
"github.com/bluele/gcache"
1820
)
1921

2022
var (
@@ -111,7 +113,6 @@ func staticMiddleware(next http.Handler) http.Handler {
111113
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
112114
ctx := context.WithValue(r.Context(), cacheInfoCtxKey, &cacheInfo{
113115
Prefix: cachePrefixStatic,
114-
Ttl: plexClient.staticCacheTtl,
115116
})
116117
r = r.WithContext(ctx)
117118
cacheMiddleware(next).ServeHTTP(w, r)
@@ -125,7 +126,6 @@ func dynamicMiddleware(next http.Handler) http.Handler {
125126
case ".css", ".ico", ".jpeg", ".jpg", ".webp":
126127
ctx = context.WithValue(r.Context(), cacheInfoCtxKey, &cacheInfo{
127128
Prefix: cachePrefixStatic,
128-
Ttl: plexClient.staticCacheTtl,
129129
})
130130
case ".m3u8", ".ts":
131131
ctx = r.Context()
@@ -136,7 +136,6 @@ func dynamicMiddleware(next http.Handler) http.Handler {
136136
}
137137
ctx = context.WithValue(r.Context(), cacheInfoCtxKey, &cacheInfo{
138138
Prefix: cachePrefixDynamic,
139-
Ttl: plexClient.dynamicCacheTtl,
140139
})
141140
}
142141
cacheMiddleware(next).ServeHTTP(w, r.WithContext(ctx))
@@ -151,8 +150,8 @@ func cacheMiddleware(next http.Handler) http.Handler {
151150
return
152151
}
153152

153+
var cache gcache.Cache
154154
var cacheKey string
155-
ctx := context.Background()
156155
info := ctxValue.(*cacheInfo)
157156

158157
defer func() {
@@ -161,9 +160,8 @@ func cacheMiddleware(next http.Handler) http.Handler {
161160
return
162161
}
163162
var resp *http.Response
164-
b, err := redisClient.Get(ctx, cacheKey).Bytes()
165-
if err == nil {
166-
reader := bufio.NewReader(bytes.NewReader(b))
163+
if cacheVal, err := cache.Get(cacheKey); err == nil {
164+
reader := bufio.NewReader(bytes.NewReader(cacheVal.([]byte)))
167165
resp, _ = http.ReadResponse(reader, r)
168166
}
169167
if resp == nil {
@@ -174,18 +172,18 @@ func cacheMiddleware(next http.Handler) http.Handler {
174172
w.Header().Set(headerCacheStatus, "MISS")
175173
w.WriteHeader(resp.StatusCode)
176174
_, _ = w.Write(nw.Unwrap().(*httptest.ResponseRecorder).Body.Bytes())
177-
if resp.StatusCode == http.StatusOK {
178-
writeToCache(cacheKey, resp, info.Ttl)
175+
if resp.StatusCode != http.StatusOK {
176+
return
177+
}
178+
if b, err := httputil.DumpResponse(resp, true); err == nil {
179+
cache.Set(cacheKey, b)
179180
}
180181
}()
181182
} else {
182183
defer func() {
183184
w.Header().Set(headerCacheStatus, "HIT")
184185
w.WriteHeader(resp.StatusCode)
185186
_, _ = io.Copy(w, resp.Body)
186-
if info.Prefix == cachePrefixStatic {
187-
writeToCache(cacheKey, resp, info.Ttl)
188-
}
189187
}()
190188
}
191189
for k, v := range resp.Header {
@@ -195,7 +193,7 @@ func cacheMiddleware(next http.Handler) http.Handler {
195193
params := r.URL.Query()
196194
switch info.Prefix {
197195
case cachePrefixStatic:
198-
break
196+
cache = plexClient.staticCache
199197
case cachePrefixDynamic:
200198
if user := r.Context().Value(userCtxKey); user != nil {
201199
params.Set(headerUserId, strconv.Itoa(user.(*plexUser).Id))
@@ -205,6 +203,7 @@ func cacheMiddleware(next http.Handler) http.Handler {
205203
} else {
206204
return
207205
}
206+
cache = plexClient.dynamicCache
208207
default:
209208
// invalid prefix
210209
return

handler/plex.go

+7-33
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package handler
22

33
import (
44
"bytes"
5-
"context"
65
"crypto/tls"
76
"encoding/json"
87
"fmt"
@@ -16,6 +15,7 @@ import (
1615
"time"
1716

1817
"github.com/RoyXiang/plexproxy/common"
18+
"github.com/bluele/gcache"
1919
"github.com/jrudio/go-plex-client"
2020
"github.com/xanderstrike/plexhooks"
2121
)
@@ -35,8 +35,8 @@ type PlexClient struct {
3535
proxy *httputil.ReverseProxy
3636
client *plex.Plex
3737

38-
staticCacheTtl time.Duration
39-
dynamicCacheTtl time.Duration
38+
staticCache gcache.Cache
39+
dynamicCache gcache.Cache
4040

4141
plaxtUrl string
4242
redirectWebApp bool
@@ -78,14 +78,8 @@ func NewPlexClient(config PlexConfig) *PlexClient {
7878
plaxtUrl = u.String()
7979
}
8080

81-
staticCacheTtl, err := time.ParseDuration(config.StaticCacheTtl)
82-
if err != nil {
83-
staticCacheTtl = time.Hour
84-
}
85-
dynamicCacheTtl, err := time.ParseDuration(config.DynamicCacheTtl)
86-
if err != nil {
87-
dynamicCacheTtl = time.Second
88-
}
81+
staticCache := gcache.New(1000).LFU().Build()
82+
dynamicCache := gcache.New(100).LRU().Expiration(time.Second).Build()
8983

9084
var redirectWebApp, disableTranscode, noRequestLogs bool
9185
if b, err := strconv.ParseBool(config.RedirectWebApp); err == nil {
@@ -108,8 +102,8 @@ func NewPlexClient(config PlexConfig) *PlexClient {
108102
proxy: proxy,
109103
client: client,
110104
plaxtUrl: plaxtUrl,
111-
staticCacheTtl: staticCacheTtl,
112-
dynamicCacheTtl: dynamicCacheTtl,
105+
staticCache: staticCache,
106+
dynamicCache: dynamicCache,
113107
redirectWebApp: redirectWebApp,
114108
disableTranscode: disableTranscode,
115109
NoRequestLogs: noRequestLogs,
@@ -192,28 +186,12 @@ func (c *PlexClient) fetchUsers(token string) {
192186
c.MulLock.Lock(lockKeyUsers)
193187
defer c.MulLock.Unlock(lockKeyUsers)
194188

195-
ctx := context.Background()
196-
cacheKey := fmt.Sprintf("%s:token:%s", cachePrefixPlex, token)
197-
isCacheEnabled := redisClient != nil
198-
199-
if isCacheEnabled {
200-
var user plexUser
201-
err := redisClient.Get(ctx, cacheKey).Scan(&user)
202-
if err == nil {
203-
c.users[token] = &user
204-
return
205-
}
206-
}
207-
208189
userInfo := c.GetAccountInfo(token)
209190
if userInfo.ID > 0 {
210191
user := plexUser{
211192
Id: userInfo.ID,
212193
Username: userInfo.Username,
213194
}
214-
if isCacheEnabled {
215-
redisClient.Set(ctx, cacheKey, &user, 0).Val()
216-
}
217195
c.users[token] = &user
218196
return
219197
}
@@ -225,10 +203,6 @@ func (c *PlexClient) fetchUsers(token string) {
225203
Id: friend.UserId,
226204
Username: friend.Username,
227205
}
228-
if isCacheEnabled {
229-
cacheKey = fmt.Sprintf("%s:token:%s", cachePrefixPlex, friend.AccessToken)
230-
redisClient.Set(ctx, cacheKey, &user, 0).Val()
231-
}
232206
c.users[friend.AccessToken] = &user
233207
}
234208
}

handler/utils.go

-10
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ package handler
33
import (
44
"context"
55
"net/http"
6-
"net/http/httputil"
76
"net/url"
87
"runtime/debug"
98
"strings"
10-
"time"
119

1210
"github.com/go-chi/chi/v5/middleware"
1311
)
@@ -89,11 +87,3 @@ func getAcceptContentType(r *http.Request) string {
8987
}
9088
return contentTypeXml
9189
}
92-
93-
func writeToCache(key string, resp *http.Response, ttl time.Duration) {
94-
b, err := httputil.DumpResponse(resp, true)
95-
if err != nil {
96-
return
97-
}
98-
redisClient.Set(context.Background(), key, b, ttl)
99-
}

0 commit comments

Comments
 (0)