package main import ( "fmt" "log" "net" "net/http" "time" "instance-manager/internal/auth" "instance-manager/internal/config" "instance-manager/internal/db" "instance-manager/internal/handlers" "instance-manager/internal/instance" "instance-manager/internal/proxy" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) func main() { cfg, err := config.Load("config.yaml") if err != nil { log.Fatalf("Failed to load config: %v", err) } database, err := db.New(cfg.Database) if err != nil { log.Fatalf("Failed to initialize database: %v", err) } defer database.Close() authMgr := auth.New(cfg.Sessions) instanceMgr := instance.New(database, cfg.Instance) proxy := proxy.New(database, instanceMgr, authMgr, cfg.Instance) templates := handlers.NewTemplateRenderer("templates") handler := handlers.New(database, authMgr, instanceMgr, proxy, templates) r := chi.NewRouter() r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate") w.Header().Set("Pragma", "no-cache") w.Header().Set("Expires", "0") next.ServeHTTP(w, r) }) }) // Subdomain routing: .baseDomain -> user's instance r.Use(proxy.SubdomainRouter(cfg.Instance.BaseDomain)) r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) handler.RegisterRoutes(r) fmt.Println("Starting instances for active users...") instanceMgr.StartAll() addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port) listener, err := net.Listen("tcp", addr) if err != nil { for retry := 1; retry <= 5; retry++ { time.Sleep(time.Second) listener, err = net.Listen("tcp", addr) if err == nil { break } } if err != nil { log.Fatalf("Port %d unavailable: %v", cfg.Server.Port, err) } } log.Printf("Server starting on %s", addr) srv := &http.Server{Handler: r} if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed { log.Fatalf("Server failed: %v", err) } }