Files
GitCodeStatic/cmd/server/main.go
2025-12-31 14:23:53 +08:00

169 lines
4.8 KiB
Go

package main
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gitcodestatic/gitcodestatic/internal/api"
"github.com/gitcodestatic/gitcodestatic/internal/cache"
"github.com/gitcodestatic/gitcodestatic/internal/config"
"github.com/gitcodestatic/gitcodestatic/internal/git"
"github.com/gitcodestatic/gitcodestatic/internal/logger"
"github.com/gitcodestatic/gitcodestatic/internal/models"
"github.com/gitcodestatic/gitcodestatic/internal/service"
"github.com/gitcodestatic/gitcodestatic/internal/stats"
"github.com/gitcodestatic/gitcodestatic/internal/storage/sqlite"
"github.com/gitcodestatic/gitcodestatic/internal/worker"
)
func main() {
// 加载配置
cfg, err := loadConfig()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load config: %v\n", err)
os.Exit(1)
}
// 初始化日志
if err := logger.InitLogger(cfg.Log.Level, cfg.Log.Format, cfg.Log.Output); err != nil {
fmt.Fprintf(os.Stderr, "Failed to initialize logger: %v\n", err)
os.Exit(1)
}
logger.Logger.Info().Msg("starting GitCodeStatic server")
// 创建工作目录
if err := ensureDirectories(cfg); err != nil {
logger.Logger.Fatal().Err(err).Msg("failed to create directories")
}
// 初始化存储
store, err := sqlite.NewSQLiteStore(cfg.Storage.SQLite.Path)
if err != nil {
logger.Logger.Fatal().Err(err).Msg("failed to create store")
}
defer store.Close()
if err := store.Init(); err != nil {
logger.Logger.Fatal().Err(err).Msg("failed to initialize database")
}
logger.Logger.Info().Msg("database initialized")
// 创建Git管理器
gitManager := git.NewCmdGitManager(cfg.Git.CommandPath)
if !gitManager.IsAvailable() {
logger.Logger.Warn().Msg("git command not available, some features may not work")
} else {
logger.Logger.Info().Msg("git command available")
}
// 创建统计计算器
calculator := stats.NewCalculator(cfg.Git.CommandPath)
// 创建缓存
fileCache := cache.NewFileCache(store, cfg.Workspace.StatsDir)
// 创建任务队列
queue := worker.NewQueue(cfg.Worker.QueueBuffer, store)
// 创建任务处理器
handlers := map[string]worker.TaskHandler{
models.TaskTypeClone: worker.NewCloneHandler(store, gitManager),
models.TaskTypePull: worker.NewPullHandler(store, gitManager),
models.TaskTypeSwitch: worker.NewSwitchHandler(store, gitManager),
models.TaskTypeReset: worker.NewResetHandler(store, gitManager, fileCache),
models.TaskTypeStats: worker.NewStatsHandler(store, calculator, fileCache, gitManager),
}
// 创建Worker池
totalWorkers := cfg.Worker.CloneWorkers + cfg.Worker.PullWorkers +
cfg.Worker.StatsWorkers + cfg.Worker.GeneralWorkers
pool := worker.NewPool(totalWorkers, cfg.Worker.QueueBuffer, store, handlers)
pool.Start()
defer pool.Stop()
logger.Logger.Info().Int("workers", totalWorkers).Msg("worker pool started")
// 创建服务层
repoService := service.NewRepoService(store, queue, cfg.Workspace.CacheDir)
statsService := service.NewStatsService(store, queue, fileCache, gitManager)
// 设置路由
router := api.NewRouter(repoService, statsService)
handler := router.Setup()
// 创建HTTP服务器
addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
srv := &http.Server{
Addr: addr,
Handler: handler,
ReadTimeout: cfg.Server.ReadTimeout,
WriteTimeout: cfg.Server.WriteTimeout,
}
// 启动服务器
go func() {
logger.Logger.Info().Str("addr", addr).Msg("server starting")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logger.Logger.Fatal().Err(err).Msg("failed to start server")
}
}()
// 等待中断信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logger.Logger.Info().Msg("shutting down server...")
// 优雅关闭
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
logger.Logger.Error().Err(err).Msg("server forced to shutdown")
}
logger.Logger.Info().Msg("server stopped")
}
// loadConfig 加载配置
func loadConfig() (*config.Config, error) {
configPath := os.Getenv("CONFIG_PATH")
if configPath == "" {
configPath = "configs/config.yaml"
}
// 检查配置文件是否存在
if _, err := os.Stat(configPath); os.IsNotExist(err) {
logger.Logger.Warn().Str("path", configPath).Msg("config file not found, using defaults")
return config.DefaultConfig(), nil
}
return config.LoadConfig(configPath)
}
// ensureDirectories 确保工作目录存在
func ensureDirectories(cfg *config.Config) error {
dirs := []string{
cfg.Workspace.BaseDir,
cfg.Workspace.CacheDir,
cfg.Workspace.StatsDir,
}
for _, dir := range dirs {
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("failed to create directory %s: %w", dir, err)
}
}
return nil
}