Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const AccountSchedulingThresholdReasonSource = "account_scheduling_threshold"
|
||||
|
||||
const (
|
||||
defaultTempUnschedReasonErrorMessage = "temporary scheduling block reason unavailable"
|
||||
defaultAccountSchedulingThresholdErrorMessage = "account scheduling threshold reached"
|
||||
)
|
||||
|
||||
type tempUnschedReasonPayload struct {
|
||||
Source string `json:"source,omitempty"`
|
||||
Platform string `json:"platform,omitempty"`
|
||||
Window string `json:"window,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
ThresholdPercent int `json:"threshold_percent,omitempty"`
|
||||
UsedPercent float64 `json:"used_percent,omitempty"`
|
||||
UntilUnix int64 `json:"until_unix,omitempty"`
|
||||
TriggeredAtUnix int64 `json:"triggered_at_unix,omitempty"`
|
||||
ErrorMessage string `json:"error_message"`
|
||||
}
|
||||
|
||||
type AccountSchedulingThresholdReasonInput struct {
|
||||
Platform string
|
||||
Window string
|
||||
Scope string
|
||||
ThresholdPercent int
|
||||
UsedPercent float64
|
||||
Until time.Time
|
||||
Now time.Time
|
||||
}
|
||||
|
||||
func BuildTempUnschedReasonPayload(source string, errorMessage string) string {
|
||||
payload := tempUnschedReasonPayload{
|
||||
Source: strings.TrimSpace(source),
|
||||
ErrorMessage: normalizeTempUnschedReasonErrorMessage(errorMessage, defaultTempUnschedReasonErrorMessage),
|
||||
}
|
||||
|
||||
raw, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return payload.ErrorMessage
|
||||
}
|
||||
return string(raw)
|
||||
}
|
||||
|
||||
func BuildAccountSchedulingThresholdReason(errorMessage string) string {
|
||||
return BuildTempUnschedReasonPayload(
|
||||
AccountSchedulingThresholdReasonSource,
|
||||
normalizeTempUnschedReasonErrorMessage(errorMessage, defaultAccountSchedulingThresholdErrorMessage),
|
||||
)
|
||||
}
|
||||
|
||||
func BuildDetailedAccountSchedulingThresholdReason(input AccountSchedulingThresholdReasonInput) string {
|
||||
triggeredAt := input.Now
|
||||
if triggeredAt.IsZero() {
|
||||
triggeredAt = time.Now().UTC()
|
||||
}
|
||||
payload := tempUnschedReasonPayload{
|
||||
Source: AccountSchedulingThresholdReasonSource,
|
||||
Platform: strings.TrimSpace(input.Platform),
|
||||
Window: strings.TrimSpace(input.Window),
|
||||
Scope: strings.TrimSpace(input.Scope),
|
||||
ThresholdPercent: input.ThresholdPercent,
|
||||
UsedPercent: input.UsedPercent,
|
||||
TriggeredAtUnix: triggeredAt.Unix(),
|
||||
ErrorMessage: buildAccountSchedulingThresholdErrorMessage(input),
|
||||
}
|
||||
if !input.Until.IsZero() {
|
||||
payload.UntilUnix = input.Until.UTC().Unix()
|
||||
}
|
||||
|
||||
raw, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return payload.ErrorMessage
|
||||
}
|
||||
return string(raw)
|
||||
}
|
||||
|
||||
func IsAccountSchedulingThresholdReason(rawReason string) bool {
|
||||
payload, ok := parseTempUnschedReasonPayload(rawReason)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return payload.Source == AccountSchedulingThresholdReasonSource
|
||||
}
|
||||
|
||||
func parseTempUnschedReasonPayload(rawReason string) (tempUnschedReasonPayload, bool) {
|
||||
rawReason = strings.TrimSpace(rawReason)
|
||||
if rawReason == "" {
|
||||
return tempUnschedReasonPayload{}, false
|
||||
}
|
||||
|
||||
var payload tempUnschedReasonPayload
|
||||
if err := json.Unmarshal([]byte(rawReason), &payload); err != nil {
|
||||
return tempUnschedReasonPayload{}, false
|
||||
}
|
||||
payload.Source = strings.TrimSpace(payload.Source)
|
||||
payload.ErrorMessage = strings.TrimSpace(payload.ErrorMessage)
|
||||
return payload, true
|
||||
}
|
||||
|
||||
func normalizeTempUnschedReasonErrorMessage(errorMessage string, fallback string) string {
|
||||
errorMessage = strings.TrimSpace(errorMessage)
|
||||
if errorMessage != "" {
|
||||
return errorMessage
|
||||
}
|
||||
|
||||
fallback = strings.TrimSpace(fallback)
|
||||
if fallback != "" {
|
||||
return fallback
|
||||
}
|
||||
return defaultTempUnschedReasonErrorMessage
|
||||
}
|
||||
|
||||
func buildAccountSchedulingThresholdErrorMessage(input AccountSchedulingThresholdReasonInput) string {
|
||||
platform := strings.TrimSpace(input.Platform)
|
||||
if platform == "" {
|
||||
platform = "account"
|
||||
}
|
||||
|
||||
target := strings.TrimSpace(input.Window)
|
||||
if scope := strings.TrimSpace(input.Scope); scope != "" {
|
||||
if target == "" {
|
||||
target = scope
|
||||
} else {
|
||||
target = target + "/" + scope
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "usage window"
|
||||
}
|
||||
|
||||
threshold := input.ThresholdPercent
|
||||
if threshold <= 0 {
|
||||
threshold = 100
|
||||
}
|
||||
|
||||
untilText := "the window reset"
|
||||
if !input.Until.IsZero() {
|
||||
untilText = input.Until.UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"%s scheduling threshold reached for %s: %.1f%% used >= %d%%; paused until %s",
|
||||
platform,
|
||||
target,
|
||||
input.UsedPercent,
|
||||
threshold,
|
||||
untilText,
|
||||
)
|
||||
}
|
||||
|
||||
func tempUnschedStateFromStoredReason(rawReason string, fallbackUntilUnix int64) *TempUnschedState {
|
||||
state := &TempUnschedState{
|
||||
UntilUnix: fallbackUntilUnix,
|
||||
RuleIndex: -1,
|
||||
}
|
||||
|
||||
rawReason = strings.TrimSpace(rawReason)
|
||||
if rawReason == "" {
|
||||
state.ErrorMessage = defaultTempUnschedReasonErrorMessage
|
||||
return state
|
||||
}
|
||||
|
||||
parsed := TempUnschedState{RuleIndex: -1}
|
||||
if err := json.Unmarshal([]byte(rawReason), &parsed); err == nil {
|
||||
if fallbackUntilUnix > parsed.UntilUnix {
|
||||
parsed.UntilUnix = fallbackUntilUnix
|
||||
}
|
||||
if strings.TrimSpace(parsed.ErrorMessage) == "" {
|
||||
if IsAccountSchedulingThresholdReason(rawReason) {
|
||||
parsed.ErrorMessage = defaultAccountSchedulingThresholdErrorMessage
|
||||
} else {
|
||||
parsed.ErrorMessage = rawReason
|
||||
}
|
||||
}
|
||||
return &parsed
|
||||
}
|
||||
|
||||
state.ErrorMessage = rawReason
|
||||
return state
|
||||
}
|
||||
Reference in New Issue
Block a user