mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-03 07:06:36 +08:00
feat(core): implement cordis configuration extension and migrate all plugins
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package admin
|
||||
|
||||
import "Wavelet/plugins/domain/admin/model"
|
||||
|
||||
// DatabaseConfig aliases model.DatabaseConfig.
|
||||
type DatabaseConfig = model.DatabaseConfig
|
||||
|
||||
// ClickHouseConfig aliases model.ClickHouseConfig.
|
||||
type ClickHouseConfig = model.ClickHouseConfig
|
||||
@@ -4,7 +4,6 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"Wavelet/pkg/config"
|
||||
"Wavelet/pkg/logger"
|
||||
"Wavelet/pkg/response"
|
||||
"Wavelet/plugins/domain/admin/errs"
|
||||
@@ -147,7 +146,7 @@ func GetDatabaseInfo(c *gin.Context) {
|
||||
// @Failure 500 {object} response.Any "导出失败"
|
||||
// @Router /api/v1/admin/db-export [get]
|
||||
func ExportDatabase(c *gin.Context) {
|
||||
if !config.Config.Database.Enabled {
|
||||
if !service.GetDBConfig().Enabled {
|
||||
exportSQLite(c)
|
||||
} else {
|
||||
exportPostgres(c)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package model
|
||||
|
||||
// DatabaseConfig holds database configuration needed by the admin plugin.
|
||||
type DatabaseConfig struct {
|
||||
Enabled bool `config:"enabled" env:"DB_ENABLED" default:"false" autoEnable:"DB_HOST"`
|
||||
Host string `config:"host" env:"DB_HOST"`
|
||||
Port int `config:"port" env:"DB_PORT" default:"5432"`
|
||||
Database string `config:"database" env:"DB_DATABASE"`
|
||||
Username string `config:"username" env:"DB_USERNAME"`
|
||||
Password string `config:"password" env:"DB_PASSWORD" secret:"true"`
|
||||
SQLitePath string `config:"sqlite_path" env:"DB_SQLITE_PATH" default:"./data/wavelet.db"`
|
||||
}
|
||||
|
||||
// ClickHouseConfig holds clickhouse enablement status needed by admin log queries/switching.
|
||||
type ClickHouseConfig struct {
|
||||
Enabled bool `config:"enabled" env:"CLICKHOUSE_ENABLED" default:"false" autoEnable:"CLICKHOUSE_HOST"`
|
||||
}
|
||||
@@ -66,8 +66,24 @@ func (p *Plugin) Manifest() core.Manifest {
|
||||
}
|
||||
}
|
||||
|
||||
// DeclareConfig declares configuration bindings consumed by the admin plugin.
|
||||
func (p *Plugin) DeclareConfig() []core.ConfigBinding {
|
||||
return []core.ConfigBinding{
|
||||
{Prefix: "database", Target: &model.DatabaseConfig{}},
|
||||
{Prefix: "clickhouse", Target: &model.ClickHouseConfig{}},
|
||||
}
|
||||
}
|
||||
|
||||
// Apply registers admin routes, tasks, schedules, and settings into the Context.
|
||||
func (p *Plugin) Apply(ctx *core.Context) error {
|
||||
var dbCfg model.DatabaseConfig
|
||||
_ = ctx.Config().Bind("database", &dbCfg)
|
||||
service.SetDBConfig(dbCfg)
|
||||
|
||||
var chCfg model.ClickHouseConfig
|
||||
_ = ctx.Config().Bind("clickhouse", &chCfg)
|
||||
service.SetClickHouseConfig(chCfg)
|
||||
|
||||
// 0. Bind Services reactively
|
||||
if db, err := core.Inject[contracts.DBService](ctx); err == nil && db != nil {
|
||||
service.SetDBService(db)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"Wavelet/pkg/config"
|
||||
"Wavelet/plugins/domain/admin/errs"
|
||||
"Wavelet/plugins/domain/admin/model"
|
||||
"context"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -22,9 +22,30 @@ const (
|
||||
logDBNameSQLite = "sqlite"
|
||||
)
|
||||
|
||||
var (
|
||||
dbConfigMu sync.RWMutex
|
||||
dbConfig = model.DatabaseConfig{
|
||||
SQLitePath: defaultSQLiteDBPath,
|
||||
}
|
||||
)
|
||||
|
||||
// SetDBConfig sets the database configuration.
|
||||
func SetDBConfig(cfg model.DatabaseConfig) {
|
||||
dbConfigMu.Lock()
|
||||
defer dbConfigMu.Unlock()
|
||||
dbConfig = cfg
|
||||
}
|
||||
|
||||
// GetDBConfig gets the database configuration.
|
||||
func GetDBConfig() model.DatabaseConfig {
|
||||
dbConfigMu.RLock()
|
||||
defer dbConfigMu.RUnlock()
|
||||
return dbConfig
|
||||
}
|
||||
|
||||
// sqliteDatabasePath resolves the effective SQLite file path from configuration.
|
||||
func sqliteDatabasePath() string {
|
||||
name := config.Config.Database.SQLitePath
|
||||
name := GetDBConfig().SQLitePath
|
||||
if name == "" {
|
||||
name = defaultSQLiteDBPath
|
||||
}
|
||||
@@ -93,7 +114,7 @@ func GetPostgresOverview(ctx context.Context) (model.DBOverviewResponse, error)
|
||||
return model.DBOverviewResponse{}, errs.ErrDatabaseUninitialized
|
||||
}
|
||||
|
||||
name := config.Config.Database.Database
|
||||
name := GetDBConfig().Database
|
||||
|
||||
var version string
|
||||
var ver string
|
||||
@@ -152,7 +173,7 @@ func ListDatabaseTableNames(ctx context.Context) ([]string, error) {
|
||||
var tables []string
|
||||
var err error
|
||||
|
||||
if !config.Config.Database.Enabled {
|
||||
if !GetDBConfig().Enabled {
|
||||
err = gormDB.Raw("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name").Scan(&tables).Error
|
||||
} else {
|
||||
err = gormDB.Raw("SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema() ORDER BY table_name").Scan(&tables).Error
|
||||
@@ -288,9 +309,10 @@ func scanRowAsMap(rows *sql.Rows, cols []string) (map[string]any, error) {
|
||||
|
||||
// GetSQLiteInfo collects the SQLite type/name/version triple.
|
||||
func GetSQLiteInfo(ctx context.Context) model.DatabaseInfoResponse {
|
||||
cfg := GetDBConfig()
|
||||
info := model.DatabaseInfoResponse{
|
||||
Type: logDBNameSQLite,
|
||||
Name: config.Config.Database.SQLitePath,
|
||||
Name: cfg.SQLitePath,
|
||||
Version: "SQLite",
|
||||
}
|
||||
if info.Name == "" {
|
||||
@@ -309,9 +331,10 @@ func GetSQLiteInfo(ctx context.Context) model.DatabaseInfoResponse {
|
||||
|
||||
// GetPostgresInfo collects the PostgreSQL type/name/version triple.
|
||||
func GetPostgresInfo(ctx context.Context) model.DatabaseInfoResponse {
|
||||
cfg := GetDBConfig()
|
||||
info := model.DatabaseInfoResponse{
|
||||
Type: "postgres",
|
||||
Name: config.Config.Database.Database,
|
||||
Name: cfg.Database,
|
||||
Version: "PostgreSQL",
|
||||
}
|
||||
gormDB := GetDB(ctx)
|
||||
@@ -343,7 +366,7 @@ func OpenSQLiteExportFile() (*os.File, os.FileInfo, error) {
|
||||
|
||||
// NewPgDumpCommand builds the streaming pg_dump command for the active database.
|
||||
func NewPgDumpCommand(ctx context.Context) (*exec.Cmd, string, error) {
|
||||
dbCfg := config.Config.Database
|
||||
dbCfg := GetDBConfig()
|
||||
|
||||
pgDumpPath, err := exec.LookPath("pg_dump")
|
||||
if err != nil {
|
||||
|
||||
@@ -44,6 +44,13 @@ func newFlushLogTestCache(t *testing.T) (contracts.CacheService, *miniredis.Mini
|
||||
|
||||
p := cacheplugin.New(cacheplugin.WithRedis(rdb), cacheplugin.WithRAMCapacity(64))
|
||||
ctx := core.NewContext(context.Background())
|
||||
ctx.Config().SetSource(core.NewMapSource(map[string]any{
|
||||
"redis": map[string]any{
|
||||
"enabled": true,
|
||||
"addrs": []string{mr.Addr()},
|
||||
},
|
||||
}))
|
||||
require.NoError(t, ctx.Config().Resolve())
|
||||
require.NoError(t, p.Apply(ctx))
|
||||
svc, err := core.Inject[contracts.CacheService](ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -4,22 +4,57 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Wavelet/pkg/config"
|
||||
"Wavelet/plugins/domain/admin/model"
|
||||
"Wavelet/plugins/domain/admin/repository"
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
dbConfigMu sync.RWMutex
|
||||
dbConfig model.DatabaseConfig
|
||||
chConfig model.ClickHouseConfig
|
||||
)
|
||||
|
||||
// SetDBConfig sets the database configuration in service and repository.
|
||||
func SetDBConfig(cfg model.DatabaseConfig) {
|
||||
dbConfigMu.Lock()
|
||||
defer dbConfigMu.Unlock()
|
||||
dbConfig = cfg
|
||||
repository.SetDBConfig(cfg)
|
||||
}
|
||||
|
||||
// GetDBConfig returns the database configuration.
|
||||
func GetDBConfig() model.DatabaseConfig {
|
||||
dbConfigMu.RLock()
|
||||
defer dbConfigMu.RUnlock()
|
||||
return dbConfig
|
||||
}
|
||||
|
||||
// SetClickHouseConfig sets the clickhouse configuration.
|
||||
func SetClickHouseConfig(cfg model.ClickHouseConfig) {
|
||||
dbConfigMu.Lock()
|
||||
defer dbConfigMu.Unlock()
|
||||
chConfig = cfg
|
||||
}
|
||||
|
||||
// GetClickHouseConfig returns the clickhouse configuration.
|
||||
func GetClickHouseConfig() model.ClickHouseConfig {
|
||||
dbConfigMu.RLock()
|
||||
defer dbConfigMu.RUnlock()
|
||||
return chConfig
|
||||
}
|
||||
|
||||
// selectSQLKeywords marks statements that return a result set instead of a row count.
|
||||
var selectSQLKeywords = []string{"select", "show", "explain", "describe", "pragma"}
|
||||
|
||||
// DatabaseOverview collects the runtime overview of the active database.
|
||||
func DatabaseOverview(ctx context.Context) (model.DBOverviewResponse, error) {
|
||||
if !config.Config.Database.Enabled {
|
||||
if !GetDBConfig().Enabled {
|
||||
return repository.GetSQLiteOverview(ctx)
|
||||
}
|
||||
return repository.GetPostgresOverview(ctx)
|
||||
@@ -114,7 +149,7 @@ func isSelectStatement(trimmedSQL string) bool {
|
||||
|
||||
// DatabaseInfo returns the active database type, name and version.
|
||||
func DatabaseInfo(ctx context.Context) model.DatabaseInfoResponse {
|
||||
if !config.Config.Database.Enabled {
|
||||
if !GetDBConfig().Enabled {
|
||||
return repository.GetSQLiteInfo(ctx)
|
||||
}
|
||||
return repository.GetPostgresInfo(ctx)
|
||||
|
||||
@@ -5,7 +5,6 @@ package service
|
||||
|
||||
import (
|
||||
"Wavelet/core/contracts"
|
||||
"Wavelet/pkg/config"
|
||||
"Wavelet/pkg/logger"
|
||||
"Wavelet/plugins/domain/admin/errs"
|
||||
"Wavelet/plugins/domain/admin/model"
|
||||
@@ -139,15 +138,15 @@ func validateSwitch(ctx context.Context, target string) error {
|
||||
}
|
||||
switch target {
|
||||
case targetClickHouse:
|
||||
if !config.Config.ClickHouse.Enabled {
|
||||
if !GetClickHouseConfig().Enabled {
|
||||
return errors.New(errs.ErrClickHouseNotEnabled)
|
||||
}
|
||||
case targetPostgres:
|
||||
if !config.Config.Database.Enabled {
|
||||
if !GetDBConfig().Enabled {
|
||||
return errors.New(errs.ErrPostgresNotEnabled)
|
||||
}
|
||||
case targetSQLite:
|
||||
if config.Config.Database.Enabled {
|
||||
if GetDBConfig().Enabled {
|
||||
return errors.New(errs.ErrSQLiteNotAllowedAsLogDB)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Wavelet/pkg/config"
|
||||
"Wavelet/pkg/logger"
|
||||
"Wavelet/plugins/domain/admin/model"
|
||||
"Wavelet/plugins/domain/admin/repository"
|
||||
@@ -152,12 +151,12 @@ func retentionOr(ctx context.Context, key string) int {
|
||||
|
||||
func availableLogTargets(active string) []string {
|
||||
if active == logDBNameClickHouse {
|
||||
if config.Config.Database.Enabled {
|
||||
if GetDBConfig().Enabled {
|
||||
return []string{logDBNamePostgres}
|
||||
}
|
||||
return []string{logDBNameSQLite}
|
||||
}
|
||||
if config.Config.ClickHouse.Enabled {
|
||||
if GetClickHouseConfig().Enabled {
|
||||
return []string{logDBNameClickHouse}
|
||||
}
|
||||
return []string{}
|
||||
|
||||
Reference in New Issue
Block a user