mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-19 06:14:45 +08:00
fix(usage): use real reset header for session window instead of prediction
The 5h window reset time displayed for Setup Token accounts was inaccurate because UpdateSessionWindow predicted the window end as "current hour + 5h" instead of reading the actual `anthropic-ratelimit-unified-5h-reset` response header. This caused the countdown to differ from the official Claude page. Backend: parse the reset header (Unix timestamp) and use it as the real window end, falling back to the hour-truncated prediction only when the header is absent. Also correct stale predictions when a subsequent request provides the real reset time. Frontend: add a reactive 60s timer so the reset countdown in UsageProgressBar ticks down in real-time instead of freezing at the initial value. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1051,16 +1051,32 @@ func (s *RateLimitService) UpdateSessionWindow(ctx context.Context, account *Acc
|
||||
var windowStart, windowEnd *time.Time
|
||||
needInitWindow := account.SessionWindowEnd == nil || time.Now().After(*account.SessionWindowEnd)
|
||||
|
||||
if needInitWindow && (status == "allowed" || status == "allowed_warning") {
|
||||
// 预测时间窗口:从当前时间的整点开始,+5小时为结束
|
||||
// 例如:现在是 14:30,窗口为 14:00 ~ 19:00
|
||||
// 优先使用响应头中的真实重置时间(比预测更准确)
|
||||
if resetStr := headers.Get("anthropic-ratelimit-unified-5h-reset"); resetStr != "" {
|
||||
if ts, err := strconv.ParseInt(resetStr, 10, 64); err == nil {
|
||||
end := time.Unix(ts, 0)
|
||||
// 窗口需要初始化,或者真实重置时间与已存储的不同,则更新
|
||||
if needInitWindow || account.SessionWindowEnd == nil || !end.Equal(*account.SessionWindowEnd) {
|
||||
start := end.Add(-5 * time.Hour)
|
||||
windowStart = &start
|
||||
windowEnd = &end
|
||||
slog.Info("account_session_window_from_header", "account_id", account.ID, "window_start", start, "window_end", end, "status", status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 回退:如果没有真实重置时间且需要初始化窗口,使用预测
|
||||
if windowEnd == nil && needInitWindow && (status == "allowed" || status == "allowed_warning") {
|
||||
now := time.Now()
|
||||
start := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
end := start.Add(5 * time.Hour)
|
||||
windowStart = &start
|
||||
windowEnd = &end
|
||||
slog.Info("account_session_window_initialized", "account_id", account.ID, "window_start", start, "window_end", end, "status", status)
|
||||
// 窗口重置时清除旧的 utilization,避免残留上个窗口的数据
|
||||
}
|
||||
|
||||
// 窗口重置时清除旧的 utilization,避免残留上个窗口的数据
|
||||
if windowEnd != nil && needInitWindow {
|
||||
_ = s.accountRepo.UpdateExtra(ctx, account.ID, map[string]any{
|
||||
"session_window_utilization": nil,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user