package main import ( "context" "log/slog" "net/http" "os" "os/signal" "syscall" "time" "codespace/internal/api" "codespace/internal/process" "codespace/internal/service" "codespace/internal/workspace" "codespace/pkg/config" "codespace/pkg/logger" ) func main() { startupLogger := slog.New(slog.NewJSONHandler(os.Stderr, nil)) cfg, err := config.Load("configs/config.yaml") if err != nil { startupLogger.Error("failed to load config", "error", err) os.Exit(1) } lg, err := logger.New(cfg.Log) if err != nil { startupLogger.Error("failed to initialize logger", "error", err) os.Exit(1) } workspaces := workspace.NewLocalManager(cfg.Workspace.Root) processes := process.NewManager(cfg.Process.OpenCodeCommand) workspaceSvc := service.NewWorkspaceService(workspaces, processes, lg) fileSvc := service.NewFileService(workspaces, cfg.File.MaxWriteBytes) processSvc := service.NewProcessService(workspaces, processes, lg) router := api.NewRouter(workspaceSvc, fileSvc, processSvc, lg, cfg.Gin.Mode) server := &http.Server{ Addr: cfg.Server.Addr, Handler: router, ReadTimeout: cfg.Server.ReadTimeout, WriteTimeout: cfg.Server.WriteTimeout, IdleTimeout: cfg.Server.IdleTimeout, MaxHeaderBytes: cfg.Server.MaxHeaderBytes, } lg.Info("server starting", "addr", cfg.Server.Addr, "read_timeout", cfg.Server.ReadTimeout.String(), "write_timeout", cfg.Server.WriteTimeout.String(), "idle_timeout", cfg.Server.IdleTimeout.String(), "max_header_bytes", cfg.Server.MaxHeaderBytes, ) go func() { if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { lg.Error("server failed", "error", err) os.Exit(1) } }() quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit lg.Info("server shutting down") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { lg.Error("server forced shutdown", "error", err) os.Exit(1) } }