@@ -53,6 +53,7 @@ type AccountHandler struct {
concurrencyService * service . ConcurrencyService
crsSyncService * service . CRSSyncService
sessionLimitCache service . SessionLimitCache
rpmCache service . RPMCache
tokenCacheInvalidator service . TokenCacheInvalidator
}
@@ -69,6 +70,7 @@ func NewAccountHandler(
concurrencyService * service . ConcurrencyService ,
crsSyncService * service . CRSSyncService ,
sessionLimitCache service . SessionLimitCache ,
rpmCache service . RPMCache ,
tokenCacheInvalidator service . TokenCacheInvalidator ,
) * AccountHandler {
return & AccountHandler {
@@ -83,6 +85,7 @@ func NewAccountHandler(
concurrencyService : concurrencyService ,
crsSyncService : crsSyncService ,
sessionLimitCache : sessionLimitCache ,
rpmCache : rpmCache ,
tokenCacheInvalidator : tokenCacheInvalidator ,
}
}
@@ -154,6 +157,7 @@ type AccountWithConcurrency struct {
// 以下字段仅对 Anthropic OAuth/SetupToken 账号有效,且仅在启用相应功能时返回
CurrentWindowCost * float64 ` json:"current_window_cost,omitempty" ` // 当前窗口费用
ActiveSessions * int ` json:"active_sessions,omitempty" ` // 当前活跃会话数
CurrentRPM * int ` json:"current_rpm,omitempty" ` // 当前分钟 RPM 计数
}
func ( h * AccountHandler ) buildAccountResponseWithRuntime ( ctx context . Context , account * service . Account ) AccountWithConcurrency {
@@ -189,6 +193,12 @@ func (h *AccountHandler) buildAccountResponseWithRuntime(ctx context.Context, ac
}
}
}
if h . rpmCache != nil && account . GetBaseRPM ( ) > 0 {
if rpm , err := h . rpmCache . GetRPM ( ctx , account . ID ) ; err == nil {
item . CurrentRPM = & rpm
}
}
}
return item
@@ -231,9 +241,10 @@ func (h *AccountHandler) List(c *gin.Context) {
concurrencyCounts = make ( map [ int64 ] int )
}
// 识别需要查询窗口费用和 会话数的账号( Anthropic OAuth/SetupToken 且启用了相应功能)
// 识别需要查询窗口费用、 会话数和 RPM 的账号( Anthropic OAuth/SetupToken 且启用了相应功能)
windowCostAccountIDs := make ( [ ] int64 , 0 )
sessionLimitAccountIDs := make ( [ ] int64 , 0 )
rpmAccountIDs := make ( [ ] int64 , 0 )
sessionIdleTimeouts := make ( map [ int64 ] time . Duration ) // 各账号的会话空闲超时配置
for i := range accounts {
acc := & accounts [ i ]
@@ -245,12 +256,24 @@ func (h *AccountHandler) List(c *gin.Context) {
sessionLimitAccountIDs = append ( sessionLimitAccountIDs , acc . ID )
sessionIdleTimeouts [ acc . ID ] = time . Duration ( acc . GetSessionIdleTimeoutMinutes ( ) ) * time . Minute
}
if acc . GetBaseRPM ( ) > 0 {
rpmAccountIDs = append ( rpmAccountIDs , acc . ID )
}
}
}
// 并行获取窗口费用和 活跃会话数
// 并行获取窗口费用、 活跃会话数和 RPM 计数
var windowCosts map [ int64 ] float64
var activeSessions map [ int64 ] int
var rpmCounts map [ int64 ] int
// 获取 RPM 计数(批量查询)
if len ( rpmAccountIDs ) > 0 && h . rpmCache != nil {
rpmCounts , _ = h . rpmCache . GetRPMBatch ( c . Request . Context ( ) , rpmAccountIDs )
if rpmCounts == nil {
rpmCounts = make ( map [ int64 ] int )
}
}
// 获取活跃会话数(批量查询,传入各账号的 idleTimeout 配置)
if len ( sessionLimitAccountIDs ) > 0 && h . sessionLimitCache != nil {
@@ -311,6 +334,13 @@ func (h *AccountHandler) List(c *gin.Context) {
}
}
// 添加 RPM 计数(仅当启用时)
if rpmCounts != nil {
if rpm , ok := rpmCounts [ acc . ID ] ; ok {
item . CurrentRPM = & rpm
}
}
result [ i ] = item
}
@@ -453,6 +483,8 @@ func (h *AccountHandler) Create(c *gin.Context) {
response . BadRequest ( c , "rate_multiplier must be >= 0" )
return
}
// base_rpm 输入校验:负值归零,超过 10000 截断
sanitizeExtraBaseRPM ( req . Extra )
// 确定是否跳过混合渠道检查
skipCheck := req . ConfirmMixedChannelRisk != nil && * req . ConfirmMixedChannelRisk
@@ -522,6 +554,8 @@ func (h *AccountHandler) Update(c *gin.Context) {
response . BadRequest ( c , "rate_multiplier must be >= 0" )
return
}
// base_rpm 输入校验:负值归零,超过 10000 截断
sanitizeExtraBaseRPM ( req . Extra )
// 确定是否跳过混合渠道检查
skipCheck := req . ConfirmMixedChannelRisk != nil && * req . ConfirmMixedChannelRisk
@@ -904,6 +938,9 @@ func (h *AccountHandler) BatchCreate(c *gin.Context) {
continue
}
// base_rpm 输入校验:负值归零,超过 10000 截断
sanitizeExtraBaseRPM ( item . Extra )
skipCheck := item . ConfirmMixedChannelRisk != nil && * item . ConfirmMixedChannelRisk
account , err := h . adminService . CreateAccount ( ctx , & service . CreateAccountInput {
@@ -1048,6 +1085,8 @@ func (h *AccountHandler) BulkUpdate(c *gin.Context) {
response . BadRequest ( c , "rate_multiplier must be >= 0" )
return
}
// base_rpm 输入校验:负值归零,超过 10000 截断
sanitizeExtraBaseRPM ( req . Extra )
// 确定是否跳过混合渠道检查
skipCheck := req . ConfirmMixedChannelRisk != nil && * req . ConfirmMixedChannelRisk
@@ -1706,3 +1745,22 @@ func (h *AccountHandler) BatchRefreshTier(c *gin.Context) {
func ( h * AccountHandler ) GetAntigravityDefaultModelMapping ( c * gin . Context ) {
response . Success ( c , domain . DefaultAntigravityModelMapping )
}
// sanitizeExtraBaseRPM 对 extra map 中的 base_rpm 值进行范围校验和归一化。
// 负值归零,超过 10000 截断为 10000。extra 为 nil 或不含 base_rpm 时无操作。
func sanitizeExtraBaseRPM ( extra map [ string ] any ) {
if extra == nil {
return
}
raw , ok := extra [ "base_rpm" ]
if ! ok {
return
}
v := service . ParseExtraInt ( raw )
if v < 0 {
v = 0
} else if v > 10000 {
v = 10000
}
extra [ "base_rpm" ] = v
}