random-api-go/main.go

162 lines
3.7 KiB
Go

package main
import (
"context"
"fmt"
"log"
"math/rand"
"net/http"
"os"
"os/signal"
"path/filepath"
"random-api-go/config"
"random-api-go/database"
"random-api-go/handler"
"random-api-go/initapp"
"random-api-go/logging"
"random-api-go/router"
"random-api-go/service"
"random-api-go/stats"
"syscall"
"time"
)
type App struct {
server *http.Server
router *router.Router
Stats *stats.StatsManager
adminHandler *handler.AdminHandler
staticHandler *handler.StaticHandler
}
func NewApp() *App {
return &App{
router: router.New(),
}
}
func (a *App) Initialize() error {
// 先加载配置
if err := config.Load(); err != nil {
return err
}
// 初始化随机数生成器
source := rand.NewSource(time.Now().UnixNano())
config.InitRNG(rand.New(source))
// 然后创建必要的目录
if err := os.MkdirAll(config.Get().Storage.DataDir, 0755); err != nil {
return fmt.Errorf("failed to create data directory: %w", err)
}
// 初始化数据库
if err := database.Initialize(config.Get().Storage.DataDir); err != nil {
return fmt.Errorf("failed to initialize database: %w", err)
}
// 初始化日志
logging.SetupLogging()
// 初始化统计管理器
statsFile := config.Get().Storage.DataDir + "/stats.json"
a.Stats = stats.NewStatsManager(statsFile)
// 初始化端点服务
service.GetEndpointService()
// 预加载所有数据到内存
log.Println("开始预加载应用数据...")
if err := initapp.InitData(); err != nil {
log.Printf("预加载数据失败: %v", err)
// 不返回错误,允许应用继续启动
}
// 创建管理后台处理器
a.adminHandler = handler.NewAdminHandler()
// 创建静态文件处理器
staticDir := "./web/out"
if _, err := os.Stat(staticDir); os.IsNotExist(err) {
log.Printf("Warning: Static directory %s does not exist, static file serving will be disabled", staticDir)
} else {
absStaticDir, err := filepath.Abs(staticDir)
if err != nil {
return fmt.Errorf("failed to get absolute path for static directory: %w", err)
}
a.staticHandler = handler.NewStaticHandler(absStaticDir)
log.Printf("Static file serving enabled from: %s", absStaticDir)
}
// 创建 handlers
handlers := handler.NewHandlers(a.Stats)
// 统一设置所有路由
a.router.SetupAllRoutes(handlers, a.adminHandler, a.staticHandler)
// 创建 HTTP 服务器
cfg := config.Get().Server
a.server = &http.Server{
Addr: cfg.Port,
Handler: a.router,
ReadTimeout: cfg.ReadTimeout,
WriteTimeout: cfg.WriteTimeout,
MaxHeaderBytes: cfg.MaxHeaderBytes,
}
return nil
}
func (a *App) Run() error {
// 启动服务器
go func() {
log.Printf("Server starting on %s...\n", a.server.Addr)
if a.staticHandler != nil {
log.Printf("Frontend available at: http://localhost%s", a.server.Addr)
log.Printf("Admin panel available at: http://localhost%s/admin", a.server.Addr)
}
if err := a.server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("Server failed: %v", err)
}
}()
// 优雅关闭
return a.gracefulShutdown()
}
func (a *App) gracefulShutdown() error {
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Server is shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
a.Stats.Shutdown()
// 关闭数据库连接
if err := database.Close(); err != nil {
log.Printf("Error closing database: %v", err)
}
if err := a.server.Shutdown(ctx); err != nil {
return err
}
log.Println("Server shutdown completed")
return nil
}
func main() {
app := NewApp()
if err := app.Initialize(); err != nil {
log.Fatal(err)
}
if err := app.Run(); err != nil {
log.Fatal(err)
}
}