Feat: refreshcache

pull/31/head
zijiren233 2 years ago
parent b5151fa2fc
commit 12bcae22f5

@ -0,0 +1,48 @@
package refreshcache
import (
"sync"
"time"
)
type RefreshCache[T any] struct {
lock sync.RWMutex
last time.Time
maxAge time.Duration
refreshFunc func() (T, error)
data T
}
func NewRefreshCache[T any](refreshFunc func() (T, error), maxAge time.Duration) *RefreshCache[T] {
if refreshFunc == nil {
panic("refreshFunc cannot be nil")
}
if maxAge <= 0 {
panic("maxAge must be positive")
}
return &RefreshCache[T]{
refreshFunc: refreshFunc,
maxAge: maxAge,
}
}
func (r *RefreshCache[T]) Get() (data T, err error) {
r.lock.RLock()
if time.Since(r.last) < r.maxAge {
r.lock.RUnlock()
return r.data, nil
}
r.lock.RUnlock()
r.lock.Lock()
defer r.lock.Unlock()
if time.Since(r.last) < r.maxAge {
return r.data, nil
}
defer func() {
if err == nil {
r.data = data
r.last = time.Now()
}
}()
return r.refreshFunc()
}

@ -3,58 +3,46 @@ package bilibili
import ( import (
"errors" "errors"
"net/http" "net/http"
"sync"
"time" "time"
json "github.com/json-iterator/go" json "github.com/json-iterator/go"
"github.com/synctv-org/synctv/utils" "github.com/synctv-org/synctv/utils"
refreshcache "github.com/synctv-org/synctv/utils/refreshCache"
) )
var ( type buvid struct {
bLock sync.RWMutex b3, b4 string
b3, b4 string }
bLastUpdateTime time.Time
) var buvidCache = refreshcache.NewRefreshCache[buvid](func() (buvid, error) {
b3, b4, err := newBuvid()
if err != nil {
return buvid{}, err
}
return buvid{
b3: b3,
b4: b4,
}, nil
}, time.Hour)
func getBuvidCookies() ([]*http.Cookie, error) { func getBuvidCookies() ([]*http.Cookie, error) {
b3, b4, err := getBuvid() buvid, err := buvidCache.Get()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return []*http.Cookie{ return []*http.Cookie{
{ {
Name: "buvid3", Name: "buvid3",
Value: b3, Value: buvid.b3,
}, },
{ {
Name: "buvid4", Name: "buvid4",
Value: b4, Value: buvid.b4,
}, },
}, nil }, nil
} }
func getBuvid() (string, string, error) { type spiResp struct {
bLock.RLock()
if time.Since(bLastUpdateTime) < time.Hour {
bLock.RUnlock()
return b3, b4, nil
}
bLock.RUnlock()
bLock.Lock()
defer bLock.Unlock()
if time.Since(bLastUpdateTime) < time.Hour {
return b3, b4, nil
}
var err error
b3, b4, err = newBuvid()
if err != nil {
return "", "", err
}
bLastUpdateTime = time.Now()
return b3, b4, nil
}
type buvid struct {
Code int `json:"code"` Code int `json:"code"`
Data struct { Data struct {
B3 string `json:"b_3"` B3 string `json:"b_3"`
@ -75,7 +63,7 @@ func newBuvid() (string, string, error) {
return "", "", err return "", "", err
} }
defer resp.Body.Close() defer resp.Body.Close()
var b buvid var b spiResp
err = json.NewDecoder(resp.Body).Decode(&b) err = json.NewDecoder(resp.Body).Decode(&b)
if err != nil { if err != nil {
return "", "", err return "", "", err

@ -8,11 +8,11 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
json "github.com/json-iterator/go" json "github.com/json-iterator/go"
"github.com/synctv-org/synctv/utils" "github.com/synctv-org/synctv/utils"
refreshcache "github.com/synctv-org/synctv/utils/refreshCache"
) )
var ( var (
@ -22,17 +22,25 @@ var (
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
36, 20, 34, 44, 52, 36, 20, 34, 44, 52,
} }
lock sync.RWMutex wbiCache = refreshcache.NewRefreshCache[key](func() (key, error) {
imgKey, subKey string imgKey, subKey, err := getWbiKeys()
lastUpdateTime time.Time if err != nil {
return key{}, err
}
return key{imgKey, subKey}, nil
}, time.Minute*10)
) )
type key struct {
imgKey, subKey string
}
func signAndGenerateURL(urlStr string) (string, error) { func signAndGenerateURL(urlStr string) (string, error) {
urlObj, err := url.Parse(urlStr) urlObj, err := url.Parse(urlStr)
if err != nil { if err != nil {
return "", err return "", err
} }
imgKey, subKey, err := getWbiKeysCached() key, err := wbiCache.Get()
if err != nil { if err != nil {
return "", err return "", err
} }
@ -41,7 +49,7 @@ func signAndGenerateURL(urlStr string) (string, error) {
for k, v := range query { for k, v := range query {
params[k] = v[0] params[k] = v[0]
} }
newParams := encWbi(params, imgKey, subKey) newParams := encWbi(params, key.imgKey, key.subKey)
for k, v := range newParams { for k, v := range newParams {
query.Set(k, v) query.Set(k, v)
} }
@ -94,27 +102,6 @@ func sanitizeString(s string) string {
return s return s
} }
func getWbiKeysCached() (string, string, error) {
lock.RLock()
if time.Since(lastUpdateTime).Minutes() < 10 {
defer lock.RUnlock()
return imgKey, subKey, nil
}
lock.RUnlock()
lock.Lock()
defer lock.Unlock()
if time.Since(lastUpdateTime).Minutes() < 10 {
return imgKey, subKey, nil
}
var err error
imgKey, subKey, err = getWbiKeys()
if err != nil {
return "", "", err
}
lastUpdateTime = time.Now()
return imgKey, subKey, nil
}
func getWbiKeys() (string, string, error) { func getWbiKeys() (string, string, error) {
req, err := http.NewRequest(http.MethodGet, "https://api.bilibili.com/x/web-interface/nav", nil) req, err := http.NewRequest(http.MethodGet, "https://api.bilibili.com/x/web-interface/nav", nil)
if err != nil { if err != nil {

Loading…
Cancel
Save