feat: sync deployed v1.0.0-rc.38-custom.42

Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
cneicy committed 2026-09-26 04:49:11 +08:00
1 parent aa6c3f50f4
commit ceddfd3d6b
828 files changed
+122253 -13702

No files matched your search

+152 -33
View File
@@ -32,14 +32,34 @@ func (input *tokenAutoGroupsInput) UnmarshalJSON(data []byte) error {
return common.Unmarshal(data, &input.Groups)
}
type tokenGroupPoolInput struct {
Set bool
Entries []model.TokenGroupEntry
}
func (input *tokenGroupPoolInput) UnmarshalJSON(data []byte) error {
input.Set = true
if strings.TrimSpace(string(data)) == "null" {
input.Entries = nil
return nil
}
return common.Unmarshal(data, &input.Entries)
}
type tokenRequest struct {
model.Token
AutoGroups tokenAutoGroupsInput `json:"auto_groups"`
AstraDetectionEnabled *bool `json:"astra_detection_enabled"`
AstraAutoSwitch *bool `json:"astra_auto_switch"`
RoutingPolicy *model.TokenRoutingPolicy `json:"routing_policy"`
AutoGroups tokenAutoGroupsInput `json:"auto_groups"`
GroupPool tokenGroupPoolInput `json:"group_pool"`
}
type tokenResponse struct {
*model.Token
AutoGroups []string `json:"auto_groups"`
RoutingPolicy *model.TokenRoutingPolicy `json:"routing_policy,omitempty"`
AutoGroups []string `json:"auto_groups"`
GroupPool []model.TokenGroupEntry `json:"group_pool,omitempty"`
}
func maxTokenQuota() int {
@@ -58,15 +78,20 @@ func buildMaskedTokenResponse(token *model.Token) *tokenResponse {
}
maskedToken := *token
maskedToken.Key = token.GetMaskedKey()
autoGroups, err := token.GetAutoGroups()
groupPool, err := token.GetGroupPool()
if err != nil {
common.SysError(fmt.Sprintf("failed to parse auto groups for token %d: %v", token.Id, err))
autoGroups = nil
groupPool = nil
}
autoGroups := make([]string, 0, len(groupPool))
for _, entry := range groupPool {
autoGroups = append(autoGroups, entry.Group)
}
if len(autoGroups) == 0 {
autoGroups = nil
}
return &tokenResponse{Token: &maskedToken, AutoGroups: autoGroups}
policy, _ := token.GetRoutingPolicy()
return &tokenResponse{Token: &maskedToken, AutoGroups: autoGroups, GroupPool: groupPool, RoutingPolicy: policy}
}
func buildMaskedTokenResponses(tokens []*model.Token) []*tokenResponse {
@@ -128,18 +153,56 @@ func setTokenAutoGroups(c *gin.Context, token *model.Token, groups []string) boo
}
func setTokenBackupGroup(c *gin.Context, token *model.Token, groups []string) bool {
if len(groups) > 1 {
common.ApiErrorI18n(c, i18n.MsgTokenAutoGroupsTooMany, map[string]any{"Max": 1})
maxCount := setting.GetMaxTokenAutoGroups()
if len(groups) > maxCount {
common.ApiErrorI18n(c, i18n.MsgTokenAutoGroupsTooMany, map[string]any{"Max": maxCount})
return false
}
if len(groups) == 1 && groups[0] == token.Group {
common.ApiErrorI18n(c, i18n.MsgTokenAutoGroupsDuplicate, map[string]any{"Group": groups[0]})
return false
for _, group := range groups {
if group == token.Group {
common.ApiErrorI18n(c, i18n.MsgTokenAutoGroupsDuplicate, map[string]any{"Group": group})
return false
}
}
if !setTokenAutoGroups(c, token, groups) {
return false
}
token.CrossGroupRetry = len(groups) == 1
token.CrossGroupRetry = len(groups) > 0
return true
}
func setTokenGroupPool(c *gin.Context, token *model.Token, entries []model.TokenGroupEntry) bool {
maxCount := setting.GetMaxTokenAutoGroups()
if len(entries) > maxCount {
common.ApiErrorI18n(c, i18n.MsgTokenAutoGroupsTooMany, map[string]any{"Max": maxCount})
return false
}
userGroup, err := getTokenRequestUserGroup(c)
if err != nil {
common.ApiError(c, err)
return false
}
seen := make(map[string]struct{}, len(entries))
for _, entry := range entries {
if entry.Group == token.Group {
common.ApiErrorI18n(c, i18n.MsgTokenAutoGroupsDuplicate, map[string]any{"Group": entry.Group})
return false
}
if _, ok := seen[entry.Group]; ok {
common.ApiErrorI18n(c, i18n.MsgTokenAutoGroupsDuplicate, map[string]any{"Group": entry.Group})
return false
}
seen[entry.Group] = struct{}{}
if !service.IsUserSelectableGroup(userGroup, entry.Group) {
common.ApiErrorI18n(c, i18n.MsgTokenAutoGroupsInvalid, map[string]any{"Group": entry.Group})
return false
}
}
if err := token.SetGroupPool(entries); err != nil {
common.ApiError(c, err)
return false
}
token.CrossGroupRetry = len(entries) > 0
return true
}
@@ -299,6 +362,16 @@ func AddToken(c *gin.Context) {
return
}
token := request.Token
token.AstraDetectionEnabled = true
if request.AstraDetectionEnabled != nil {
token.AstraDetectionEnabled = *request.AstraDetectionEnabled
}
if request.AstraAutoSwitch != nil {
token.AstraAutoSwitch = *request.AstraAutoSwitch
}
if !token.AstraDetectionEnabled {
token.AstraAutoSwitch = false
}
if len(token.Name) > 50 {
common.ApiErrorI18n(c, i18n.MsgTokenNameTooLong)
return
@@ -331,15 +404,36 @@ func AddToken(c *gin.Context) {
})
return
}
if token.Group == "auto" {
if request.RoutingPolicy != nil {
if !setTokenRoutingPolicy(c, &token, request.RoutingPolicy) {
return
}
} else if token.Group == "auto" {
if !setTokenAutoGroups(c, &token, request.AutoGroups.Groups) {
return
}
} else if request.GroupPool.Set {
if !setTokenGroupPool(c, &token, request.GroupPool.Entries) {
return
}
} else {
if !setTokenBackupGroup(c, &token, request.AutoGroups.Groups) {
return
}
}
if token.RoutingPolicy == "" {
policy, err := token.LegacyRoutingPolicy()
if err != nil {
common.ApiError(c, err)
return
}
body, err := common.Marshal(policy)
if err != nil {
common.ApiError(c, err)
return
}
token.RoutingPolicy = string(body)
}
key, err := common.GenerateKey()
if err != nil {
common.ApiErrorI18n(c, i18n.MsgTokenGenerateFailed)
@@ -347,20 +441,23 @@ func AddToken(c *gin.Context) {
return
}
cleanToken := model.Token{
UserId: c.GetInt("id"),
Name: token.Name,
Key: key,
CreatedTime: common.GetTimestamp(),
AccessedTime: common.GetTimestamp(),
ExpiredTime: token.ExpiredTime,
RemainQuota: token.RemainQuota,
UnlimitedQuota: token.UnlimitedQuota,
ModelLimitsEnabled: token.ModelLimitsEnabled,
ModelLimits: token.ModelLimits,
AllowIps: token.AllowIps,
Group: token.Group,
CrossGroupRetry: token.CrossGroupRetry,
AutoGroups: token.AutoGroups,
UserId: c.GetInt("id"),
Name: token.Name,
Key: key,
CreatedTime: common.GetTimestamp(),
AccessedTime: common.GetTimestamp(),
ExpiredTime: token.ExpiredTime,
RemainQuota: token.RemainQuota,
UnlimitedQuota: token.UnlimitedQuota,
ModelLimitsEnabled: token.ModelLimitsEnabled,
ModelLimits: token.ModelLimits,
AllowIps: token.AllowIps,
Group: token.Group,
CrossGroupRetry: token.CrossGroupRetry,
AstraAutoSwitch: token.AstraAutoSwitch,
AstraDetectionEnabled: token.AstraDetectionEnabled,
AutoGroups: token.AutoGroups,
RoutingPolicy: token.RoutingPolicy,
}
err = cleanToken.Insert()
if err != nil {
@@ -454,15 +551,34 @@ func UpdateToken(c *gin.Context) {
cleanToken.ModelLimitsEnabled = token.ModelLimitsEnabled
cleanToken.ModelLimits = token.ModelLimits
cleanToken.AllowIps = token.AllowIps
cleanToken.Group = token.Group
cleanToken.CrossGroupRetry = token.CrossGroupRetry
if token.Group != "auto" {
if !setTokenBackupGroup(c, cleanToken, request.AutoGroups.Groups) {
if request.AstraDetectionEnabled != nil {
cleanToken.AstraDetectionEnabled = *request.AstraDetectionEnabled
}
if request.AstraAutoSwitch != nil {
cleanToken.AstraAutoSwitch = *request.AstraAutoSwitch
}
if !cleanToken.AstraDetectionEnabled {
cleanToken.AstraAutoSwitch = false
}
if request.RoutingPolicy != nil {
if !setTokenRoutingPolicy(c, cleanToken, request.RoutingPolicy) {
return
}
} else if request.AutoGroups.Set {
if !setTokenAutoGroups(c, cleanToken, request.AutoGroups.Groups) {
return
} else if cleanToken.RoutingPolicy == "" {
cleanToken.Group = token.Group
cleanToken.CrossGroupRetry = token.CrossGroupRetry
if token.Group != "auto" {
if request.GroupPool.Set {
if !setTokenGroupPool(c, cleanToken, request.GroupPool.Entries) {
return
}
} else if !setTokenBackupGroup(c, cleanToken, request.AutoGroups.Groups) {
return
}
} else if request.AutoGroups.Set {
if !setTokenAutoGroups(c, cleanToken, request.AutoGroups.Groups) {
return
}
}
}
}
@@ -490,7 +606,10 @@ func UpdateToken(c *gin.Context) {
(previous.AllowIps != nil && cleanToken.AllowIps != nil && *previous.AllowIps != *cleanToken.AllowIps)},
{"group", previous.Group != cleanToken.Group},
{"cross_group_retry", previous.CrossGroupRetry != cleanToken.CrossGroupRetry},
{"astra_auto_switch", previous.AstraAutoSwitch != cleanToken.AstraAutoSwitch},
{"astra_detection_enabled", previous.AstraDetectionEnabled != cleanToken.AstraDetectionEnabled},
{"auto_groups", previous.AutoGroups != cleanToken.AutoGroups},
{"routing_policy", previous.RoutingPolicy != cleanToken.RoutingPolicy},
} {
if field.changed {
changedFields = append(changedFields, field.name)