mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-03-30 05:04:28 +00:00
201 lines
6.3 KiB
Go
201 lines
6.3 KiB
Go
package admin
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/pkg/usagestats"
|
|
)
|
|
|
|
var (
|
|
dashboardTrendCache = newSnapshotCache(30 * time.Second)
|
|
dashboardModelStatsCache = newSnapshotCache(30 * time.Second)
|
|
dashboardGroupStatsCache = newSnapshotCache(30 * time.Second)
|
|
dashboardUsersTrendCache = newSnapshotCache(30 * time.Second)
|
|
dashboardAPIKeysTrendCache = newSnapshotCache(30 * time.Second)
|
|
)
|
|
|
|
type dashboardTrendCacheKey struct {
|
|
StartTime string `json:"start_time"`
|
|
EndTime string `json:"end_time"`
|
|
Granularity string `json:"granularity"`
|
|
UserID int64 `json:"user_id"`
|
|
APIKeyID int64 `json:"api_key_id"`
|
|
AccountID int64 `json:"account_id"`
|
|
GroupID int64 `json:"group_id"`
|
|
Model string `json:"model"`
|
|
RequestType *int16 `json:"request_type"`
|
|
Stream *bool `json:"stream"`
|
|
BillingType *int8 `json:"billing_type"`
|
|
}
|
|
|
|
type dashboardModelGroupCacheKey struct {
|
|
StartTime string `json:"start_time"`
|
|
EndTime string `json:"end_time"`
|
|
UserID int64 `json:"user_id"`
|
|
APIKeyID int64 `json:"api_key_id"`
|
|
AccountID int64 `json:"account_id"`
|
|
GroupID int64 `json:"group_id"`
|
|
RequestType *int16 `json:"request_type"`
|
|
Stream *bool `json:"stream"`
|
|
BillingType *int8 `json:"billing_type"`
|
|
}
|
|
|
|
type dashboardEntityTrendCacheKey struct {
|
|
StartTime string `json:"start_time"`
|
|
EndTime string `json:"end_time"`
|
|
Granularity string `json:"granularity"`
|
|
Limit int `json:"limit"`
|
|
}
|
|
|
|
func cacheStatusValue(hit bool) string {
|
|
if hit {
|
|
return "hit"
|
|
}
|
|
return "miss"
|
|
}
|
|
|
|
func mustMarshalDashboardCacheKey(value any) string {
|
|
raw, err := json.Marshal(value)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return string(raw)
|
|
}
|
|
|
|
func snapshotPayloadAs[T any](payload any) (T, error) {
|
|
typed, ok := payload.(T)
|
|
if !ok {
|
|
var zero T
|
|
return zero, fmt.Errorf("unexpected cache payload type %T", payload)
|
|
}
|
|
return typed, nil
|
|
}
|
|
|
|
func (h *DashboardHandler) getUsageTrendCached(
|
|
ctx context.Context,
|
|
startTime, endTime time.Time,
|
|
granularity string,
|
|
userID, apiKeyID, accountID, groupID int64,
|
|
model string,
|
|
requestType *int16,
|
|
stream *bool,
|
|
billingType *int8,
|
|
) ([]usagestats.TrendDataPoint, bool, error) {
|
|
key := mustMarshalDashboardCacheKey(dashboardTrendCacheKey{
|
|
StartTime: startTime.UTC().Format(time.RFC3339),
|
|
EndTime: endTime.UTC().Format(time.RFC3339),
|
|
Granularity: granularity,
|
|
UserID: userID,
|
|
APIKeyID: apiKeyID,
|
|
AccountID: accountID,
|
|
GroupID: groupID,
|
|
Model: model,
|
|
RequestType: requestType,
|
|
Stream: stream,
|
|
BillingType: billingType,
|
|
})
|
|
entry, hit, err := dashboardTrendCache.GetOrLoad(key, func() (any, error) {
|
|
return h.dashboardService.GetUsageTrendWithFilters(ctx, startTime, endTime, granularity, userID, apiKeyID, accountID, groupID, model, requestType, stream, billingType)
|
|
})
|
|
if err != nil {
|
|
return nil, hit, err
|
|
}
|
|
trend, err := snapshotPayloadAs[[]usagestats.TrendDataPoint](entry.Payload)
|
|
return trend, hit, err
|
|
}
|
|
|
|
func (h *DashboardHandler) getModelStatsCached(
|
|
ctx context.Context,
|
|
startTime, endTime time.Time,
|
|
userID, apiKeyID, accountID, groupID int64,
|
|
requestType *int16,
|
|
stream *bool,
|
|
billingType *int8,
|
|
) ([]usagestats.ModelStat, bool, error) {
|
|
key := mustMarshalDashboardCacheKey(dashboardModelGroupCacheKey{
|
|
StartTime: startTime.UTC().Format(time.RFC3339),
|
|
EndTime: endTime.UTC().Format(time.RFC3339),
|
|
UserID: userID,
|
|
APIKeyID: apiKeyID,
|
|
AccountID: accountID,
|
|
GroupID: groupID,
|
|
RequestType: requestType,
|
|
Stream: stream,
|
|
BillingType: billingType,
|
|
})
|
|
entry, hit, err := dashboardModelStatsCache.GetOrLoad(key, func() (any, error) {
|
|
return h.dashboardService.GetModelStatsWithFilters(ctx, startTime, endTime, userID, apiKeyID, accountID, groupID, requestType, stream, billingType)
|
|
})
|
|
if err != nil {
|
|
return nil, hit, err
|
|
}
|
|
stats, err := snapshotPayloadAs[[]usagestats.ModelStat](entry.Payload)
|
|
return stats, hit, err
|
|
}
|
|
|
|
func (h *DashboardHandler) getGroupStatsCached(
|
|
ctx context.Context,
|
|
startTime, endTime time.Time,
|
|
userID, apiKeyID, accountID, groupID int64,
|
|
requestType *int16,
|
|
stream *bool,
|
|
billingType *int8,
|
|
) ([]usagestats.GroupStat, bool, error) {
|
|
key := mustMarshalDashboardCacheKey(dashboardModelGroupCacheKey{
|
|
StartTime: startTime.UTC().Format(time.RFC3339),
|
|
EndTime: endTime.UTC().Format(time.RFC3339),
|
|
UserID: userID,
|
|
APIKeyID: apiKeyID,
|
|
AccountID: accountID,
|
|
GroupID: groupID,
|
|
RequestType: requestType,
|
|
Stream: stream,
|
|
BillingType: billingType,
|
|
})
|
|
entry, hit, err := dashboardGroupStatsCache.GetOrLoad(key, func() (any, error) {
|
|
return h.dashboardService.GetGroupStatsWithFilters(ctx, startTime, endTime, userID, apiKeyID, accountID, groupID, requestType, stream, billingType)
|
|
})
|
|
if err != nil {
|
|
return nil, hit, err
|
|
}
|
|
stats, err := snapshotPayloadAs[[]usagestats.GroupStat](entry.Payload)
|
|
return stats, hit, err
|
|
}
|
|
|
|
func (h *DashboardHandler) getAPIKeyUsageTrendCached(ctx context.Context, startTime, endTime time.Time, granularity string, limit int) ([]usagestats.APIKeyUsageTrendPoint, bool, error) {
|
|
key := mustMarshalDashboardCacheKey(dashboardEntityTrendCacheKey{
|
|
StartTime: startTime.UTC().Format(time.RFC3339),
|
|
EndTime: endTime.UTC().Format(time.RFC3339),
|
|
Granularity: granularity,
|
|
Limit: limit,
|
|
})
|
|
entry, hit, err := dashboardAPIKeysTrendCache.GetOrLoad(key, func() (any, error) {
|
|
return h.dashboardService.GetAPIKeyUsageTrend(ctx, startTime, endTime, granularity, limit)
|
|
})
|
|
if err != nil {
|
|
return nil, hit, err
|
|
}
|
|
trend, err := snapshotPayloadAs[[]usagestats.APIKeyUsageTrendPoint](entry.Payload)
|
|
return trend, hit, err
|
|
}
|
|
|
|
func (h *DashboardHandler) getUserUsageTrendCached(ctx context.Context, startTime, endTime time.Time, granularity string, limit int) ([]usagestats.UserUsageTrendPoint, bool, error) {
|
|
key := mustMarshalDashboardCacheKey(dashboardEntityTrendCacheKey{
|
|
StartTime: startTime.UTC().Format(time.RFC3339),
|
|
EndTime: endTime.UTC().Format(time.RFC3339),
|
|
Granularity: granularity,
|
|
Limit: limit,
|
|
})
|
|
entry, hit, err := dashboardUsersTrendCache.GetOrLoad(key, func() (any, error) {
|
|
return h.dashboardService.GetUserUsageTrend(ctx, startTime, endTime, granularity, limit)
|
|
})
|
|
if err != nil {
|
|
return nil, hit, err
|
|
}
|
|
trend, err := snapshotPayloadAs[[]usagestats.UserUsageTrendPoint](entry.Payload)
|
|
return trend, hit, err
|
|
}
|