mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-07 05:34:17 +00:00
feat: add shared metadata models and helpers
This commit is contained in:
parent
36826706ec
commit
fd0af148cb
5 changed files with 137 additions and 0 deletions
|
|
@ -40,6 +40,8 @@ func initModels() error {
|
|||
&model.InboundClientIps{},
|
||||
&xray.ClientTraffic{},
|
||||
&model.HistoryOfSeeders{},
|
||||
&model.SharedState{},
|
||||
&model.NodeState{},
|
||||
}
|
||||
for _, model := range models {
|
||||
if err := db.AutoMigrate(model); err != nil {
|
||||
|
|
@ -47,6 +49,9 @@ func initModels() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if err := seedSharedAccountsVersion(db); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -256,3 +256,67 @@ func TestSettingKey_IsUnique(t *testing.T) {
|
|||
t.Fatal("expected duplicate setting key insert to fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitDB_CreatesSharedMetadataTables(t *testing.T) {
|
||||
setupTestDB(t)
|
||||
|
||||
for _, table := range []string{"shared_states", "node_states"} {
|
||||
var count int64
|
||||
if err := db.Table(table).Count(&count).Error; err != nil {
|
||||
t.Fatalf("table %s should exist: %v", table, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBumpSharedAccountsVersion(t *testing.T) {
|
||||
setupTestDB(t)
|
||||
|
||||
version, err := GetSharedAccountsVersion(GetDB())
|
||||
if err != nil {
|
||||
t.Fatalf("GetSharedAccountsVersion error: %v", err)
|
||||
}
|
||||
if version != 0 {
|
||||
t.Fatalf("expected seeded version 0, got %d", version)
|
||||
}
|
||||
|
||||
tx := GetDB().Begin()
|
||||
if err := BumpSharedAccountsVersion(tx); err != nil {
|
||||
t.Fatalf("BumpSharedAccountsVersion error: %v", err)
|
||||
}
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
t.Fatalf("Commit error: %v", err)
|
||||
}
|
||||
|
||||
version, err = GetSharedAccountsVersion(GetDB())
|
||||
if err != nil {
|
||||
t.Fatalf("GetSharedAccountsVersion error: %v", err)
|
||||
}
|
||||
if version != 1 {
|
||||
t.Fatalf("expected bumped version 1, got %d", version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpsertNodeState(t *testing.T) {
|
||||
setupTestDB(t)
|
||||
|
||||
state := &model.NodeState{
|
||||
NodeID: "worker-1",
|
||||
NodeRole: "worker",
|
||||
LastSeenVersion: 7,
|
||||
LastError: "dial tcp timeout",
|
||||
}
|
||||
if err := UpsertNodeState(GetDB(), state); err != nil {
|
||||
t.Fatalf("UpsertNodeState error: %v", err)
|
||||
}
|
||||
|
||||
var stored model.NodeState
|
||||
if err := GetDB().First(&stored, "node_id = ?", "worker-1").Error; err != nil {
|
||||
t.Fatalf("lookup node state failed: %v", err)
|
||||
}
|
||||
if stored.LastSeenVersion != 7 {
|
||||
t.Fatalf("expected last seen version 7, got %d", stored.LastSeenVersion)
|
||||
}
|
||||
if stored.LastError != "dial tcp timeout" {
|
||||
t.Fatalf("expected last error to round-trip, got %q", stored.LastError)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
11
database/model/node_state.go
Normal file
11
database/model/node_state.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package model
|
||||
|
||||
type NodeState struct {
|
||||
NodeID string `json:"nodeId" gorm:"primaryKey"`
|
||||
NodeRole string `json:"nodeRole" gorm:"not null"`
|
||||
LastSyncAt int64 `json:"lastSyncAt"`
|
||||
LastHeartbeatAt int64 `json:"lastHeartbeatAt"`
|
||||
LastSeenVersion int64 `json:"lastSeenVersion"`
|
||||
LastError string `json:"lastError"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
7
database/model/shared_state.go
Normal file
7
database/model/shared_state.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package model
|
||||
|
||||
type SharedState struct {
|
||||
Key string `json:"key" gorm:"primaryKey"`
|
||||
Version int64 `json:"version" gorm:"not null;default:0"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
50
database/shared_state.go
Normal file
50
database/shared_state.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v2/database/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const SharedAccountsVersionKey = "shared_accounts_version"
|
||||
|
||||
func txOrDB(tx *gorm.DB) *gorm.DB {
|
||||
if tx != nil {
|
||||
return tx
|
||||
}
|
||||
return GetDB()
|
||||
}
|
||||
|
||||
func seedSharedAccountsVersion(tx *gorm.DB) error {
|
||||
return txOrDB(tx).FirstOrCreate(
|
||||
&model.SharedState{},
|
||||
&model.SharedState{
|
||||
Key: SharedAccountsVersionKey,
|
||||
Version: 0,
|
||||
UpdatedAt: time.Now().Unix(),
|
||||
},
|
||||
).Error
|
||||
}
|
||||
|
||||
func GetSharedAccountsVersion(tx *gorm.DB) (int64, error) {
|
||||
state := &model.SharedState{}
|
||||
if err := txOrDB(tx).First(state, "key = ?", SharedAccountsVersionKey).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return state.Version, nil
|
||||
}
|
||||
|
||||
func BumpSharedAccountsVersion(tx *gorm.DB) error {
|
||||
return txOrDB(tx).Model(&model.SharedState{}).
|
||||
Where("key = ?", SharedAccountsVersionKey).
|
||||
Updates(map[string]any{
|
||||
"version": gorm.Expr("version + 1"),
|
||||
"updated_at": time.Now().Unix(),
|
||||
}).Error
|
||||
}
|
||||
|
||||
func UpsertNodeState(tx *gorm.DB, state *model.NodeState) error {
|
||||
state.UpdatedAt = time.Now().Unix()
|
||||
return txOrDB(tx).Save(state).Error
|
||||
}
|
||||
Loading…
Reference in a new issue