package api import ( "fmt" "net/http" "path/filepath" "strings" "time" "browser.local/platform/config" "browser.local/platform/repo" "browser.local/platform/service" ) func NewRouter() http.Handler { router, err := NewRouterFromConfig(config.Load()) if err != nil { panic(err) } return router } func NewRouterFromConfig(cfg config.Config) (http.Handler, error) { store, err := storeFromConfig(cfg) if err != nil { return nil, err } logStore, err := logStoreFromConfig(cfg) if err != nil { return nil, err } artifactDir := strings.TrimSpace(cfg.ArtifactDir) if artifactDir == "" { if strings.TrimSpace(cfg.DataDir) != "" { artifactDir = filepath.Join(cfg.DataDir, "artifacts") } else { artifactDir = filepath.Join(filepath.Dir(cfg.MetadataPath), "artifacts") } } artifactStore, err := service.NewFileArtifactBodyStore(artifactDir) if err != nil { return nil, err } core, err := service.NewCoreServiceWithDurableStores(store, logStore, artifactStore) if err != nil { return nil, err } if err := core.ConfigureSecretEnvelopeKey(cfg.SecretEnvelopeKey); err != nil { return nil, err } core.ConfigureDistributionBuilder(service.NewDockerDistributionBuilder(service.DockerDistributionBuilderConfig{ DockerBinary: cfg.BuilderDockerBinary, Image: cfg.BuilderImage, SourceDir: cfg.BuilderSourceDir, WorkspaceDir: cfg.BuilderWorkspaceDir, CacheDir: cfg.BuilderCacheDir, Timeout: time.Duration(cfg.BuilderTimeoutSeconds) * time.Second, })) if err := core.ConfigureAIProviderMode(cfg.AIProviderMode); err != nil { return nil, err } if strings.TrimSpace(cfg.BootstrapAdminPassword) != "" { if err := core.SeedPlatformAdmin(cfg.BootstrapAdminEmail, cfg.BootstrapAdminPassword); err != nil { return nil, err } } return NewAuthorizedRouterWithCore(core), nil } func NewRouterWithCore(core service.Core) http.Handler { return newRouterWithCore(core, true) } func NewAuthorizedRouterWithCore(core service.Core) http.Handler { return newRouterWithCore(core, true) } func NewTestRouterWithCore(core service.Core) http.Handler { return newRouterWithCore(core, false) } func newRouterWithCore(core service.Core, enforceAuthorization bool) http.Handler { handlers := newCoreHandlers(core, enforceAuthorization) mux := http.NewServeMux() mux.HandleFunc("/healthz", HealthHandler) handlers.register(mux) if enforceAuthorization { return handlers.requireAuthorizedAPI(mux) } return mux } func storeFromConfig(cfg config.Config) (repo.Store, error) { switch strings.ToLower(strings.TrimSpace(cfg.StorageBackend)) { case "", "file": return repo.NewFileStore(cfg.MetadataPath) case "memory": return repo.NewMemoryStore(), nil case "mysql": return repo.NewMySQLStore(cfg.MySQLDSN) default: return nil, fmt.Errorf("unsupported platform storage backend %q", cfg.StorageBackend) } } func logStoreFromConfig(cfg config.Config) (service.LogBodyStore, error) { backend := strings.ToLower(strings.TrimSpace(cfg.LogBodyBackend)) if backend == "" { backend = strings.ToLower(strings.TrimSpace(cfg.StorageBackend)) if backend == "mysql" { backend = "file" } } switch backend { case "", "file": return service.NewFileLogBodyStore(cfg.LogDir) case "memory": return service.NewMemoryLogBodyStore(), nil default: return nil, fmt.Errorf("unsupported platform log body backend %q", backend) } }