[功能] 添加源站管理功能,包括源站的创建、更新、删除及列表展示

This commit is contained in:
ryan
2026-03-20 20:01:42 +08:00
parent edd31da527
commit afd891f0f6
26 changed files with 2046 additions and 105 deletions
+125 -1
View File
@@ -9,10 +9,13 @@ import (
"gorm.io/gorm"
"gorm.io/gorm/schema"
"log/slog"
"net"
"net/url"
"openflare/common"
"openflare/utils/security"
"os"
"reflect"
"strings"
"sync"
)
@@ -36,6 +39,7 @@ func registeredModels() []any {
&File{},
&User{},
&Option{},
&Origin{},
&ProxyRoute{},
&ConfigVersion{},
&Node{},
@@ -307,6 +311,19 @@ func validateDatabaseSchemaV3(db *gorm.DB, backend string) error {
return nil
}
func validateDatabaseSchemaV4(db *gorm.DB, backend string) error {
if err := validateDatabaseSchemaV3(db, backend); err != nil {
return err
}
if !db.Migrator().HasTable(&Origin{}) {
return fmt.Errorf("table origins is missing")
}
if !db.Migrator().HasColumn(&ProxyRoute{}, "origin_id") {
return fmt.Errorf("column proxy_routes.origin_id is missing")
}
return nil
}
func renameLegacyObservabilityShardTables(db *gorm.DB) error {
for _, baseTable := range shardedObservabilityBaseTables() {
for _, table := range observabilityShardTables(baseTable) {
@@ -549,6 +566,91 @@ func migrateObservabilityShardsToID(db *gorm.DB, backend string) error {
return dropLegacyObservabilityShardTables(db)
}
func normalizeOriginAddressForMigration(raw string) string {
return strings.ToLower(strings.TrimSpace(raw))
}
func extractOriginAddressForMigration(rawURL string) string {
parsed, err := url.ParseRequestURI(strings.TrimSpace(rawURL))
if err != nil {
return ""
}
return normalizeOriginAddressForMigration(parsed.Hostname())
}
func backfillOriginsFromProxyRoutes(db *gorm.DB) error {
if db == nil {
return fmt.Errorf("database handle is nil")
}
if !db.Migrator().HasTable(&Origin{}) || !db.Migrator().HasTable(&ProxyRoute{}) {
return nil
}
var routes []ProxyRoute
if err := db.Order("id asc").Find(&routes).Error; err != nil {
return fmt.Errorf("list proxy routes for origin backfill failed: %w", err)
}
type originSeed struct {
ID uint
Address string
}
originByAddress := make(map[string]originSeed)
var origins []Origin
if err := db.Order("id asc").Find(&origins).Error; err != nil {
return fmt.Errorf("list origins for backfill failed: %w", err)
}
for _, origin := range origins {
address := normalizeOriginAddressForMigration(origin.Address)
if address == "" {
continue
}
originByAddress[address] = originSeed{ID: origin.ID, Address: address}
}
for _, route := range routes {
address := extractOriginAddressForMigration(route.OriginURL)
if address == "" {
continue
}
origin, ok := originByAddress[address]
if !ok {
name := address
if ip := net.ParseIP(address); ip != nil {
name = ip.String()
}
record := Origin{
Name: name,
Address: address,
Remark: "",
}
if err := db.Create(&record).Error; err != nil {
return fmt.Errorf("create origin for address %s failed: %w", address, err)
}
origin = originSeed{ID: record.ID, Address: address}
originByAddress[address] = origin
}
if route.OriginID != nil && *route.OriginID == origin.ID {
continue
}
if err := db.Model(&ProxyRoute{}).
Where("id = ?", route.ID).
Update("origin_id", origin.ID).Error; err != nil {
return fmt.Errorf("backfill proxy route %d origin_id failed: %w", route.ID, err)
}
}
return nil
}
func migrateOriginsSchema(db *gorm.DB, backend string) error {
if err := applyCurrentSchema(db, backend); err != nil {
return err
}
return backfillOriginsFromProxyRoutes(db)
}
func databaseSchemaMigrations() []databaseSchemaMigration {
return []databaseSchemaMigration{
{
@@ -563,6 +665,12 @@ func databaseSchemaMigrations() []databaseSchemaMigration {
migrate: migrateObservabilityShardsToID,
validate: validateDatabaseSchemaV3,
},
{
fromVersion: 3,
toVersion: 4,
migrate: migrateOriginsSchema,
validate: validateDatabaseSchemaV4,
},
}
}
@@ -575,6 +683,19 @@ func databaseSchemaMigrationMap() map[int]databaseSchemaMigration {
}
func runDatabaseSchemaMigration(db *gorm.DB, backend string, migration databaseSchemaMigration) error {
if backend == "sqlite" {
if err := migration.migrate(db, backend); err != nil {
return fmt.Errorf("migrate database schema from v%d to v%d failed: %w", migration.fromVersion, migration.toVersion, err)
}
if err := migration.validate(db, backend); err != nil {
return fmt.Errorf("validate database schema v%d failed: %w", migration.toVersion, err)
}
if err := saveDatabaseSchemaVersion(db, migration.toVersion); err != nil {
return fmt.Errorf("persist database schema version v%d failed: %w", migration.toVersion, err)
}
return nil
}
return db.Transaction(func(tx *gorm.DB) error {
if err := migration.migrate(tx, backend); err != nil {
return fmt.Errorf("migrate database schema from v%d to v%d failed: %w", migration.fromVersion, migration.toVersion, err)
@@ -614,10 +735,13 @@ func initializeFreshDatabaseSchema(db *gorm.DB, backend string) error {
if err := applyCurrentSchema(db, backend); err != nil {
return err
}
if err := backfillOriginsFromProxyRoutes(db); err != nil {
return err
}
if err := migrateSQLiteDataIfNeeded(db, backend); err != nil {
return err
}
if err := validateDatabaseSchemaV3(db, backend); err != nil {
if err := validateDatabaseSchemaV4(db, backend); err != nil {
return err
}
return saveDatabaseSchemaVersion(db, currentDatabaseSchemaVersion)