From 495fbc523ab7450dc1266cabff9f08415255c7ff Mon Sep 17 00:00:00 2001 From: Maxim Lebedev Date: Wed, 14 Feb 2024 23:45:03 +0600 Subject: [PATCH] :building_construction: Reuse HTTP delivery of content modules --- internal/cmd/home/home.go | 109 ++++++++++++-------------------------- 1 file changed, 35 insertions(+), 74 deletions(-) diff --git a/internal/cmd/home/home.go b/internal/cmd/home/home.go index bad5aa9..b802518 100644 --- a/internal/cmd/home/home.go +++ b/internal/cmd/home/home.go @@ -1,35 +1,31 @@ package home import ( - "bytes" "context" "fmt" - "io" "io/fs" "log" - "mime" "net" "net/http" "os" "strings" "time" - "golang.org/x/text/language" - - "source.toby3d.me/toby3d/home/internal/common" "source.toby3d.me/toby3d/home/internal/domain" - entryhttpdelivery "source.toby3d.me/toby3d/home/internal/entry/delivery/http" pagefsrepo "source.toby3d.me/toby3d/home/internal/entry/repository/fs" pageucase "source.toby3d.me/toby3d/home/internal/entry/usecase" "source.toby3d.me/toby3d/home/internal/middleware" + resourcehttpdelivery "source.toby3d.me/toby3d/home/internal/resource/delivery/http" resourcefsrepo "source.toby3d.me/toby3d/home/internal/resource/repository/fs" resourceucase "source.toby3d.me/toby3d/home/internal/resource/usecase" servercase "source.toby3d.me/toby3d/home/internal/server/usecase" + sitehttpdelivery "source.toby3d.me/toby3d/home/internal/site/delivery/http" sitefsrepo "source.toby3d.me/toby3d/home/internal/site/repository/fs" siteucase "source.toby3d.me/toby3d/home/internal/site/usecase" statichttpdelivery "source.toby3d.me/toby3d/home/internal/static/delivery/http" staticfsrepo "source.toby3d.me/toby3d/home/internal/static/repository/fs" staticucase "source.toby3d.me/toby3d/home/internal/static/usecase" + themehttpdelivery "source.toby3d.me/toby3d/home/internal/theme/delivery/http" themefsrepo "source.toby3d.me/toby3d/home/internal/theme/repository/fs" themeucase "source.toby3d.me/toby3d/home/internal/theme/usecase" "source.toby3d.me/toby3d/home/internal/urlutil" @@ -63,8 +59,10 @@ func NewApp(logger *log.Logger, config *domain.Config) (*App, error) { serverer := servercase.NewServerUseCase(sites) webfingerer := webfingerucase.NewWebFingerUseCase(sites) webfingerHandler := webfingerhttpdelivery.NewHandler(webfingerer) - entryHandler := entryhttpdelivery.NewHandler(siter, entrier, themer) + themeHandler := themehttpdelivery.NewHandler(themer) + resourceHandler := resourcehttpdelivery.NewHandler(resourcer, contentDir) staticHandler := statichttpdelivery.NewHandler(staticer) + siteHandler := sitehttpdelivery.NewHandler(siter) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // NOTE(toby3d): any file in $HOME_STATIC_DIR is public and // unprotected by design, so it's safe to search it first before @@ -76,55 +74,9 @@ func NewApp(logger *log.Logger, config *domain.Config) (*App, error) { return } - return - } - head, tail := urlutil.ShiftPath(r.URL.Path) switch strings.ToLower(head) { - case "": // NOTE(toby3d): render home page or redirect to home subfolder. - mediaType, _, _ := mime.ParseMediaType(r.Header.Get(common.HeaderAccept)) - - switch mediaType { - case common.MIMEApplicationLdJSON: - entryHandler.ServeHTTP(w, r) - - return - } - - // NOTE(toby3d): read $HOME_CONTENT_DIR/index.md as a - // source of truth and global settings for any child - // entry. - s, err := siter.Do(r.Context(), domain.LanguageUnd) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - - return - } - - if s.IsMultiLingual() { - supported := make([]language.Tag, len(s.Languages)) - for i := range s.Languages { - supported[i] = language.Make(s.Languages[i].Lang()) - } - - if s.DefaultLanguage != domain.LanguageUnd { - supported = append([]language.Tag{language.Make(s.DefaultLanguage.Code())}, - supported...) - } - - requested, _, _ := language.ParseAcceptLanguage(r.Header.Get( - common.HeaderAcceptLanguage)) - if len(requested) == 0 { - requested = append(requested, language.English) - } - - matched, _, _ := language.NewMatcher(supported).Match(requested...) - http.Redirect(w, r, "/"+domain.NewLanguage(matched.String()).Lang()+"/", - http.StatusSeeOther) - - return - } case ".well-known": switch strings.ToLower(tail) { case "/webfinger": @@ -134,30 +86,39 @@ func NewApp(logger *log.Logger, config *domain.Config) (*App, error) { } } - if res, err := resourcer.Do(r.Context(), tail); err == nil { - // TODO(toby3d) : ugly workaround, must be refactored - resFile, err := contentDir.Open(res.File.Filename()) - if err != nil { - http.Error(w, "cannot open resource: "+err.Error(), http.StatusInternalServerError) - - return - } - defer resFile.Close() - - resBytes, err := io.ReadAll(resFile) - if err != nil { - http.Error(w, "cannot read resource: "+err.Error(), http.StatusInternalServerError) - - return - } - defer resFile.Close() - - http.ServeContent(w, r, res.Name(), domain.ResourceModTime(res), bytes.NewReader(resBytes)) + // NOTE(toby3d): read $HOME_CONTENT_DIR/index.md as a source of + // truth and global settings for any child entry. + site, handler, err := siteHandler.Handle(r.Context(), head) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) return } - entryHandler.ServeHTTP(w, r) + if handler != nil { + handler.ServeHTTP(w, r) + + return + } + + if site.IsMultiLingual() { + r.URL.Path = tail + } + + if handler, err = resourceHandler.Handle(r.Context(), r.URL.Path); err == nil { + handler.ServeHTTP(w, r) + + return + } + + entry, err := entrier.Do(r.Context(), site.Language, r.URL.Path) + if err != nil { + http.NotFound(w, r) + + return + } + + themeHandler.Handle(site, entry).ServeHTTP(w, r) }) chain := middleware.Chain{ // middleware.LogFmt(),