169 lines
4.8 KiB
Go
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
|
|
}
|