b0dc9df887
- Implemented `GetAPIKeyUsage` to expose recent request data grouped by provider and API key. - Added supporting function `mergeRecentRequestBuckets` for bucket aggregation. - Registered new endpoint `/v0/management/api-key-usage` in the management API. - Included extensive unit tests for provider and key-based grouping validation. - Updated `formatRecentRequestBucketLabel` to support configurable bucket duration.
87 lines
2.0 KiB
Go
87 lines
2.0 KiB
Go
package management
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
|
)
|
|
|
|
func mergeRecentRequestBuckets(dst, src []coreauth.RecentRequestBucket) []coreauth.RecentRequestBucket {
|
|
if len(dst) == 0 {
|
|
return src
|
|
}
|
|
if len(src) == 0 {
|
|
return dst
|
|
}
|
|
if len(dst) != len(src) {
|
|
n := len(dst)
|
|
if len(src) < n {
|
|
n = len(src)
|
|
}
|
|
for i := 0; i < n; i++ {
|
|
dst[i].Success += src[i].Success
|
|
dst[i].Failed += src[i].Failed
|
|
}
|
|
return dst
|
|
}
|
|
for i := range dst {
|
|
dst[i].Success += src[i].Success
|
|
dst[i].Failed += src[i].Failed
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// GetAPIKeyUsage returns recent request buckets for all in-memory api_key auths,
|
|
// grouped by provider and keyed by the raw api-key value.
|
|
func (h *Handler) GetAPIKeyUsage(c *gin.Context) {
|
|
if h == nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "handler not initialized"})
|
|
return
|
|
}
|
|
|
|
h.mu.Lock()
|
|
manager := h.authManager
|
|
h.mu.Unlock()
|
|
if manager == nil {
|
|
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "core auth manager unavailable"})
|
|
return
|
|
}
|
|
|
|
now := time.Now()
|
|
out := make(map[string]map[string][]coreauth.RecentRequestBucket)
|
|
for _, auth := range manager.List() {
|
|
if auth == nil {
|
|
continue
|
|
}
|
|
kind, apiKey := auth.AccountInfo()
|
|
if !strings.EqualFold(strings.TrimSpace(kind), "api_key") {
|
|
continue
|
|
}
|
|
apiKey = strings.TrimSpace(apiKey)
|
|
if apiKey == "" {
|
|
continue
|
|
}
|
|
provider := strings.ToLower(strings.TrimSpace(auth.Provider))
|
|
if provider == "" {
|
|
provider = "unknown"
|
|
}
|
|
|
|
recent := auth.RecentRequestsSnapshot(now)
|
|
providerBucket, ok := out[provider]
|
|
if !ok {
|
|
providerBucket = make(map[string][]coreauth.RecentRequestBucket)
|
|
out[provider] = providerBucket
|
|
}
|
|
if existing, exists := providerBucket[apiKey]; exists {
|
|
providerBucket[apiKey] = mergeRecentRequestBuckets(existing, recent)
|
|
continue
|
|
}
|
|
providerBucket[apiKey] = recent
|
|
}
|
|
|
|
c.JSON(http.StatusOK, out)
|
|
}
|