mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-09-24 16:04:35 +08:00
Refactor provider usage tracking to utilize recent requests data
- Introduced `useProviderRecentRequests` hook to manage recent request data for providers. - Replaced usage of `useProviderStats` with `useProviderRecentRequests` in relevant components. - Updated `VertexSection` and other provider components to consume recent request data instead of key stats. - Removed obsolete `useProviderStats` hook and related usage details. - Added new utility functions for handling recent request data, including normalization and aggregation. - Updated API service to fetch recent request usage data. - Refactored `AuthFileCard` and related components to utilize recent request statistics. - Cleaned up unused code and types related to previous usage stats implementation.
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
import type { StatusBarData, StatusBlockDetail, StatusBlockState } from '@/utils/usage';
|
||||
|
||||
export type { StatusBarData, StatusBlockDetail, StatusBlockState };
|
||||
|
||||
export interface RecentRequestBucket {
|
||||
time?: string;
|
||||
success: number;
|
||||
failed: number;
|
||||
}
|
||||
|
||||
export type ApiKeyUsageResponse = Record<string, Record<string, RecentRequestBucket[]>>;
|
||||
|
||||
const RECENT_REQUEST_BLOCK_COUNT = 20;
|
||||
const RECENT_REQUEST_BLOCK_DURATION_MS = 10 * 60 * 1000;
|
||||
|
||||
const toFiniteNumber = (value: unknown): number => {
|
||||
const numberValue = typeof value === 'number' ? value : Number(value);
|
||||
return Number.isFinite(numberValue) ? numberValue : 0;
|
||||
};
|
||||
|
||||
export function buildRecentRequestCompositeKey(baseUrl: unknown, apiKey: unknown): string {
|
||||
const normalizedBaseUrl = String(baseUrl ?? '').trim();
|
||||
const normalizedApiKey = String(apiKey ?? '').trim();
|
||||
return `${normalizedBaseUrl}|${normalizedApiKey}`;
|
||||
}
|
||||
|
||||
export function normalizeRecentRequestAuthIndex(value: unknown): string | null {
|
||||
if (typeof value === 'number' && Number.isFinite(value)) {
|
||||
return value.toString();
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed ? trimmed : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function normalizeRecentRequestBuckets(input: unknown): RecentRequestBucket[] {
|
||||
if (!Array.isArray(input)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return input.slice(-RECENT_REQUEST_BLOCK_COUNT).map((item) => {
|
||||
const record = item && typeof item === 'object' ? (item as Record<string, unknown>) : {};
|
||||
const time = typeof record.time === 'string' ? record.time : undefined;
|
||||
|
||||
return {
|
||||
...(time ? { time } : {}),
|
||||
success: toFiniteNumber(record.success),
|
||||
failed: toFiniteNumber(record.failed),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function mergeRecentRequestBucketGroups(
|
||||
groups: RecentRequestBucket[][]
|
||||
): RecentRequestBucket[] {
|
||||
const normalizedGroups = groups
|
||||
.map((group) => normalizeRecentRequestBuckets(group))
|
||||
.filter((group) => group.length > 0);
|
||||
|
||||
if (normalizedGroups.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const mergedLength = Math.min(
|
||||
RECENT_REQUEST_BLOCK_COUNT,
|
||||
Math.max(...normalizedGroups.map((group) => group.length))
|
||||
);
|
||||
const merged: RecentRequestBucket[] = Array.from({ length: mergedLength }, () => ({
|
||||
success: 0,
|
||||
failed: 0,
|
||||
}));
|
||||
|
||||
normalizedGroups.forEach((group) => {
|
||||
const tail = group.slice(-mergedLength);
|
||||
const offset = mergedLength - tail.length;
|
||||
|
||||
tail.forEach((bucket, index) => {
|
||||
const target = merged[offset + index];
|
||||
target.success += bucket.success;
|
||||
target.failed += bucket.failed;
|
||||
if (!target.time && bucket.time) {
|
||||
target.time = bucket.time;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function sumRecentRequests(
|
||||
buckets: RecentRequestBucket[]
|
||||
): { success: number; failure: number } {
|
||||
return normalizeRecentRequestBuckets(buckets).reduce(
|
||||
(total, bucket) => ({
|
||||
success: total.success + bucket.success,
|
||||
failure: total.failure + bucket.failed,
|
||||
}),
|
||||
{ success: 0, failure: 0 }
|
||||
);
|
||||
}
|
||||
|
||||
export function statusBarDataFromRecentRequests(buckets: RecentRequestBucket[]): StatusBarData {
|
||||
const normalizedBuckets = normalizeRecentRequestBuckets(buckets);
|
||||
const emptyBucketCount = Math.max(0, RECENT_REQUEST_BLOCK_COUNT - normalizedBuckets.length);
|
||||
const blockStats = [
|
||||
...Array.from({ length: emptyBucketCount }, () => ({ success: 0, failed: 0 })),
|
||||
...normalizedBuckets.slice(-RECENT_REQUEST_BLOCK_COUNT),
|
||||
];
|
||||
|
||||
const now = Date.now();
|
||||
const windowStart = now - RECENT_REQUEST_BLOCK_COUNT * RECENT_REQUEST_BLOCK_DURATION_MS;
|
||||
|
||||
const blocks: StatusBlockState[] = [];
|
||||
const blockDetails: StatusBarData['blockDetails'] = [];
|
||||
let totalSuccess = 0;
|
||||
let totalFailure = 0;
|
||||
|
||||
blockStats.forEach((bucket, index) => {
|
||||
const success = bucket.success;
|
||||
const failure = bucket.failed;
|
||||
const total = success + failure;
|
||||
|
||||
totalSuccess += success;
|
||||
totalFailure += failure;
|
||||
|
||||
if (total === 0) {
|
||||
blocks.push('idle');
|
||||
} else if (failure === 0) {
|
||||
blocks.push('success');
|
||||
} else if (success === 0) {
|
||||
blocks.push('failure');
|
||||
} else {
|
||||
blocks.push('mixed');
|
||||
}
|
||||
|
||||
const blockStartTime = windowStart + index * RECENT_REQUEST_BLOCK_DURATION_MS;
|
||||
blockDetails.push({
|
||||
success,
|
||||
failure,
|
||||
rate: total > 0 ? success / total : -1,
|
||||
startTime: blockStartTime,
|
||||
endTime: blockStartTime + RECENT_REQUEST_BLOCK_DURATION_MS,
|
||||
});
|
||||
});
|
||||
|
||||
const total = totalSuccess + totalFailure;
|
||||
|
||||
return {
|
||||
blocks,
|
||||
blockDetails,
|
||||
successRate: total > 0 ? (totalSuccess / total) * 100 : 100,
|
||||
totalSuccess,
|
||||
totalFailure,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user