From 04498ea7f48192001a62fdef6c76973c39010cce Mon Sep 17 00:00:00 2001 From: kiootic Date: Wed, 29 Nov 2023 16:06:43 +0800 Subject: [PATCH] Add custom domain resolution logic --- cmd/controller/app/start.go | 7 ++++-- internal/db/db.go | 1 + internal/db/postgres/domains.go | 17 +++++++++++++++ internal/db/sqlite/domains.go | 17 +++++++++++++++ internal/domain/db/resolver.go | 38 +++++++++++++++++++++++++++++++++ internal/site/db/resolver.go | 14 +++++++++++- 6 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 internal/domain/db/resolver.go diff --git a/cmd/controller/app/start.go b/cmd/controller/app/start.go index 357f6d1..fe30599 100644 --- a/cmd/controller/app/start.go +++ b/cmd/controller/app/start.go @@ -14,7 +14,7 @@ import ( "github.com/oursky/pageship/internal/db" _ "github.com/oursky/pageship/internal/db/postgres" _ "github.com/oursky/pageship/internal/db/sqlite" - "github.com/oursky/pageship/internal/domain" + domaindb "github.com/oursky/pageship/internal/domain/db" "github.com/oursky/pageship/internal/handler/controller" "github.com/oursky/pageship/internal/handler/site" "github.com/oursky/pageship/internal/handler/site/middleware" @@ -129,7 +129,10 @@ func (s *setup) checkDomain(name string) error { } func (s *setup) sites(conf StartSitesConfig) error { - domainResolver := &domain.ResolverNull{} // FIXME: custom domain + domainResolver := &domaindb.Resolver{ + HostIDScheme: conf.HostIDScheme, + DB: s.database, + } siteResolver := &sitedb.Resolver{ HostIDScheme: conf.HostIDScheme, DB: s.database, diff --git a/internal/db/db.go b/internal/db/db.go index fa8bb66..452c772 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -78,6 +78,7 @@ type DeploymentsDB interface { type DomainsDB interface { CreateDomain(ctx context.Context, domain *models.Domain) error GetDomainByName(ctx context.Context, domain string) (*models.Domain, error) + GetDomainBySite(ctx context.Context, appID string, siteName string) (*models.Domain, error) DeleteDomain(ctx context.Context, id string, now time.Time) error ListDomains(ctx context.Context, appID string) ([]*models.Domain, error) } diff --git a/internal/db/postgres/domains.go b/internal/db/postgres/domains.go index 6354ae2..53eadd5 100644 --- a/internal/db/postgres/domains.go +++ b/internal/db/postgres/domains.go @@ -48,6 +48,23 @@ func (q query[T]) GetDomainByName(ctx context.Context, domainName string) (*mode return &domain, nil } +func (q query[T]) GetDomainBySite(ctx context.Context, appID string, siteName string) (*models.Domain, error) { + var domain models.Domain + + err := sqlx.GetContext(ctx, q.ext, &domain, ` + SELECT d.id, d.created_at, d.updated_at, d.deleted_at, d.domain, d.app_id, d.site_name FROM domain_association d + JOIN app a ON (a.id = d.app_id AND a.deleted_at IS NULL) + WHERE d.app_id = $1 AND d.site_name = $2 AND d.deleted_at IS NULL + `, appID, siteName) + if errors.Is(err, sql.ErrNoRows) { + return nil, models.ErrDomainNotFound + } else if err != nil { + return nil, err + } + + return &domain, nil +} + func (q query[T]) DeleteDomain(ctx context.Context, id string, now time.Time) error { _, err := q.ext.ExecContext(ctx, ` UPDATE domain_association SET deleted_at = $1 WHERE id = $2 diff --git a/internal/db/sqlite/domains.go b/internal/db/sqlite/domains.go index 54e63a0..eb3800b 100644 --- a/internal/db/sqlite/domains.go +++ b/internal/db/sqlite/domains.go @@ -48,6 +48,23 @@ func (q query[T]) GetDomainByName(ctx context.Context, domainName string) (*mode return &domain, nil } +func (q query[T]) GetDomainBySite(ctx context.Context, appID string, siteName string) (*models.Domain, error) { + var domain models.Domain + + err := sqlx.GetContext(ctx, q.ext, &domain, ` + SELECT d.id, d.created_at, d.updated_at, d.deleted_at, d.domain, d.app_id, d.site_name FROM domain_association d + JOIN app a ON (a.id = d.app_id AND a.deleted_at IS NULL) + WHERE d.app_id = ? AND d.site_name = ? AND d.deleted_at IS NULL + `, appID, siteName) + if errors.Is(err, sql.ErrNoRows) { + return nil, models.ErrDomainNotFound + } else if err != nil { + return nil, err + } + + return &domain, nil +} + func (q query[T]) DeleteDomain(ctx context.Context, id string, now time.Time) error { _, err := q.ext.ExecContext(ctx, ` UPDATE domain_association SET deleted_at = ? WHERE id = ? diff --git a/internal/domain/db/resolver.go b/internal/domain/db/resolver.go new file mode 100644 index 0000000..d03247c --- /dev/null +++ b/internal/domain/db/resolver.go @@ -0,0 +1,38 @@ +package db + +import ( + "context" + "errors" + + "github.com/oursky/pageship/internal/config" + "github.com/oursky/pageship/internal/db" + "github.com/oursky/pageship/internal/domain" + "github.com/oursky/pageship/internal/models" +) + +type Resolver struct { + DB db.DB + HostIDScheme config.HostIDScheme +} + +func (r *Resolver) Kind() string { return "database" } + +func (r *Resolver) Resolve(ctx context.Context, hostname string) (string, error) { + dom, err := r.DB.GetDomainByName(ctx, hostname) + if errors.Is(err, models.ErrDomainNotFound) { + return "", domain.ErrDomainNotFound + } + + app, err := r.DB.GetApp(ctx, dom.AppID) + if errors.Is(err, models.ErrAppNotFound) { + return "", domain.ErrDomainNotFound + } + + sub := dom.SiteName + if dom.SiteName == app.Config.DefaultSite { + sub = "" + } + id := r.HostIDScheme.Make(dom.AppID, sub) + + return id, nil +} diff --git a/internal/site/db/resolver.go b/internal/site/db/resolver.go index d836348..948ee0c 100644 --- a/internal/site/db/resolver.go +++ b/internal/site/db/resolver.go @@ -99,11 +99,23 @@ func (r *Resolver) Resolve(ctx context.Context, matchedID string) (*site.Descrip config.Access = app.Config.Deployments.Access } + domain, err := r.DB.GetDomainBySite(ctx, app.ID, siteName) + if errors.Is(err, models.ErrDomainNotFound) { + domain = nil + } else if err != nil { + return nil, err + } + + domainName := "" + if domain != nil { + domainName = domain.Domain + } + id := strings.Join([]string{deployment.AppID, siteName, deployment.ID}, "/") desc := &site.Descriptor{ ID: id, Config: &config, - Domain: "", // FIXME: custom domain + Domain: domainName, FS: newStorageFS(r.Storage, deployment), }