mirror of
https://github.com/EZ-Api/ez-api.git
synced 2026-01-13 17:47:51 +00:00
feat(stats): add usage stats and quota reset
This commit is contained in:
79
internal/service/stats.go
Normal file
79
internal/service/stats.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type StatsService struct {
|
||||
rdb *redis.Client
|
||||
}
|
||||
|
||||
type RealtimeStats struct {
|
||||
Requests int64
|
||||
Tokens int64
|
||||
LastAccessedAt *time.Time
|
||||
}
|
||||
|
||||
func NewStatsService(rdb *redis.Client) *StatsService {
|
||||
return &StatsService{rdb: rdb}
|
||||
}
|
||||
|
||||
func (s *StatsService) GetKeyRealtimeStats(ctx context.Context, tokenHash string) (RealtimeStats, error) {
|
||||
if s == nil || s.rdb == nil {
|
||||
return RealtimeStats{}, fmt.Errorf("redis client is required")
|
||||
}
|
||||
tokenHash = strings.TrimSpace(tokenHash)
|
||||
if tokenHash == "" {
|
||||
return RealtimeStats{}, fmt.Errorf("token hash required")
|
||||
}
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
reqs, err := s.rdb.Get(ctx, fmt.Sprintf("key:stats:%s:requests", tokenHash)).Int64()
|
||||
if err != nil && err != redis.Nil {
|
||||
return RealtimeStats{}, fmt.Errorf("read key requests: %w", err)
|
||||
}
|
||||
tokens, err := s.rdb.Get(ctx, fmt.Sprintf("key:stats:%s:tokens", tokenHash)).Int64()
|
||||
if err != nil && err != redis.Nil {
|
||||
return RealtimeStats{}, fmt.Errorf("read key tokens: %w", err)
|
||||
}
|
||||
lastRaw, err := s.rdb.Get(ctx, fmt.Sprintf("key:stats:%s:last_access", tokenHash)).Result()
|
||||
if err != nil && err != redis.Nil {
|
||||
return RealtimeStats{}, fmt.Errorf("read key last access: %w", err)
|
||||
}
|
||||
var lastAt *time.Time
|
||||
if lastRaw != "" {
|
||||
if sec, err := strconv.ParseInt(lastRaw, 10, 64); err == nil && sec > 0 {
|
||||
t := time.Unix(sec, 0).UTC()
|
||||
lastAt = &t
|
||||
}
|
||||
}
|
||||
return RealtimeStats{Requests: reqs, Tokens: tokens, LastAccessedAt: lastAt}, nil
|
||||
}
|
||||
|
||||
func (s *StatsService) GetMasterRealtimeStats(ctx context.Context, masterID uint) (RealtimeStats, error) {
|
||||
if s == nil || s.rdb == nil {
|
||||
return RealtimeStats{}, fmt.Errorf("redis client is required")
|
||||
}
|
||||
if masterID == 0 {
|
||||
return RealtimeStats{}, fmt.Errorf("master id required")
|
||||
}
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
reqs, err := s.rdb.Get(ctx, fmt.Sprintf("master:stats:%d:requests", masterID)).Int64()
|
||||
if err != nil && err != redis.Nil {
|
||||
return RealtimeStats{}, fmt.Errorf("read master requests: %w", err)
|
||||
}
|
||||
tokens, err := s.rdb.Get(ctx, fmt.Sprintf("master:stats:%d:tokens", masterID)).Int64()
|
||||
if err != nil && err != redis.Nil {
|
||||
return RealtimeStats{}, fmt.Errorf("read master tokens: %w", err)
|
||||
}
|
||||
return RealtimeStats{Requests: reqs, Tokens: tokens}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user