mirror of
https://github.com/skyle1995/NetworkAuth.git
synced 2026-05-25 02:24:05 +08:00
更新底层架构
This commit is contained in:
270
cmd/root.go
270
cmd/root.go
@@ -1,142 +1,128 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"networkDev/config"
|
||||
"networkDev/utils/logger"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
// ============================================================================
|
||||
// 全局变量
|
||||
// ============================================================================
|
||||
|
||||
var cfgFile string
|
||||
|
||||
// ============================================================================
|
||||
// 命令定义
|
||||
// ============================================================================
|
||||
|
||||
// rootCmd 代表没有调用子命令时的基础命令
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "networkDev",
|
||||
Short: "一个基于Cobra的网络验证服务器应用",
|
||||
Long: `networkDev是一个使用Cobra CLI框架构建的网络验证服务器应用,
|
||||
集成了Viper配置管理、Logrus日志记录和embed静态资源嵌入功能。`,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
// 在加载配置前配置logrus用于非HTTP日志
|
||||
|
||||
setupLogrusForNonHTTP()
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 公共函数
|
||||
// ============================================================================
|
||||
|
||||
// Execute 添加所有子命令到根命令并设置适当的标志
|
||||
// 这由main.main()调用。只需要对rootCmd执行一次。
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
// 在这里定义标志和配置设置
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "配置文件路径 (默认为 config.json)")
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 私有函数
|
||||
// ============================================================================
|
||||
|
||||
// setupLogrusForNonHTTP 配置logrus用于非HTTP日志
|
||||
// 在加载配置文件之前进行基本的logrus设置
|
||||
func setupLogrusForNonHTTP() {
|
||||
// 设置日志格式
|
||||
logrus.SetFormatter(&logrus.TextFormatter{
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
FullTimestamp: true,
|
||||
ForceColors: false,
|
||||
DisableColors: true,
|
||||
})
|
||||
|
||||
// 设置默认日志级别
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
|
||||
// 设置输出目标(稍后会根据配置文件调整)
|
||||
logrus.SetOutput(os.Stdout)
|
||||
if cfgFile != "" {
|
||||
config.Init(cfgFile)
|
||||
} else {
|
||||
config.Init("./config.json")
|
||||
}
|
||||
|
||||
// 根据配置文件进一步配置logrus
|
||||
setupLogrusFromConfig()
|
||||
|
||||
// 初始化HTTP日志处理器
|
||||
logger.InitLogger()
|
||||
|
||||
// 记录配置加载完成
|
||||
logrus.Info("配置文件加载完成")
|
||||
}
|
||||
|
||||
// initConfig 读取配置文件和环境变量
|
||||
func initConfig() {
|
||||
|
||||
}
|
||||
|
||||
// setupLogrusFromConfig 根据配置文件进一步配置logrus
|
||||
// 设置日志级别和输出目标,支持日志切割功能
|
||||
func setupLogrusFromConfig() {
|
||||
// 设置日志级别
|
||||
if level := viper.GetString("log.level"); level != "" {
|
||||
if logLevel, err := logrus.ParseLevel(level); err == nil {
|
||||
logrus.SetLevel(logLevel)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置日志输出目标
|
||||
logFile := viper.GetString("log.file")
|
||||
if logFile != "" {
|
||||
// 确保日志目录存在
|
||||
logDir := filepath.Dir(logFile)
|
||||
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||||
logrus.WithError(err).Error("创建日志目录失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 配置lumberjack日志轮转
|
||||
lumberjackLogger := &lumberjack.Logger{
|
||||
Filename: logFile,
|
||||
MaxSize: viper.GetInt("log.max_size"), // MB
|
||||
MaxBackups: viper.GetInt("log.max_backups"), // 保留的旧日志文件数量
|
||||
MaxAge: viper.GetInt("log.max_age"), // 天数
|
||||
Compress: true, // 压缩旧日志文件
|
||||
}
|
||||
|
||||
// 同时输出到控制台和文件(带日志切割)
|
||||
multiWriter := io.MultiWriter(os.Stdout, lumberjackLogger)
|
||||
logrus.SetOutput(multiWriter)
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"file": logFile,
|
||||
"max_size": viper.GetInt("log.max_size"),
|
||||
"max_backups": viper.GetInt("log.max_backups"),
|
||||
"max_age": viper.GetInt("log.max_age"),
|
||||
}).Info("日志切割功能已启用")
|
||||
}
|
||||
// 当日志文件路径为空时,保持默认输出到控制台,不创建任何目录
|
||||
}
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"NetworkAuth/config"
|
||||
"NetworkAuth/utils/logger"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
var cfgFile string
|
||||
|
||||
// rootCmd 代表没有调用子命令时的基础命令
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "NetworkAuth",
|
||||
Short: "网络授权服务命令行工具",
|
||||
Long: `网络授权服务 (NetworkAuth) 是一个专注于应用鉴权、接口管理和动态逻辑分发的后端系统。
|
||||
本命令行工具用于启动服务器、管理配置和执行维护任务。`,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
// 在加载配置前配置logrus用于非HTTP日志
|
||||
|
||||
setupLogrusForNonHTTP()
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
// Execute 添加所有子命令到根命令并设置适当的标志
|
||||
// 这由main.main()调用。只需要对rootCmd执行一次。
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
// 在这里定义标志和配置设置
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "配置文件路径 (默认为 config.json)")
|
||||
}
|
||||
|
||||
// setupLogrusForNonHTTP 配置logrus用于非HTTP日志
|
||||
// 在加载配置文件之前进行基本的logrus设置
|
||||
func setupLogrusForNonHTTP() {
|
||||
// 设置日志格式
|
||||
logrus.SetFormatter(&logrus.TextFormatter{
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
FullTimestamp: true,
|
||||
ForceColors: false,
|
||||
DisableColors: true,
|
||||
})
|
||||
|
||||
// 设置默认日志级别
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
|
||||
// 设置输出目标(稍后会根据配置文件调整)
|
||||
logrus.SetOutput(os.Stdout)
|
||||
if cfgFile != "" {
|
||||
// 使用命令行指定的配置文件
|
||||
config.Init(cfgFile)
|
||||
} else {
|
||||
// 使用默认配置文件路径
|
||||
config.Init("./config.json")
|
||||
}
|
||||
|
||||
// 根据配置文件进一步配置logrus
|
||||
setupLogrusFromConfig()
|
||||
|
||||
// 初始化HTTP日志处理器
|
||||
logger.InitLogger()
|
||||
|
||||
// 记录配置加载完成
|
||||
logrus.WithField("file", viper.ConfigFileUsed()).Info("配置文件加载完成")
|
||||
}
|
||||
|
||||
// initConfig 读取配置文件和环境变量
|
||||
func initConfig() {
|
||||
|
||||
}
|
||||
|
||||
// setupLogrusFromConfig 根据配置文件进一步配置logrus
|
||||
// 设置日志级别和输出目标,支持日志切割功能
|
||||
func setupLogrusFromConfig() {
|
||||
// 设置日志级别
|
||||
if level := viper.GetString("log.level"); level != "" {
|
||||
if logLevel, err := logrus.ParseLevel(level); err == nil {
|
||||
logrus.SetLevel(logLevel)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置日志输出目标
|
||||
logFile := viper.GetString("log.file")
|
||||
if logFile != "" {
|
||||
// 确保日志目录存在
|
||||
logDir := filepath.Dir(logFile)
|
||||
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||||
logrus.WithError(err).Error("创建日志目录失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 配置lumberjack日志轮转
|
||||
lumberjackLogger := &lumberjack.Logger{
|
||||
Filename: logFile,
|
||||
MaxSize: viper.GetInt("log.max_size"), // MB
|
||||
MaxBackups: viper.GetInt("log.max_backups"), // 保留的旧日志文件数量
|
||||
MaxAge: viper.GetInt("log.max_age"), // 天数
|
||||
Compress: true, // 压缩旧日志文件
|
||||
}
|
||||
|
||||
// 同时输出到控制台和文件(带日志切割)
|
||||
multiWriter := io.MultiWriter(os.Stdout, lumberjackLogger)
|
||||
logrus.SetOutput(multiWriter)
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"file": logFile,
|
||||
"max_size": viper.GetInt("log.max_size"),
|
||||
"max_backups": viper.GetInt("log.max_backups"),
|
||||
"max_age": viper.GetInt("log.max_age"),
|
||||
}).Info("日志切割功能已启用")
|
||||
}
|
||||
// 当日志文件路径为空时,保持默认输出到控制台,不创建任何目录
|
||||
}
|
||||
|
||||
151
cmd/server.go
151
cmd/server.go
@@ -3,19 +3,19 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"networkDev/database"
|
||||
"networkDev/middleware"
|
||||
"networkDev/server"
|
||||
"networkDev/utils"
|
||||
"networkDev/utils/logger"
|
||||
"networkDev/web"
|
||||
"NetworkAuth/database"
|
||||
"NetworkAuth/middleware"
|
||||
"NetworkAuth/server"
|
||||
"NetworkAuth/services"
|
||||
"NetworkAuth/utils"
|
||||
"NetworkAuth/utils/logger"
|
||||
"NetworkAuth/web"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -23,22 +23,14 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// ============================================================================
|
||||
// 命令定义
|
||||
// ============================================================================
|
||||
|
||||
// serverCmd 代表服务器命令
|
||||
var serverCmd = &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "启动HTTP服务器",
|
||||
Long: `启动一个简单的HTTP服务器,监听配置文件中指定的端口。`,
|
||||
Short: "启动网络授权服务",
|
||||
Long: `启动 NetworkAuth HTTP 服务器,监听配置文件中指定的端口,提供 Web 管理界面和 API 服务。`,
|
||||
Run: runServer,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 初始化函数
|
||||
// ============================================================================
|
||||
|
||||
func init() {
|
||||
// 将服务器命令添加到根命令
|
||||
rootCmd.AddCommand(serverCmd)
|
||||
@@ -48,10 +40,6 @@ func init() {
|
||||
serverCmd.Flags().IntP("port", "p", 0, "服务器监听端口 (覆盖配置文件)")
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 主要函数
|
||||
// ============================================================================
|
||||
|
||||
// runServer 运行HTTP服务器
|
||||
func runServer(cmd *cobra.Command, args []string) {
|
||||
// 获取配置
|
||||
@@ -63,21 +51,47 @@ func runServer(cmd *cobra.Command, args []string) {
|
||||
logger := logger.GetLogger()
|
||||
logger.LogServerStart(host, port)
|
||||
|
||||
// 重定向 Gin 框架内部日志到 Logrus
|
||||
// 这将捕获 [GIN-debug] 路由注册日志和其他框架级输出
|
||||
gin.DefaultWriter = logger.WriterLevel(logrus.DebugLevel)
|
||||
gin.DefaultErrorWriter = logger.WriterLevel(logrus.ErrorLevel)
|
||||
|
||||
// 设置 Gin 模式
|
||||
if !viper.GetBool("server.dev_mode") {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
// 初始化Redis(如果配置存在,失败不致命)
|
||||
utils.InitRedis()
|
||||
|
||||
// 初始化数据库(根据 viper 配置选择 SQLite 或 MySQL)
|
||||
// 如果初始化失败则回退并退出
|
||||
if _, err := database.Init(); err != nil {
|
||||
db, err := database.Init()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("数据库初始化失败")
|
||||
}
|
||||
// 执行自动迁移(确保表结构存在)
|
||||
if err := database.AutoMigrate(); err != nil {
|
||||
logrus.WithError(err).Fatal("数据库自动迁移失败")
|
||||
}
|
||||
// 初始化默认系统设置(包含管理员账号)
|
||||
if err := database.SeedDefaultSettings(); err != nil {
|
||||
logrus.WithError(err).Fatal("默认系统设置初始化失败")
|
||||
|
||||
if db != nil {
|
||||
// 执行自动迁移(确保表结构存在)
|
||||
if err := database.AutoMigrate(); err != nil {
|
||||
logrus.WithError(err).Fatal("数据库自动迁移失败")
|
||||
}
|
||||
// 初始化默认系统设置
|
||||
if err := database.SeedDefaultSettings(); err != nil {
|
||||
logrus.WithError(err).Fatal("默认系统设置初始化失败")
|
||||
}
|
||||
|
||||
// 初始化加密管理器
|
||||
// 从数据库设置中获取加密密钥
|
||||
encryptionKey := services.GetSettingsService().GetEncryptionKey()
|
||||
if err := utils.InitEncryption(encryptionKey); err != nil {
|
||||
logrus.WithError(err).Fatal("加密管理器初始化失败")
|
||||
}
|
||||
|
||||
// 启动日志清理定时任务
|
||||
services.StartLogCleanupTask()
|
||||
} else {
|
||||
logrus.Info("系统处于未初始化状态,跳过数据库自动迁移和设置加载")
|
||||
}
|
||||
|
||||
// 创建HTTP服务器
|
||||
@@ -87,10 +101,6 @@ func runServer(cmd *cobra.Command, args []string) {
|
||||
startServer(server)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 辅助函数
|
||||
// ============================================================================
|
||||
|
||||
// getServerHost 获取服务器监听地址
|
||||
func getServerHost(cmd *cobra.Command) string {
|
||||
if host, _ := cmd.Flags().GetString("host"); host != "" {
|
||||
@@ -109,49 +119,51 @@ func getServerPort(cmd *cobra.Command) int {
|
||||
|
||||
// createHTTPServer 创建HTTP服务器
|
||||
func createHTTPServer(addr string) *http.Server {
|
||||
// 配置Gin模式和日志
|
||||
configureGin()
|
||||
// 创建 Gin 引擎
|
||||
r := gin.New()
|
||||
|
||||
// 创建Gin引擎
|
||||
router := gin.New()
|
||||
|
||||
// 添加恢复中间件
|
||||
router.Use(gin.Recovery())
|
||||
// 使用默认的 Recovery 中间件
|
||||
r.Use(gin.Recovery())
|
||||
|
||||
// 添加日志中间件
|
||||
router.Use(middleware.WrapHandler())
|
||||
// 默认为 true,只有显式设置为 false 才关闭
|
||||
enableAccessLog := true
|
||||
if viper.IsSet("server.access_log") {
|
||||
enableAccessLog = viper.GetBool("server.access_log")
|
||||
}
|
||||
if enableAccessLog {
|
||||
r.Use(middleware.WrapHandler())
|
||||
}
|
||||
|
||||
// 添加开发模式中间件(统一管理开发模式功能)
|
||||
router.Use(middleware.DevModeMiddleware(router))
|
||||
// 添加安装检查中间件
|
||||
r.Use(middleware.InstallCheckMiddleware())
|
||||
|
||||
// 加载模板
|
||||
if err := loadTemplates(router); err != nil {
|
||||
logrus.WithError(err).Fatal("模板加载失败")
|
||||
// 添加维护模式中间件
|
||||
r.Use(middleware.MaintenanceMiddleware())
|
||||
|
||||
// 添加开发模式中间件(统一管理开发模式功能:模板热重载等)
|
||||
r.Use(middleware.DevModeMiddleware(r))
|
||||
|
||||
// 加载并设置 HTML 模板
|
||||
if tmpl, err := web.ParseTemplates(); err == nil {
|
||||
r.SetHTMLTemplate(tmpl)
|
||||
} else {
|
||||
logrus.WithError(err).Error("HTML模板加载失败")
|
||||
}
|
||||
|
||||
// 注册路由
|
||||
registerRoutes(router)
|
||||
registerRoutes(r)
|
||||
|
||||
return &http.Server{
|
||||
Addr: addr,
|
||||
Handler: router,
|
||||
Handler: r,
|
||||
}
|
||||
}
|
||||
|
||||
// loadTemplates 加载模板到Gin引擎
|
||||
func loadTemplates(router *gin.Engine) error {
|
||||
tmpl, err := web.ParseTemplates()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
router.SetHTMLTemplate(tmpl)
|
||||
return nil
|
||||
}
|
||||
|
||||
// registerRoutes 注册HTTP路由
|
||||
func registerRoutes(router *gin.Engine) {
|
||||
func registerRoutes(r *gin.Engine) {
|
||||
// 使用server包中的路由注册函数
|
||||
server.RegisterRoutes(router)
|
||||
server.RegisterRoutes(r)
|
||||
}
|
||||
|
||||
// startServer 启动服务器并处理优雅关闭
|
||||
@@ -174,8 +186,6 @@ func startServer(server *http.Server) {
|
||||
|
||||
// 等待中断信号
|
||||
<-sigChan
|
||||
// 清除终端上的 ^C 字符并移动光标到行首
|
||||
fmt.Print("\r\033[K")
|
||||
logger.Info("收到关闭信号,正在优雅关闭服务器...")
|
||||
|
||||
// 创建一个带超时的上下文
|
||||
@@ -189,20 +199,3 @@ func startServer(server *http.Server) {
|
||||
logger.LogServerStop()
|
||||
}
|
||||
}
|
||||
|
||||
// configureGin 配置Gin的全局设置
|
||||
func configureGin() {
|
||||
// 禁用Gin的颜色输出,提高控制台兼容性
|
||||
gin.DisableConsoleColor()
|
||||
|
||||
// 设置Gin的输出为丢弃,因为我们使用自定义日志中间件
|
||||
gin.DefaultWriter = io.Discard
|
||||
gin.DefaultErrorWriter = io.Discard
|
||||
|
||||
// 根据配置设置Gin模式
|
||||
if viper.GetString("app.mode") == "production" {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
} else {
|
||||
gin.SetMode(gin.DebugMode)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user