sub2api/backend/internal/service/windsurf_credentials.go
win 21325afb33
Some checks failed
CI / test (push) Failing after 10s
CI / frontend (push) Failing after 8s
CI / golangci-lint (push) Failing after 5s
Security Scan / backend-security (push) Failing after 5s
Security Scan / frontend-security (push) Failing after 4s
feat(windsurf): 补全ops日志记录与endpoint派生,对齐其他平台
- windsurf_gateway_service: 添加上游延迟/TTFT/错误上下文记录
- endpoint: DeriveUpstreamEndpoint 添加 PlatformWindsurf 分支
- ops_error_logger: guessPlatformFromPath 添加 /windsurf/ 识别
2026-04-23 20:46:27 +08:00

178 lines
6.2 KiB
Go

package service
import (
"encoding/json"
"time"
)
type WindsurfCredentials struct {
Email string `json:"email,omitempty"`
APIKey string `json:"api_key,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
IDToken string `json:"id_token,omitempty"`
SessionToken string `json:"session_token,omitempty"`
Auth1Token string `json:"auth1_token,omitempty"`
APIServerURL string `json:"api_server_url,omitempty"`
AuthMethod string `json:"auth_method,omitempty"`
Tier string `json:"tier,omitempty"`
ExpiresAt string `json:"expires_at,omitempty"`
RegisteredAt string `json:"registered_at,omitempty"`
LastRefreshAt string `json:"last_refresh_at,omitempty"`
LastReregisterAt string `json:"last_reregister_at,omitempty"`
LastErrorCode string `json:"last_error_code,omitempty"`
TokenVersion int64 `json:"_token_version,omitempty"`
}
type WindsurfExtra struct {
Profile WindsurfProfileSnapshot `json:"profile,omitempty"`
UserStatus WindsurfUserStatusSnapshot `json:"user_status,omitempty"`
Quota WindsurfQuotaSnapshot `json:"quota,omitempty"`
Refresh WindsurfRefreshState `json:"refresh,omitempty"`
Probe WindsurfProbeState `json:"probe,omitempty"`
Capabilities map[string]WindsurfModelCapability `json:"capabilities,omitempty"`
ModelMatrix map[string]WindsurfModelAvail `json:"model_matrix,omitempty"`
LSBinding WindsurfLSBinding `json:"ls_binding,omitempty"`
}
type WindsurfLSBinding struct {
ContainerID string `json:"container_id,omitempty"`
ContainerName string `json:"container_name,omitempty"`
Host string `json:"host,omitempty"`
Port int `json:"port,omitempty"`
}
type WindsurfProfileSnapshot struct {
UserID string `json:"user_id,omitempty"`
TeamID string `json:"team_id,omitempty"`
Email string `json:"email,omitempty"`
DisplayName string `json:"display_name,omitempty"`
PlanName string `json:"plan_name,omitempty"`
TeamsTier string `json:"teams_tier,omitempty"`
TierSource string `json:"tier_source,omitempty"`
TrialEndAt string `json:"trial_end_at,omitempty"`
IsTeams bool `json:"is_teams,omitempty"`
IsEnterprise bool `json:"is_enterprise,omitempty"`
}
type WindsurfUserStatusSnapshot struct {
AllowedModels []WindsurfAllowedModel `json:"allowed_models,omitempty"`
MonthlyPromptCredits int64 `json:"monthly_prompt_credits,omitempty"`
MonthlyFlowCredits int64 `json:"monthly_flow_credits,omitempty"`
UserUsedPromptCredits int64 `json:"user_used_prompt_credits,omitempty"`
UserUsedFlowCredits int64 `json:"user_used_flow_credits,omitempty"`
MaxPremiumChatMessages int64 `json:"max_premium_chat_messages,omitempty"`
LastFetchedAt string `json:"last_fetched_at,omitempty"`
}
type WindsurfAllowedModel struct {
ModelKey string `json:"model_key,omitempty"`
ModelEnum int32 `json:"model_enum,omitempty"`
ModelUID string `json:"model_uid,omitempty"`
Alias string `json:"alias,omitempty"`
CreditMultiplier float64 `json:"credit_multiplier,omitempty"`
}
type WindsurfQuotaSnapshot struct {
DailyPercent *float64 `json:"daily_percent,omitempty"`
WeeklyPercent *float64 `json:"weekly_percent,omitempty"`
PromptUsed *float64 `json:"prompt_used,omitempty"`
PromptLimit *float64 `json:"prompt_limit,omitempty"`
FlexUsed *float64 `json:"flex_used,omitempty"`
FlexLimit *float64 `json:"flex_limit,omitempty"`
LastCheckedAt string `json:"last_checked_at,omitempty"`
LastError string `json:"last_error,omitempty"`
}
type WindsurfRefreshState struct {
LastTokenRefreshAt string `json:"last_token_refresh_at,omitempty"`
LastStatusRefreshAt string `json:"last_status_refresh_at,omitempty"`
TokenRefreshFailures int `json:"token_refresh_failures,omitempty"`
StatusRefreshFailures int `json:"status_refresh_failures,omitempty"`
}
type WindsurfProbeState struct {
LastProbeAt string `json:"last_probe_at,omitempty"`
LastCanaryAt string `json:"last_canary_at,omitempty"`
LastProbeError string `json:"last_probe_error,omitempty"`
ModelCatalogEtag string `json:"model_catalog_etag,omitempty"`
ModelCatalogAt string `json:"model_catalog_at,omitempty"`
}
type WindsurfModelCapability struct {
Available bool `json:"available"`
Mode string `json:"mode,omitempty"`
Reason string `json:"reason,omitempty"`
CheckedAt string `json:"checked_at,omitempty"`
}
type WindsurfModelAvail struct {
Visible bool `json:"visible"`
Available bool `json:"available"`
Blocked bool `json:"blocked"`
Mode string `json:"mode,omitempty"`
Source string `json:"source,omitempty"`
}
func LoadWindsurfCredentials(m map[string]any) WindsurfCredentials {
data, _ := json.Marshal(m)
var creds WindsurfCredentials
_ = json.Unmarshal(data, &creds)
return creds
}
func StoreWindsurfCredentials(creds WindsurfCredentials) map[string]any {
data, _ := json.Marshal(creds)
var m map[string]any
_ = json.Unmarshal(data, &m)
return m
}
func LoadWindsurfExtra(m map[string]any) WindsurfExtra {
data, _ := json.Marshal(m)
var extra WindsurfExtra
_ = json.Unmarshal(data, &extra)
return extra
}
func StoreWindsurfExtra(extra WindsurfExtra) map[string]any {
data, _ := json.Marshal(extra)
var m map[string]any
_ = json.Unmarshal(data, &m)
return m
}
func (c *WindsurfCredentials) IsExpired() bool {
if c.ExpiresAt == "" {
return false
}
t, err := time.Parse(time.RFC3339, c.ExpiresAt)
if err != nil {
return false
}
return time.Now().After(t)
}
func (c *WindsurfCredentials) NeedsRefresh(beforeExpiry time.Duration) bool {
if c.ExpiresAt == "" || c.RefreshToken == "" {
return false
}
t, err := time.Parse(time.RFC3339, c.ExpiresAt)
if err != nil {
return false
}
return time.Now().Add(beforeExpiry).After(t)
}
func WindsurfBaseRPM(tier string, cfg struct{ RPMPro, RPMFree, RPMUnknown, RPMExpired int }) int {
switch tier {
case "pro":
return cfg.RPMPro
case "free":
return cfg.RPMFree
case "expired":
return cfg.RPMExpired
default:
return cfg.RPMUnknown
}
}