refactor: extract proxy token store
This commit is contained in:
69
internal/playback/proxy_tokens.go
Normal file
69
internal/playback/proxy_tokens.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package playback
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type proxyTokenTarget struct {
|
||||
targetURL string
|
||||
referer string
|
||||
scope string
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
type proxyTokenStore struct {
|
||||
mu sync.Mutex
|
||||
tokens map[string]proxyTokenTarget
|
||||
}
|
||||
|
||||
func newProxyTokenStore() *proxyTokenStore {
|
||||
return &proxyTokenStore{
|
||||
tokens: make(map[string]proxyTokenTarget),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *proxyTokenStore) create(targetURL, referer, scope string, ttl time.Duration, now time.Time) (string, error) {
|
||||
tokenBytes := make([]byte, 32)
|
||||
if _, err := rand.Read(tokenBytes); err != nil {
|
||||
return "", fmt.Errorf("generate proxy token: %w", err)
|
||||
}
|
||||
|
||||
token := base64.RawURLEncoding.EncodeToString(tokenBytes)
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.pruneExpiredLocked(now)
|
||||
s.tokens[token] = proxyTokenTarget{
|
||||
targetURL: targetURL,
|
||||
referer: referer,
|
||||
scope: scope,
|
||||
expiresAt: now.Add(ttl),
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (s *proxyTokenStore) resolve(token string, now time.Time) (proxyTokenTarget, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
target, ok := s.tokens[token]
|
||||
if !ok {
|
||||
return proxyTokenTarget{}, fmt.Errorf("invalid proxy token")
|
||||
}
|
||||
if !target.expiresAt.After(now) {
|
||||
delete(s.tokens, token)
|
||||
return proxyTokenTarget{}, fmt.Errorf("proxy token expired")
|
||||
}
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (s *proxyTokenStore) pruneExpiredLocked(now time.Time) {
|
||||
for token, target := range s.tokens {
|
||||
if !target.expiresAt.After(now) {
|
||||
delete(s.tokens, token)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@ package playback
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -19,7 +17,6 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@@ -38,66 +35,6 @@ type playbackService struct {
|
||||
|
||||
type ProxyTokenKey string
|
||||
|
||||
type proxyTokenTarget struct {
|
||||
targetURL string
|
||||
referer string
|
||||
scope string
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
type proxyTokenStore struct {
|
||||
mu sync.Mutex
|
||||
tokens map[string]proxyTokenTarget
|
||||
}
|
||||
|
||||
func newProxyTokenStore() *proxyTokenStore {
|
||||
return &proxyTokenStore{
|
||||
tokens: make(map[string]proxyTokenTarget),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *proxyTokenStore) create(targetURL, referer, scope string, ttl time.Duration, now time.Time) (string, error) {
|
||||
tokenBytes := make([]byte, 32)
|
||||
if _, err := rand.Read(tokenBytes); err != nil {
|
||||
return "", fmt.Errorf("generate proxy token: %w", err)
|
||||
}
|
||||
|
||||
token := base64.RawURLEncoding.EncodeToString(tokenBytes)
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.pruneExpiredLocked(now)
|
||||
s.tokens[token] = proxyTokenTarget{
|
||||
targetURL: targetURL,
|
||||
referer: referer,
|
||||
scope: scope,
|
||||
expiresAt: now.Add(ttl),
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (s *proxyTokenStore) resolve(token string, now time.Time) (proxyTokenTarget, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
target, ok := s.tokens[token]
|
||||
if !ok {
|
||||
return proxyTokenTarget{}, fmt.Errorf("invalid proxy token")
|
||||
}
|
||||
if !target.expiresAt.After(now) {
|
||||
delete(s.tokens, token)
|
||||
return proxyTokenTarget{}, fmt.Errorf("proxy token expired")
|
||||
}
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (s *proxyTokenStore) pruneExpiredLocked(now time.Time) {
|
||||
for token, target := range s.tokens {
|
||||
if !target.expiresAt.After(now) {
|
||||
delete(s.tokens, token)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewPlaybackService(repo domain.PlaybackRepository, providers []domain.Provider, jikan *jikan.Client, episodes domain.EpisodeService, auditSvc domain.AuditService, proxyTokenKey ProxyTokenKey) domain.PlaybackService {
|
||||
return &playbackService{
|
||||
repo: repo,
|
||||
|
||||
Reference in New Issue
Block a user