package app import ( "fmt" "log" "net/http" "os" "github.com/rs/cors" "spore-registry/internal/config" "spore-registry/internal/database" "spore-registry/internal/handlers" "spore-registry/internal/repository" "spore-registry/internal/service" "spore-registry/internal/storage" ) // App holds the application dependencies type App struct { config *config.Config db *database.DB handler *handlers.FirmwareHandler } // NewApp creates a new application instance func NewApp() (*App, error) { // Load configuration cfg := config.LoadConfig() // Create registry directory if it doesn't exist if err := os.MkdirAll(cfg.Registry, 0755); err != nil { return nil, fmt.Errorf("failed to create registry directory: %w", err) } // Initialize database db, err := database.NewDB(cfg.DBPath) if err != nil { return nil, fmt.Errorf("failed to initialize database: %w", err) } // Create repository repo := repository.NewFirmwareRepository(db.GetConnection()) // Create storage fileStorage := storage.NewFileStorage(cfg.Registry) // Create service firmwareService := service.NewFirmwareService(repo, fileStorage) // Create handler handler := handlers.NewFirmwareHandler(firmwareService) return &App{ config: cfg, db: db, handler: handler, }, nil } // Close closes the database connection func (a *App) Close() error { return a.db.Close() } // SetupRoutes sets up HTTP routes func (a *App) SetupRoutes() *http.ServeMux { mux := http.NewServeMux() // API endpoints mux.HandleFunc("POST /firmware", a.handler.UploadFirmware) mux.HandleFunc("PUT /firmware/{name}/{version}", a.handler.UpdateFirmwareMetadata) mux.HandleFunc("GET /firmware", a.handler.ListFirmware) mux.HandleFunc("GET /firmware/{name}/{version}", a.handler.DownloadFirmware) mux.HandleFunc("DELETE /firmware/{name}/{version}", a.handler.DeleteFirmware) // Health check endpoint mux.HandleFunc("GET /health", a.handler.HealthCheck) return mux } // Start starts the HTTP server func (a *App) Start() error { mux := a.SetupRoutes() log.Printf("Starting SPORE registry server on port %s", a.config.Port) log.Printf("Server will be accessible from any host on port %s", a.config.Port) log.Printf("CORS enabled for all origins to support mobile access") // Add CORS middleware with dynamic origin handling c := cors.New(cors.Options{ AllowedOrigins: []string{"*"}, // Allow all origins for mobile access AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"*"}, AllowCredentials: false, // Set to false when using wildcard origins AllowOriginFunc: func(origin string) bool { // Allow all origins for mobile/remote access return true }, }) // Add request logging middleware loggedHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Printf("%s %s from %s", r.Method, r.URL.Path, r.RemoteAddr) c.Handler(mux).ServeHTTP(w, r) }) return http.ListenAndServe(":"+a.config.Port, loggedHandler) }