后端重构

This commit is contained in:
Yvan
2026-01-14 14:34:49 +08:00
parent f5f77b32fe
commit 30842b42e5
274 changed files with 39754 additions and 1005 deletions
+189
View File
@@ -0,0 +1,189 @@
package initialize
import (
"kra/internal/conf"
"gorm.io/gorm"
)
const SystemDB = "system"
// DBList 数据库列表管理器
type DBList struct {
dbs map[string]*gorm.DB
}
// NewDBList 创建数据库列表
func NewDBList() *DBList {
return &DBList{
dbs: make(map[string]*gorm.DB),
}
}
// InitDBList 初始化多数据库连接
func InitDBList(dbList []*conf.SpecializedDB) (*DBList, error) {
list := NewDBList()
for _, info := range dbList {
if info.Disable {
continue
}
var db *gorm.DB
var err error
switch info.Type {
case "mysql":
db, err = GormMysqlByConfig(specializedDBToMysql(info))
case "pgsql":
db, err = GormPgsqlByConfig(specializedDBToPgsql(info))
case "sqlite":
db, err = GormSqliteByConfig(specializedDBToSqlite(info))
case "mssql":
db, err = GormMssqlByConfig(specializedDBToMssql(info))
case "oracle":
db, err = GormOracleByConfig(specializedDBToOracle(info))
default:
continue
}
if err != nil {
return nil, err
}
if db != nil {
list.dbs[info.AliasName] = db
}
}
return list, nil
}
// Get 获取指定名称的数据库连接
func (l *DBList) Get(name string) *gorm.DB {
if l.dbs == nil {
return nil
}
return l.dbs[name]
}
// GetSystem 获取系统数据库连接
func (l *DBList) GetSystem() *gorm.DB {
return l.Get(SystemDB)
}
// Set 设置数据库连接
func (l *DBList) Set(name string, db *gorm.DB) {
if l.dbs == nil {
l.dbs = make(map[string]*gorm.DB)
}
l.dbs[name] = db
}
// All 获取所有数据库连接
func (l *DBList) All() map[string]*gorm.DB {
return l.dbs
}
// Close 关闭所有数据库连接
func (l *DBList) Close() error {
for _, db := range l.dbs {
sqlDB, err := db.DB()
if err != nil {
continue
}
sqlDB.Close()
}
return nil
}
// specializedDBToMysql 转换为MySQL配置
func specializedDBToMysql(s *conf.SpecializedDB) *conf.Mysql {
return &conf.Mysql{
Prefix: s.Prefix,
Path: s.Path,
Port: s.Port,
Config: s.Config,
DbName: s.DbName,
Username: s.Username,
Password: s.Password,
Engine: s.Engine,
MaxIdleConns: s.MaxIdleConns,
MaxOpenConns: s.MaxOpenConns,
LogMode: s.LogMode,
LogZap: s.LogZap,
Singular: s.Singular,
}
}
// specializedDBToPgsql 转换为PostgreSQL配置
func specializedDBToPgsql(s *conf.SpecializedDB) *conf.Pgsql {
return &conf.Pgsql{
Prefix: s.Prefix,
Path: s.Path,
Port: s.Port,
Config: s.Config,
DbName: s.DbName,
Username: s.Username,
Password: s.Password,
Engine: s.Engine,
MaxIdleConns: s.MaxIdleConns,
MaxOpenConns: s.MaxOpenConns,
LogMode: s.LogMode,
LogZap: s.LogZap,
Singular: s.Singular,
}
}
// specializedDBToSqlite 转换为SQLite配置
func specializedDBToSqlite(s *conf.SpecializedDB) *conf.Sqlite {
return &conf.Sqlite{
Prefix: s.Prefix,
Path: s.Path,
DbName: s.DbName,
Engine: s.Engine,
MaxIdleConns: s.MaxIdleConns,
MaxOpenConns: s.MaxOpenConns,
LogMode: s.LogMode,
LogZap: s.LogZap,
Singular: s.Singular,
}
}
// specializedDBToMssql 转换为MSSQL配置
func specializedDBToMssql(s *conf.SpecializedDB) *conf.Mssql {
return &conf.Mssql{
Prefix: s.Prefix,
Path: s.Path,
Port: s.Port,
Config: s.Config,
DbName: s.DbName,
Username: s.Username,
Password: s.Password,
Engine: s.Engine,
MaxIdleConns: s.MaxIdleConns,
MaxOpenConns: s.MaxOpenConns,
LogMode: s.LogMode,
LogZap: s.LogZap,
Singular: s.Singular,
}
}
// specializedDBToOracle 转换为Oracle配置
func specializedDBToOracle(s *conf.SpecializedDB) *conf.Oracle {
return &conf.Oracle{
Prefix: s.Prefix,
Path: s.Path,
Port: s.Port,
Config: s.Config,
DbName: s.DbName,
Username: s.Username,
Password: s.Password,
Engine: s.Engine,
MaxIdleConns: s.MaxIdleConns,
MaxOpenConns: s.MaxOpenConns,
LogMode: s.LogMode,
LogZap: s.LogZap,
Singular: s.Singular,
}
}
+69
View File
@@ -0,0 +1,69 @@
package initialize
import (
"time"
"kra/internal/conf"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
// GormConfig 创建GORM配置
func GormConfig(prefix string, singular bool, logMode string) *gorm.Config {
return &gorm.Config{
Logger: logger.Default.LogMode(parseLogLevel(logMode)),
NamingStrategy: schema.NamingStrategy{
TablePrefix: prefix,
SingularTable: singular,
},
DisableForeignKeyConstraintWhenMigrating: true,
}
}
// GormConfigWithSlowThreshold 创建带慢查询阈值的GORM配置
func GormConfigWithSlowThreshold(prefix string, singular bool, logMode string, slowThreshold time.Duration) *gorm.Config {
return &gorm.Config{
Logger: logger.Default.LogMode(parseLogLevel(logMode)),
NamingStrategy: schema.NamingStrategy{
TablePrefix: prefix,
SingularTable: singular,
},
DisableForeignKeyConstraintWhenMigrating: true,
}
}
// parseLogLevel 解析日志级别
func parseLogLevel(level string) logger.LogLevel {
switch level {
case "silent":
return logger.Silent
case "error":
return logger.Error
case "warn":
return logger.Warn
case "info":
return logger.Info
default:
return logger.Info
}
}
// NewDBByType 根据数据库类型创建数据库连接
func NewDBByType(dbType string, bootstrap *conf.Bootstrap) (*gorm.DB, error) {
switch dbType {
case "mysql":
return GormMysql(bootstrap.Mysql)
case "pgsql":
return GormPgsql(bootstrap.Pgsql)
case "sqlite":
return GormSqlite(bootstrap.Sqlite)
case "mssql":
return GormMssql(bootstrap.Mssql)
case "oracle":
return GormOracle(bootstrap.Oracle)
default:
return GormMysql(bootstrap.Mysql)
}
}
+63
View File
@@ -0,0 +1,63 @@
package initialize
import (
"fmt"
"kra/internal/conf"
"gorm.io/driver/sqlserver"
"gorm.io/gorm"
)
// GormMssql 初始化MSSQL数据库
func GormMssql(m *conf.Mssql) (*gorm.DB, error) {
if m == nil || m.DbName == "" {
return nil, fmt.Errorf("mssql config is empty")
}
return initMssqlDatabase(m)
}
// GormMssqlByConfig 通过传入配置初始化MSSQL数据库
func GormMssqlByConfig(m *conf.Mssql) (*gorm.DB, error) {
return initMssqlDatabase(m)
}
// initMssqlDatabase 初始化MSSQL数据库的辅助函数
func initMssqlDatabase(m *conf.Mssql) (*gorm.DB, error) {
if m.DbName == "" {
return nil, nil
}
dsn := MssqlDsn(m)
mssqlConfig := sqlserver.Config{
DSN: dsn,
DefaultStringSize: 191,
}
gormConfig := GormConfig(m.Prefix, m.Singular, m.LogMode)
db, err := gorm.Open(sqlserver.New(mssqlConfig), gormConfig)
if err != nil {
return nil, err
}
if m.Engine != "" {
db.InstanceSet("gorm:table_options", "ENGINE="+m.Engine)
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(m.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(m.MaxOpenConns))
return db, nil
}
// MssqlDsn 生成MSSQL DSN
func MssqlDsn(m *conf.Mssql) string {
return fmt.Sprintf("sqlserver://%s:%s@%s:%s?database=%s&%s",
m.Username, m.Password, m.Path, m.Port, m.DbName, m.Config)
}
+65
View File
@@ -0,0 +1,65 @@
package initialize
import (
"fmt"
"kra/internal/conf"
_ "github.com/go-sql-driver/mysql"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// GormMysql 初始化MySQL数据库
func GormMysql(m *conf.Mysql) (*gorm.DB, error) {
if m == nil || m.DbName == "" {
return nil, fmt.Errorf("mysql config is empty")
}
return initMysqlDatabase(m)
}
// GormMysqlByConfig 通过传入配置初始化MySQL数据库
func GormMysqlByConfig(m *conf.Mysql) (*gorm.DB, error) {
return initMysqlDatabase(m)
}
// initMysqlDatabase 初始化MySQL数据库的辅助函数
func initMysqlDatabase(m *conf.Mysql) (*gorm.DB, error) {
if m.DbName == "" {
return nil, nil
}
dsn := MysqlDsn(m)
mysqlConfig := mysql.Config{
DSN: dsn,
DefaultStringSize: 191,
SkipInitializeWithVersion: false,
}
gormConfig := GormConfig(m.Prefix, m.Singular, m.LogMode)
db, err := gorm.Open(mysql.New(mysqlConfig), gormConfig)
if err != nil {
return nil, err
}
if m.Engine != "" {
db.InstanceSet("gorm:table_options", "ENGINE="+m.Engine)
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(m.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(m.MaxOpenConns))
return db, nil
}
// MysqlDsn 生成MySQL DSN
func MysqlDsn(m *conf.Mysql) string {
return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s",
m.Username, m.Password, m.Path, m.Port, m.DbName, m.Config)
}
+54
View File
@@ -0,0 +1,54 @@
package initialize
import (
"fmt"
"kra/internal/conf"
oracle "github.com/dzwvip/gorm-oracle"
"gorm.io/gorm"
)
// GormOracle 初始化Oracle数据库
func GormOracle(o *conf.Oracle) (*gorm.DB, error) {
if o == nil || o.DbName == "" {
return nil, fmt.Errorf("oracle config is empty")
}
return initOracleDatabase(o)
}
// GormOracleByConfig 通过传入配置初始化Oracle数据库
func GormOracleByConfig(o *conf.Oracle) (*gorm.DB, error) {
return initOracleDatabase(o)
}
// initOracleDatabase 初始化Oracle数据库的辅助函数
func initOracleDatabase(o *conf.Oracle) (*gorm.DB, error) {
if o.DbName == "" {
return nil, nil
}
dsn := OracleDsn(o)
gormConfig := GormConfig(o.Prefix, o.Singular, o.LogMode)
db, err := gorm.Open(oracle.Open(dsn), gormConfig)
if err != nil {
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(o.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(o.MaxOpenConns))
return db, nil
}
// OracleDsn 生成Oracle DSN
func OracleDsn(o *conf.Oracle) string {
return fmt.Sprintf("oracle://%s:%s@%s:%s/%s?%s",
o.Username, o.Password, o.Path, o.Port, o.DbName, o.Config)
}
+59
View File
@@ -0,0 +1,59 @@
package initialize
import (
"fmt"
"kra/internal/conf"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
// GormPgsql 初始化PostgreSQL数据库
func GormPgsql(p *conf.Pgsql) (*gorm.DB, error) {
if p == nil || p.DbName == "" {
return nil, fmt.Errorf("pgsql config is empty")
}
return initPgsqlDatabase(p)
}
// GormPgsqlByConfig 通过传入配置初始化PostgreSQL数据库
func GormPgsqlByConfig(p *conf.Pgsql) (*gorm.DB, error) {
return initPgsqlDatabase(p)
}
// initPgsqlDatabase 初始化PostgreSQL数据库的辅助函数
func initPgsqlDatabase(p *conf.Pgsql) (*gorm.DB, error) {
if p.DbName == "" {
return nil, nil
}
dsn := PgsqlDsn(p)
pgsqlConfig := postgres.Config{
DSN: dsn,
PreferSimpleProtocol: false,
}
gormConfig := GormConfig(p.Prefix, p.Singular, p.LogMode)
db, err := gorm.Open(postgres.New(pgsqlConfig), gormConfig)
if err != nil {
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(p.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(p.MaxOpenConns))
return db, nil
}
// PgsqlDsn 生成PostgreSQL DSN
func PgsqlDsn(p *conf.Pgsql) string {
return fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s %s",
p.Path, p.Username, p.Password, p.DbName, p.Port, p.Config)
}
+56
View File
@@ -0,0 +1,56 @@
package initialize
import (
"fmt"
"kra/internal/conf"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
)
// GormSqlite 初始化SQLite数据库
func GormSqlite(s *conf.Sqlite) (*gorm.DB, error) {
if s == nil || s.DbName == "" {
return nil, fmt.Errorf("sqlite config is empty")
}
return initSqliteDatabase(s)
}
// GormSqliteByConfig 通过传入配置初始化SQLite数据库
func GormSqliteByConfig(s *conf.Sqlite) (*gorm.DB, error) {
return initSqliteDatabase(s)
}
// initSqliteDatabase 初始化SQLite数据库的辅助函数
func initSqliteDatabase(s *conf.Sqlite) (*gorm.DB, error) {
if s.DbName == "" {
return nil, nil
}
dsn := SqliteDsn(s)
gormConfig := GormConfig(s.Prefix, s.Singular, s.LogMode)
db, err := gorm.Open(sqlite.Open(dsn), gormConfig)
if err != nil {
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(s.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(s.MaxOpenConns))
return db, nil
}
// SqliteDsn 生成SQLite DSN
func SqliteDsn(s *conf.Sqlite) string {
if s.Path != "" {
return fmt.Sprintf("%s/%s", s.Path, s.DbName)
}
return s.DbName
}
+193
View File
@@ -0,0 +1,193 @@
package initialize
import (
"kra/internal/conf"
"github.com/gin-gonic/gin"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
// Initializer 初始化器
type Initializer struct {
config *conf.Bootstrap
db *gorm.DB
dbList *DBList
redis *RedisClient
redisList *RedisList
timerManager *TimerManager
pluginManager *PluginManager
mcpServer *MCPServer
}
// NewInitializer 创建初始化器
func NewInitializer(config *conf.Bootstrap) *Initializer {
return &Initializer{
config: config,
}
}
// InitDB 初始化主数据库
func (i *Initializer) InitDB() (*gorm.DB, error) {
dbType := "mysql"
if i.config.System != nil && i.config.System.DbType != "" {
dbType = i.config.System.DbType
}
db, err := NewDBByType(dbType, i.config)
if err != nil {
return nil, err
}
i.db = db
return db, nil
}
// InitDBList 初始化多数据库
func (i *Initializer) InitDBList() (*DBList, error) {
dbList, err := InitDBList(i.config.DbList)
if err != nil {
return nil, err
}
// 如果有system数据库,设置为主数据库
if sysDB := dbList.GetSystem(); sysDB != nil {
i.db = sysDB
}
i.dbList = dbList
return dbList, nil
}
// InitRedis 初始化主Redis
func (i *Initializer) InitRedis() (*RedisClient, error) {
if i.config.Redis == nil {
return nil, nil
}
client, err := NewRedisClient(i.config.Redis)
if err != nil {
return nil, err
}
i.redis = client
return client, nil
}
// InitRedisList 初始化多Redis
func (i *Initializer) InitRedisList() (*RedisList, error) {
redisList, err := InitRedisList(i.config.RedisList)
if err != nil {
return nil, err
}
i.redisList = redisList
return redisList, nil
}
// InitTimer 初始化定时任务
func (i *Initializer) InitTimer() *TimerManager {
manager := NewTimerManager(i.db)
manager.Start()
i.timerManager = manager
return manager
}
// InitPlugin 初始化插件管理器
func (i *Initializer) InitPlugin() *PluginManager {
manager := NewPluginManager(i.db)
i.pluginManager = manager
return manager
}
// InitMCP 初始化MCP服务器
func (i *Initializer) InitMCP() *MCPServer {
server := NewMCPServer(i.config.Mcp)
i.mcpServer = server
return server
}
// DB 获取主数据库
func (i *Initializer) DB() *gorm.DB {
return i.db
}
// DBList 获取数据库列表
func (i *Initializer) DBList() *DBList {
return i.dbList
}
// Redis 获取主Redis客户端
func (i *Initializer) Redis() redis.UniversalClient {
if i.redis == nil {
return nil
}
return i.redis.Client()
}
// RedisList 获取Redis列表
func (i *Initializer) RedisList() *RedisList {
return i.redisList
}
// TimerManager 获取定时任务管理器
func (i *Initializer) TimerManager() *TimerManager {
return i.timerManager
}
// PluginManager 获取插件管理器
func (i *Initializer) PluginManager() *PluginManager {
return i.pluginManager
}
// MCPServer 获取MCP服务器
func (i *Initializer) MCPServer() *MCPServer {
return i.mcpServer
}
// InstallPlugins 安装插件
func (i *Initializer) InstallPlugins(privateGroup *gin.RouterGroup, publicGroup *gin.RouterGroup, engine *gin.Engine) {
if i.pluginManager != nil {
i.pluginManager.InstallPlugins(privateGroup, publicGroup, engine)
}
}
// RegisterMCPRoutes 注册MCP路由
func (i *Initializer) RegisterMCPRoutes(engine *gin.Engine) {
if i.mcpServer != nil {
i.mcpServer.RegisterRoutes(engine)
}
}
// Close 关闭所有资源
func (i *Initializer) Close() error {
// 关闭定时任务
if i.timerManager != nil {
i.timerManager.Stop()
}
// 关闭数据库连接
if i.db != nil {
sqlDB, err := i.db.DB()
if err == nil {
sqlDB.Close()
}
}
// 关闭数据库列表
if i.dbList != nil {
i.dbList.Close()
}
// 关闭Redis连接
if i.redis != nil {
i.redis.Close()
}
// 关闭Redis列表
if i.redisList != nil {
i.redisList.Close()
}
return nil
}
+117
View File
@@ -0,0 +1,117 @@
package initialize
import (
"kra/internal/conf"
mcpTool "kra/pkg/mcp/tool"
"github.com/gin-gonic/gin"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"go.uber.org/zap"
"gorm.io/gorm"
)
// MCPServer MCP服务器包装器
type MCPServer struct {
server *server.MCPServer
sseServer *server.SSEServer
config *conf.MCP
}
// NewMCPServer 创建MCP服务器
func NewMCPServer(config *conf.MCP) *MCPServer {
if config == nil || !config.Enabled {
return nil
}
s := server.NewMCPServer(
config.Name,
config.Version,
)
sseServer := server.NewSSEServer(s,
server.WithSSEEndpoint(config.SsePath),
server.WithMessageEndpoint(config.MessagePath),
server.WithBaseURL(config.UrlPrefix))
return &MCPServer{
server: s,
sseServer: sseServer,
config: config,
}
}
// Server 获取MCP服务器实例
func (m *MCPServer) Server() *server.MCPServer {
if m == nil {
return nil
}
return m.server
}
// SSEServer 获取SSE服务器实例
func (m *MCPServer) SSEServer() *server.SSEServer {
if m == nil {
return nil
}
return m.sseServer
}
// Config 获取MCP配置
func (m *MCPServer) Config() *conf.MCP {
if m == nil {
return nil
}
return m.config
}
// RegisterRoutes 注册MCP路由到Gin引擎
func (m *MCPServer) RegisterRoutes(engine *gin.Engine) {
if m == nil || m.sseServer == nil || m.config == nil {
return
}
// 如果不是独立模式,注册到主服务
if !m.config.Separate {
// 注册SSE端点
engine.GET(m.config.SsePath, func(c *gin.Context) {
m.sseServer.SSEHandler().ServeHTTP(c.Writer, c.Request)
})
// 注册消息端点
engine.POST(m.config.MessagePath, func(c *gin.Context) {
m.sseServer.MessageHandler().ServeHTTP(c.Writer, c.Request)
})
}
}
// RegisterTool 注册MCP工具
func (m *MCPServer) RegisterTool(tool mcp.Tool, handler server.ToolHandlerFunc) {
if m == nil || m.server == nil {
return
}
m.server.AddTool(tool, handler)
}
// MCPToolRegistrar MCP工具注册器接口
type MCPToolRegistrar interface {
RegisterTools(s *server.MCPServer)
}
// RegisterAllTools 注册所有MCP工具
func (m *MCPServer) RegisterAllTools(registrars ...MCPToolRegistrar) {
if m == nil || m.server == nil {
return
}
for _, registrar := range registrars {
registrar.RegisterTools(m.server)
}
}
// RegisterMCPTools 注册所有MCP工具(带依赖注入)
func (m *MCPServer) RegisterMCPTools(db *gorm.DB, logger *zap.Logger, autoCodeConfig *mcpTool.AutoCodeConfig) {
if m == nil || m.server == nil {
return
}
mcpTool.RegisterAllToolsWithDependencies(m.server, db, logger, autoCodeConfig)
}
+99
View File
@@ -0,0 +1,99 @@
package initialize
import (
"fmt"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// Plugin 插件接口 (v1版本)
type Plugin interface {
// Register 注册路由
Register(group *gin.RouterGroup)
// RouterPath 返回路由路径
RouterPath() string
}
// PluginV2 插件接口 (v2版本)
type PluginV2 interface {
// Register 注册到引擎
Register(engine *gin.Engine)
}
// PluginManager 插件管理器
type PluginManager struct {
db *gorm.DB
pluginsV1 []Plugin
pluginsV2 []PluginV2
initialized bool
}
// NewPluginManager 创建插件管理器
func NewPluginManager(db *gorm.DB) *PluginManager {
return &PluginManager{
db: db,
pluginsV1: make([]Plugin, 0),
pluginsV2: make([]PluginV2, 0),
}
}
// RegisterPluginV1 注册V1版本插件
func (m *PluginManager) RegisterPluginV1(plugin Plugin) {
m.pluginsV1 = append(m.pluginsV1, plugin)
}
// RegisterPluginV2 注册V2版本插件
func (m *PluginManager) RegisterPluginV2(plugin PluginV2) {
m.pluginsV2 = append(m.pluginsV2, plugin)
}
// InstallPlugins 安装所有插件
func (m *PluginManager) InstallPlugins(privateGroup *gin.RouterGroup, publicGroup *gin.RouterGroup, engine *gin.Engine) {
if m.db == nil {
fmt.Println("项目暂未初始化,无法安装插件,初始化后重启项目即可完成插件安装")
return
}
// 安装V1版本插件
m.installPluginsV1(privateGroup, publicGroup)
// 安装V2版本插件
m.installPluginsV2(engine)
m.initialized = true
}
// installPluginsV1 安装V1版本插件
func (m *PluginManager) installPluginsV1(privateGroup *gin.RouterGroup, publicGroup *gin.RouterGroup) {
for _, plugin := range m.pluginsV1 {
fmt.Printf("%s 注册开始!\n", plugin.RouterPath())
pluginGroup := privateGroup.Group(plugin.RouterPath())
plugin.Register(pluginGroup)
fmt.Printf("%s 注册成功!\n", plugin.RouterPath())
}
}
// installPluginsV2 安装V2版本插件
func (m *PluginManager) installPluginsV2(engine *gin.Engine) {
for _, plugin := range m.pluginsV2 {
plugin.Register(engine)
}
}
// PluginInit 初始化V1版本插件(兼容旧版方式)
func PluginInit(group *gin.RouterGroup, plugins ...Plugin) {
for _, plugin := range plugins {
fmt.Printf("%s 注册开始!\n", plugin.RouterPath())
pluginGroup := group.Group(plugin.RouterPath())
plugin.Register(pluginGroup)
fmt.Printf("%s 注册成功!\n", plugin.RouterPath())
}
}
// PluginInitV2 初始化V2版本插件(兼容旧版方式)
func PluginInitV2(engine *gin.Engine, plugins ...PluginV2) {
for _, plugin := range plugins {
plugin.Register(engine)
}
}
+8
View File
@@ -0,0 +1,8 @@
package initialize
import (
"github.com/google/wire"
)
// ProviderSet is initialize providers.
var ProviderSet = wire.NewSet(NewTimerManager)
+136
View File
@@ -0,0 +1,136 @@
package initialize
import (
"context"
"fmt"
"kra/internal/conf"
"github.com/redis/go-redis/v9"
)
// RedisClient Redis客户端包装器
type RedisClient struct {
client redis.UniversalClient
name string
}
// NewRedisClient 创建Redis客户端
func NewRedisClient(cfg *conf.Redis) (*RedisClient, error) {
if cfg == nil {
return nil, fmt.Errorf("redis config is nil")
}
client, err := initRedisClient(cfg)
if err != nil {
return nil, err
}
return &RedisClient{
client: client,
name: cfg.Name,
}, nil
}
// initRedisClient 初始化Redis客户端
func initRedisClient(cfg *conf.Redis) (redis.UniversalClient, error) {
var client redis.UniversalClient
// 使用集群模式
if cfg.UseCluster {
client = redis.NewClusterClient(&redis.ClusterOptions{
Addrs: cfg.ClusterAddrs,
Password: cfg.Password,
})
} else {
// 使用单例模式
client = redis.NewClient(&redis.Options{
Addr: cfg.Addr,
Password: cfg.Password,
DB: int(cfg.Db),
})
}
// 测试连接
pong, err := client.Ping(context.Background()).Result()
if err != nil {
return nil, fmt.Errorf("redis connect ping failed, name: %s, err: %v", cfg.Name, err)
}
_ = pong // 连接成功
return client, nil
}
// Client 获取Redis客户端
func (r *RedisClient) Client() redis.UniversalClient {
return r.client
}
// Name 获取Redis名称
func (r *RedisClient) Name() string {
return r.name
}
// Close 关闭Redis连接
func (r *RedisClient) Close() error {
if r.client != nil {
return r.client.Close()
}
return nil
}
// RedisList Redis列表管理器
type RedisList struct {
clients map[string]*RedisClient
}
// NewRedisList 创建Redis列表
func NewRedisList() *RedisList {
return &RedisList{
clients: make(map[string]*RedisClient),
}
}
// InitRedisList 初始化多Redis连接
func InitRedisList(redisList []*conf.Redis) (*RedisList, error) {
list := NewRedisList()
for _, cfg := range redisList {
client, err := NewRedisClient(cfg)
if err != nil {
return nil, err
}
list.clients[cfg.Name] = client
}
return list, nil
}
// Get 获取指定名称的Redis客户端
func (l *RedisList) Get(name string) *RedisClient {
if l.clients == nil {
return nil
}
return l.clients[name]
}
// Set 设置Redis客户端
func (l *RedisList) Set(name string, client *RedisClient) {
if l.clients == nil {
l.clients = make(map[string]*RedisClient)
}
l.clients[name] = client
}
// All 获取所有Redis客户端
func (l *RedisList) All() map[string]*RedisClient {
return l.clients
}
// Close 关闭所有Redis连接
func (l *RedisList) Close() error {
for _, client := range l.clients {
client.Close()
}
return nil
}
+105
View File
@@ -0,0 +1,105 @@
package initialize
import (
"net/http"
"os"
"kra/internal/conf"
"github.com/gin-gonic/gin"
)
// justFilesFilesystem 只允许访问文件的文件系统
type justFilesFilesystem struct {
fs http.FileSystem
}
func (fs justFilesFilesystem) Open(name string) (http.File, error) {
f, err := fs.fs.Open(name)
if err != nil {
return nil, err
}
stat, err := f.Stat()
if err != nil {
f.Close()
return nil, err
}
if stat.IsDir() {
f.Close()
return nil, os.ErrPermission
}
return f, nil
}
// RouterConfig 路由配置
type RouterConfig struct {
RouterPrefix string
StorePath string
SwaggerPath string
}
// NewRouterConfig 创建路由配置
func NewRouterConfig(system *conf.System, local *conf.Local) *RouterConfig {
cfg := &RouterConfig{
RouterPrefix: "",
StorePath: "uploads/file",
SwaggerPath: "/swagger/*any",
}
if system != nil {
cfg.RouterPrefix = system.RouterPrefix
}
if local != nil && local.StorePath != "" {
cfg.StorePath = local.StorePath
}
return cfg
}
// SetupStaticFiles 设置静态文件服务
func SetupStaticFiles(engine *gin.Engine, storePath string) {
if storePath != "" {
engine.StaticFS(storePath, justFilesFilesystem{http.Dir(storePath)})
}
}
// SetupHealthCheck 设置健康检查端点
func SetupHealthCheck(group *gin.RouterGroup) {
group.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, "ok")
})
}
// RouterGroups 路由组集合
type RouterGroups struct {
Public *gin.RouterGroup
Private *gin.RouterGroup
}
// NewRouterGroups 创建路由组
func NewRouterGroups(engine *gin.Engine, prefix string) *RouterGroups {
return &RouterGroups{
Public: engine.Group(prefix),
Private: engine.Group(prefix),
}
}
// RouteInfo 路由信息
type RouteInfo struct {
Method string
Path string
Handler string
HandlerFunc gin.HandlerFunc
}
// Routes 路由列表
type Routes []RouteInfo
// GetRoutes 获取所有路由信息
func GetRoutes(engine *gin.Engine) gin.RoutesInfo {
return engine.Routes()
}
+68
View File
@@ -0,0 +1,68 @@
package initialize
import (
"fmt"
"kra/internal/task"
"kra/pkg/timer"
"github.com/robfig/cron/v3"
"gorm.io/gorm"
)
// TimerManager 定时任务管理器
type TimerManager struct {
timer timer.Timer
db *gorm.DB
}
// NewTimerManager 创建定时任务管理器
func NewTimerManager(db *gorm.DB) *TimerManager {
return &TimerManager{
timer: timer.NewTimerTask(),
db: db,
}
}
// Timer 获取定时器实例
func (m *TimerManager) Timer() timer.Timer {
return m.timer
}
// Start 启动定时任务
func (m *TimerManager) Start() {
go func() {
var option []cron.Option
option = append(option, cron.WithSeconds())
// 清理DB定时任务
_, err := m.timer.AddTaskByFunc("ClearDB", "@daily", func() {
err := task.ClearTable(m.db)
if err != nil {
fmt.Println("timer error:", err)
}
}, "定时清理数据库【日志,黑名单】内容", option...)
if err != nil {
fmt.Println("add timer error:", err)
}
// 其他定时任务可以在这里添加
}()
}
// Stop 停止定时任务
func (m *TimerManager) Stop() {
if m.timer != nil {
m.timer.Close()
}
}
// AddTask 添加定时任务
func (m *TimerManager) AddTask(name, spec string, fn func(), desc string, options ...cron.Option) (cron.EntryID, error) {
return m.timer.AddTaskByFunc(name, spec, fn, desc, options...)
}
// RemoveTask 移除定时任务
func (m *TimerManager) RemoveTask(name string) {
m.timer.Clear(name)
}
+35
View File
@@ -0,0 +1,35 @@
package initialize
import (
"kra/pkg/utils"
)
// InitValidator 初始化验证器规则
func InitValidator() {
// 分页验证规则
_ = utils.RegisterRule("PageVerify",
utils.Rules{
"Page": {utils.NotEmpty()},
"PageSize": {utils.NotEmpty()},
},
)
// ID验证规则
_ = utils.RegisterRule("IdVerify",
utils.Rules{
"Id": {utils.NotEmpty()},
},
)
// 权限ID验证规则
_ = utils.RegisterRule("AuthorityIdVerify",
utils.Rules{
"AuthorityId": {utils.NotEmpty()},
},
)
}
// init 包初始化时自动注册验证规则
func init() {
InitValidator()
}