Updated static pages to use db
This commit is contained in:
@@ -52,6 +52,25 @@ func (c *CachedSiteRepository) GetSite(id string) (*models.Site, error) {
|
|||||||
return s, nil
|
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) {
|
func (c *CachedSiteRepository) ListSites() ([]models.Site, error) {
|
||||||
c.mu.RLock()
|
c.mu.RLock()
|
||||||
if c.siteListValid {
|
if c.siteListValid {
|
||||||
|
|||||||
+36
-23
@@ -4,15 +4,21 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"quay/internal/config"
|
"quay/app/repository"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"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 {
|
return func(c fiber.Ctx) error {
|
||||||
site, ok := siteMap[c.Hostname()]
|
domain := c.Hostname()
|
||||||
if !ok {
|
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")
|
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())
|
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 {
|
for _, rule := range site.ForwardRules {
|
||||||
if rule.Regex && rule.Compiled != nil {
|
if rule.Regex {
|
||||||
match := rule.Compiled.FindStringSubmatchIndex(urlPath)
|
re, err := regexp.Compile(rule.Source)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
match := re.FindStringSubmatchIndex(urlPath)
|
||||||
if match != nil {
|
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))
|
return c.Redirect().Status(rule.StatusCode).To(string(dest))
|
||||||
}
|
}
|
||||||
} else if rule.Source == urlPath {
|
} 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 == "." {
|
if urlPath == "/" || urlPath == "." {
|
||||||
urlPath = "/index.html"
|
urlPath = "/index.html"
|
||||||
}
|
}
|
||||||
|
|
||||||
basePath := filepath.Join(storagePath, site.Name)
|
basePath := filepath.Join(storagePath, site.ID)
|
||||||
filePath := filepath.Join(basePath, urlPath)
|
filePath := filepath.Join(basePath, urlPath)
|
||||||
|
|
||||||
info, err := os.Stat(filePath)
|
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")
|
indexPath := filepath.Join(basePath, "index.html")
|
||||||
if _, err := os.Stat(indexPath); err == nil {
|
if _, err := os.Stat(indexPath); err == nil {
|
||||||
return c.SendFile(indexPath)
|
return c.SendFile(indexPath)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type Header struct {
|
|||||||
type CustomHeaders struct {
|
type CustomHeaders struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
|
Regex bool `json:"regex"`
|
||||||
Headers []Header `json:"headers"`
|
Headers []Header `json:"headers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import "quay/app/models"
|
|||||||
|
|
||||||
type SiteRepository interface {
|
type SiteRepository interface {
|
||||||
GetSite(id string) (*models.Site, error)
|
GetSite(id string) (*models.Site, error)
|
||||||
|
GetSiteByDomain(domain string) (*models.Site, error)
|
||||||
ListSites() ([]models.Site, error)
|
ListSites() ([]models.Site, error)
|
||||||
CreateSite(s *models.Site) error
|
CreateSite(s *models.Site) error
|
||||||
UpdateSite(s *models.Site) error
|
UpdateSite(s *models.Site) error
|
||||||
|
|||||||
@@ -66,5 +66,5 @@ func Register(app *fiber.App, cfg *config.Config, envCfg *envconfig.EnvConfig, d
|
|||||||
siteMap[site.Domain] = site
|
siteMap[site.Domain] = site
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Use(handlers.NewStaticHandler(storagePath, siteMap))
|
app.Use(handlers.NewStaticHandler(storagePath, siteRepository))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ CREATE TABLE IF NOT EXISTS custom_headers (
|
|||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
site_id TEXT NOT NULL,
|
site_id TEXT NOT NULL,
|
||||||
source TEXT NOT NULL,
|
source TEXT NOT NULL,
|
||||||
|
regex INTEGER NOT NULL DEFAULT 0,
|
||||||
FOREIGN KEY (site_id) REFERENCES sites(id) ON DELETE CASCADE
|
FOREIGN KEY (site_id) REFERENCES sites(id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"quay/app/models"
|
"quay/app/models"
|
||||||
"quay/app/repository"
|
"quay/app/repository"
|
||||||
@@ -38,6 +39,25 @@ func (r *SQLiteSiteRepository) GetSite(id string) (*models.Site, error) {
|
|||||||
return s, nil
|
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) {
|
func (r *SQLiteSiteRepository) ListSites() ([]models.Site, error) {
|
||||||
rows, err := r.db.Query(`
|
rows, err := r.db.Query(`
|
||||||
SELECT id, git_server, owner, repository, branch, domain, deploy_token, enabled, not_found_file
|
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
|
// Custom Headers
|
||||||
|
|
||||||
func (r *SQLiteSiteRepository) GetCustomHeaders(id string) (*models.CustomHeaders, error) {
|
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
|
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)
|
return nil, fmt.Errorf("get custom headers: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +238,7 @@ func (r *SQLiteSiteRepository) GetCustomHeaders(id string) (*models.CustomHeader
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ch.Headers = headers
|
ch.Headers = headers
|
||||||
|
ch.Regex = regex != 0
|
||||||
return &ch, nil
|
return &ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +261,7 @@ func (r *SQLiteSiteRepository) UpdateCustomHeaders(ch *models.CustomHeaders) err
|
|||||||
}
|
}
|
||||||
defer tx.Rollback()
|
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)
|
return fmt.Errorf("update custom headers: %w", err)
|
||||||
}
|
}
|
||||||
if _, err := tx.Exec(`DELETE FROM headers WHERE custom_header_id = ?`, ch.ID); err != nil {
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("list custom headers: %w", err)
|
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
|
var result []models.CustomHeaders
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var ch models.CustomHeaders
|
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()
|
rows.Close()
|
||||||
return nil, fmt.Errorf("list custom headers scan: %w", err)
|
return nil, fmt.Errorf("list custom headers scan: %w", err)
|
||||||
}
|
}
|
||||||
|
ch.Regex = regex != 0
|
||||||
result = append(result, ch)
|
result = append(result, ch)
|
||||||
}
|
}
|
||||||
rows.Close()
|
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 {
|
func insertCustomHeaders(tx *sql.Tx, siteID string, ch *models.CustomHeaders) error {
|
||||||
ch.ID = uuid.NewString()
|
ch.ID = uuid.NewString()
|
||||||
_, err := tx.Exec(`
|
_, err := tx.Exec(`
|
||||||
INSERT INTO custom_headers (id, site_id, source) VALUES (?, ?, ?)`,
|
INSERT INTO custom_headers (id, site_id, source, regex) VALUES (?, ?, ?, ?)`,
|
||||||
ch.ID, siteID, ch.Source,
|
ch.ID, siteID, ch.Source, ch.Regex,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("insert custom headers: %w", err)
|
return fmt.Errorf("insert custom headers: %w", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user