Files
tbphp de6d2d44fc feat(access-keys): 支持自定义密钥并统一编辑与生成交互 (#611)
* feat(access-keys): 支持自定义密钥与强度提示

* fix(access-keys): 恢复默认掩码并按密钥长度分档

* feat(access-keys): 统一密钥编辑与随机生成交互

* style(access-keys): 改用骰子图标生成密钥

* fix(access-keys): 修复筛选幂等判定与恢复状态提示

* fix(access-keys): 统一编辑请求的幂等摘要
2026-09-09 23:05:09 +08:00

106 lines
3.0 KiB
Go

package control
import (
"context"
"fmt"
"gorm.io/gorm"
"gpt-load/internal/catalog"
app_errors "gpt-load/internal/platform/errors"
"gpt-load/internal/pricing"
"gpt-load/internal/storage/models"
"github.com/sirupsen/logrus"
)
const defaultAccessKeyMarker = models.InternalSystemSettingPrefix + "bootstrap.default_access_key.v1"
func (s *Service) EnsureInitialState(ctx context.Context) error {
s.writeMu.Lock()
defer s.writeMu.Unlock()
var catalogSnapshot *catalog.Snapshot
if s.catalogRuntime != nil {
catalogSnapshot = s.catalogRuntime.Load()
}
var priceTable *pricing.Table
err := s.withControlTransaction(ctx, func(tx *gorm.DB) error {
nowMS := s.now().UnixMilli()
if err := tx.Model(&models.Credential{}).
Where("auth_state = ?", models.CredentialAuthStateRefreshing).
Updates(map[string]any{
"auth_state": models.CredentialAuthStateOutcomeUnknown,
"auth_error_code": "refresh_interrupted", "updated_at_ms": nowMS,
}).Error; err != nil {
return app_errors.ParseDBError(err)
}
if err := tx.Model(&models.CredentialStage{}).
Where("status = ?", models.CredentialStageExchanging).
Updates(map[string]any{
"status": models.CredentialStageOutcomeUnknown,
"encrypted_payload": "", "oauth_state_hash": nil,
"error_code": "authorization_exchange_interrupted", "updated_at_ms": nowMS,
}).Error; err != nil {
return app_errors.ParseDBError(err)
}
var marker models.SystemSetting
query := tx.Where(&models.SystemSetting{Key: defaultAccessKeyMarker}).
Limit(1).Find(&marker)
if query.Error != nil {
return app_errors.ParseDBError(query.Error)
}
if query.RowsAffected == 0 {
var count int64
if err := tx.Model(&models.AccessKey{}).Count(&count).Error; err != nil {
return app_errors.ParseDBError(err)
}
if count == 0 {
filters, err := normalizeAccessKeyFilters(nil)
if err != nil {
return fmt.Errorf("build default access key filters: %w", err)
}
row, _, err := s.newAccessKeyRow("Default", filters, 0, "")
if err != nil {
return err
}
if err := tx.Create(&row).Error; err != nil {
return app_errors.ParseDBError(err)
}
}
marker = models.SystemSetting{
Key: defaultAccessKeyMarker,
Value: "true",
}
if err := tx.Create(&marker).Error; err != nil {
return app_errors.ParseDBError(err)
}
}
if catalogSnapshot != nil {
if err := reconcileCatalogAutomaticPrices(tx, catalogSnapshot); err != nil {
return err
}
}
if err := reconcileReferencedPrices(tx, catalogSnapshot); err != nil {
return err
}
if err := cleanupUnreferencedAutomaticPrices(tx); err != nil {
return err
}
var err error
priceTable, err = loadPriceTable(ctx, tx)
if err != nil {
return err
}
return nil
})
if err != nil {
return fmt.Errorf("ensure initial control state: %w", err)
}
s.priceRuntime.Publish(priceTable)
logrus.WithField("event", "startup.model_prices_publish").Info("model prices published")
return nil
}