Files
anthropic-proxy/internal/ratelimit/usage.go
T
Alexander 0df28e9dd8 refactor: modularize codebase — deduplicate, extract, clean up
- Unify duplicate uTLS transports into shared internal/transport package
- Extract shared version constant into internal/version
- Move LoadDefaultCredentials from config to auth (remove config→auth import)
- Deduplicate handler.go: extract telemetry/error helpers (324→268 lines)
- Break up main.go::run() into initCredential/initEmbedded
- Eliminate logging.Config duplication (use config.LoggingConfig directly)
- Extract logWriter to embedded/log.go, SSE fixtures to consts in sniff.go
- Use uTLS client for usage polling (consistent TLS fingerprint)
- Handle sjson.SetBytes errors in sanitize.go instead of silently swallowing
- Document reverse-engineered magic values in billing.go
- Unexport Credential.CooldownUntil (internal state)
- Replace hardcoded auth bypass paths with map in server.go
2026-04-15 11:01:29 +02:00

68 lines
1.8 KiB
Go

package ratelimit
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/fujin/anthropic-proxy/internal/transport"
"github.com/fujin/anthropic-proxy/internal/version"
)
var usageClient = transport.NewHTTPClient(10 * time.Second)
const usageURL = "https://api.anthropic.com/api/oauth/usage"
type RateLimit struct {
Utilization *float64 `json:"utilization"` // 0-100
ResetsAt *string `json:"resets_at"` // ISO 8601
}
type ExtraUsage struct {
IsEnabled bool `json:"is_enabled"`
MonthlyLimit *float64 `json:"monthly_limit"`
UsedCredits *float64 `json:"used_credits"`
Utilization *float64 `json:"utilization"`
}
type UsageResponse struct {
FiveHour *RateLimit `json:"five_hour"`
SevenDay *RateLimit `json:"seven_day"`
SevenDaySonnet *RateLimit `json:"seven_day_sonnet"`
ExtraUsage *ExtraUsage `json:"extra_usage"`
}
func fetchUsage(ctx context.Context, token string) (*UsageResponse, error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, usageURL, nil)
if err != nil {
return nil, fmt.Errorf("build request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("anthropic-beta", "oauth-2025-04-20")
req.Header.Set("User-Agent", "claude-cli/"+version.ClaudeCodeFallback)
resp, err := usageClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request: %w", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("usage returned %d: %s", resp.StatusCode, string(body))
}
var usage UsageResponse
if err := json.Unmarshal(body, &usage); err != nil {
return nil, fmt.Errorf("decode: %w", err)
}
return &usage, nil
}