From 12678f8241b9b524cd725dc1c5bd149d6cb948fc Mon Sep 17 00:00:00 2001 From: KartoffelChips <104089082+KartoffelChipss@users.noreply.github.com> Date: Fri, 3 Apr 2026 11:21:27 +0200 Subject: [PATCH] Updated static pages to use db --- app/cachedrepo/cached_site_repository.go | 19 ++++++++ app/handlers/static.go | 59 +++++++++++++++--------- app/models/site.go | 1 + app/repository/site_repository.go | 1 + app/routes/routes.go | 2 +- internal/database/init_sqlite.go | 1 + internal/database/site_sqlite.go | 38 ++++++++++++--- 7 files changed, 90 insertions(+), 31 deletions(-) diff --git a/app/cachedrepo/cached_site_repository.go b/app/cachedrepo/cached_site_repository.go index 60a2e87..86822e6 100644 --- a/app/cachedrepo/cached_site_repository.go +++ b/app/cachedrepo/cached_site_repository.go @@ -52,6 +52,25 @@ func (c *CachedSiteRepository) GetSite(id string) (*models.Site, error) { return s, nil } +func (c *CachedSiteRepository) GetSiteByDomain(domain string) (*models.Site, error) { + c.mu.RLock() + if s, ok := c.sites[domain]; ok { + c.mu.RUnlock() + return s, nil + } + c.mu.RUnlock() + + s, err := c.inner.GetSiteByDomain(domain) + if err != nil { + return nil, err + } + + c.mu.Lock() + c.sites[domain] = s + c.mu.Unlock() + return s, nil +} + func (c *CachedSiteRepository) ListSites() ([]models.Site, error) { c.mu.RLock() if c.siteListValid { diff --git a/app/handlers/static.go b/app/handlers/static.go index a1349be..b599db5 100644 --- a/app/handlers/static.go +++ b/app/handlers/static.go @@ -4,15 +4,21 @@ import ( "os" "path" "path/filepath" - "quay/internal/config" + "quay/app/repository" + "regexp" "github.com/gofiber/fiber/v3" ) -func NewStaticHandler(storagePath string, siteMap map[string]config.SiteConfig) fiber.Handler { +func NewStaticHandler(storagePath string, siteRepo repository.SiteRepository) fiber.Handler { return func(c fiber.Ctx) error { - site, ok := siteMap[c.Hostname()] - if !ok { + domain := c.Hostname() + site, err := siteRepo.GetSiteByDomain(domain) + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Failed to resolve site") + } + + if site == nil { return c.Status(fiber.StatusNotFound).SendString("Site not found") } @@ -22,25 +28,15 @@ func NewStaticHandler(storagePath string, siteMap map[string]config.SiteConfig) urlPath := filepath.Clean(c.Path()) - for _, header := range site.CustomHeaders { - var matched bool - if header.Regex && header.Compiled != nil { - matched = header.Compiled.MatchString(urlPath) - } else { - matched, _ = path.Match(header.Source, urlPath) - } - if matched { - for key, value := range header.Headers { - c.Set(key, value) - } - } - } - for _, rule := range site.ForwardRules { - if rule.Regex && rule.Compiled != nil { - match := rule.Compiled.FindStringSubmatchIndex(urlPath) + if rule.Regex { + re, err := regexp.Compile(rule.Source) + if err != nil { + continue + } + match := re.FindStringSubmatchIndex(urlPath) if match != nil { - dest := rule.Compiled.ExpandString([]byte{}, rule.Destination, urlPath, match) + dest := re.ExpandString([]byte{}, rule.Destination, urlPath, match) return c.Redirect().Status(rule.StatusCode).To(string(dest)) } } else if rule.Source == urlPath { @@ -48,11 +44,28 @@ func NewStaticHandler(storagePath string, siteMap map[string]config.SiteConfig) } } + for _, customHeader := range site.CustomHeaders { + var matched bool + if customHeader.Regex { + re, err := regexp.Compile(customHeader.Source) + if err == nil { + matched = re.MatchString(urlPath) + } + } else { + matched, _ = path.Match(customHeader.Source, urlPath) + } + if matched { + for _, header := range customHeader.Headers { + c.Set(header.Key, header.Value) + } + } + } + if urlPath == "/" || urlPath == "." { urlPath = "/index.html" } - basePath := filepath.Join(storagePath, site.Name) + basePath := filepath.Join(storagePath, site.ID) filePath := filepath.Join(basePath, urlPath) info, err := os.Stat(filePath) @@ -67,7 +80,7 @@ func NewStaticHandler(storagePath string, siteMap map[string]config.SiteConfig) } } - if site.SPA { + if site.Spa { indexPath := filepath.Join(basePath, "index.html") if _, err := os.Stat(indexPath); err == nil { return c.SendFile(indexPath) diff --git a/app/models/site.go b/app/models/site.go index 3faa3fa..6ac0a32 100644 --- a/app/models/site.go +++ b/app/models/site.go @@ -17,6 +17,7 @@ type Header struct { type CustomHeaders struct { ID string `json:"id"` Source string `json:"source"` + Regex bool `json:"regex"` Headers []Header `json:"headers"` } diff --git a/app/repository/site_repository.go b/app/repository/site_repository.go index d20554f..4ec2ff1 100644 --- a/app/repository/site_repository.go +++ b/app/repository/site_repository.go @@ -4,6 +4,7 @@ import "quay/app/models" type SiteRepository interface { GetSite(id string) (*models.Site, error) + GetSiteByDomain(domain string) (*models.Site, error) ListSites() ([]models.Site, error) CreateSite(s *models.Site) error UpdateSite(s *models.Site) error diff --git a/app/routes/routes.go b/app/routes/routes.go index 5316ad4..c2632f0 100644 --- a/app/routes/routes.go +++ b/app/routes/routes.go @@ -66,5 +66,5 @@ func Register(app *fiber.App, cfg *config.Config, envCfg *envconfig.EnvConfig, d siteMap[site.Domain] = site } - app.Use(handlers.NewStaticHandler(storagePath, siteMap)) + app.Use(handlers.NewStaticHandler(storagePath, siteRepository)) } diff --git a/internal/database/init_sqlite.go b/internal/database/init_sqlite.go index 28d3ea7..c8221f2 100644 --- a/internal/database/init_sqlite.go +++ b/internal/database/init_sqlite.go @@ -34,6 +34,7 @@ CREATE TABLE IF NOT EXISTS custom_headers ( id TEXT PRIMARY KEY, site_id TEXT NOT NULL, source TEXT NOT NULL, + regex INTEGER NOT NULL DEFAULT 0, FOREIGN KEY (site_id) REFERENCES sites(id) ON DELETE CASCADE ); diff --git a/internal/database/site_sqlite.go b/internal/database/site_sqlite.go index d4e5667..d838785 100644 --- a/internal/database/site_sqlite.go +++ b/internal/database/site_sqlite.go @@ -2,6 +2,7 @@ package database import ( "database/sql" + "errors" "fmt" "quay/app/models" "quay/app/repository" @@ -38,6 +39,25 @@ func (r *SQLiteSiteRepository) GetSite(id string) (*models.Site, error) { return s, nil } +func (r *SQLiteSiteRepository) GetSiteByDomain(domain string) (*models.Site, error) { + row := r.db.QueryRow(` + SELECT id, git_server, owner, repository, branch, domain, deploy_token, enabled, not_found_file + FROM sites WHERE domain = ?`, domain) + + s, err := scanSite(row) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return nil, fmt.Errorf("get site by domain: %w", err) + } + + if err := r.populateSiteRelations(s); err != nil { + return nil, err + } + return s, nil +} + func (r *SQLiteSiteRepository) ListSites() ([]models.Site, error) { rows, err := r.db.Query(` SELECT id, git_server, owner, repository, branch, domain, deploy_token, enabled, not_found_file @@ -205,10 +225,11 @@ func (r *SQLiteSiteRepository) DeleteForwardRule(id string) error { // Custom Headers func (r *SQLiteSiteRepository) GetCustomHeaders(id string) (*models.CustomHeaders, error) { - row := r.db.QueryRow(`SELECT id, source FROM custom_headers WHERE id = ?`, id) + row := r.db.QueryRow(`SELECT id, source, regex FROM custom_headers WHERE id = ?`, id) var ch models.CustomHeaders - if err := row.Scan(&ch.ID, &ch.Source); err != nil { + var regex int + if err := row.Scan(&ch.ID, &ch.Source, ®ex); err != nil { return nil, fmt.Errorf("get custom headers: %w", err) } @@ -217,6 +238,7 @@ func (r *SQLiteSiteRepository) GetCustomHeaders(id string) (*models.CustomHeader return nil, err } ch.Headers = headers + ch.Regex = regex != 0 return &ch, nil } @@ -239,7 +261,7 @@ func (r *SQLiteSiteRepository) UpdateCustomHeaders(ch *models.CustomHeaders) err } defer tx.Rollback() - if _, err := tx.Exec(`UPDATE custom_headers SET source=? WHERE id=?`, ch.Source, ch.ID); err != nil { + if _, err := tx.Exec(`UPDATE custom_headers SET source=?, regex=? WHERE id=?`, ch.Source, ch.Regex, ch.ID); err != nil { return fmt.Errorf("update custom headers: %w", err) } if _, err := tx.Exec(`DELETE FROM headers WHERE custom_header_id = ?`, ch.ID); err != nil { @@ -360,7 +382,7 @@ func (r *SQLiteSiteRepository) listForwardRules(siteID string) ([]models.Forward } func (r *SQLiteSiteRepository) listCustomHeaders(siteID string) ([]models.CustomHeaders, error) { - rows, err := r.db.Query(`SELECT id, source FROM custom_headers WHERE site_id = ?`, siteID) + rows, err := r.db.Query(`SELECT id, source, regex FROM custom_headers WHERE site_id = ?`, siteID) if err != nil { return nil, fmt.Errorf("list custom headers: %w", err) } @@ -368,10 +390,12 @@ func (r *SQLiteSiteRepository) listCustomHeaders(siteID string) ([]models.Custom var result []models.CustomHeaders for rows.Next() { var ch models.CustomHeaders - if err := rows.Scan(&ch.ID, &ch.Source); err != nil { + var regex int + if err := rows.Scan(&ch.ID, &ch.Source, ®ex); err != nil { rows.Close() return nil, fmt.Errorf("list custom headers scan: %w", err) } + ch.Regex = regex != 0 result = append(result, ch) } rows.Close() @@ -424,8 +448,8 @@ func insertForwardRule(tx *sql.Tx, siteID string, fr *models.ForwardRule) error func insertCustomHeaders(tx *sql.Tx, siteID string, ch *models.CustomHeaders) error { ch.ID = uuid.NewString() _, err := tx.Exec(` - INSERT INTO custom_headers (id, site_id, source) VALUES (?, ?, ?)`, - ch.ID, siteID, ch.Source, + INSERT INTO custom_headers (id, site_id, source, regex) VALUES (?, ?, ?, ?)`, + ch.ID, siteID, ch.Source, ch.Regex, ) if err != nil { return fmt.Errorf("insert custom headers: %w", err)