From 3e4b54cf9261743e7e1c77a421383069d3758546 Mon Sep 17 00:00:00 2001 From: Maxim Lebedev Date: Wed, 14 Feb 2024 21:50:54 +0600 Subject: [PATCH] :construction: WIP of entry handler split --- internal/cmd/home/home.go | 13 ++- internal/entry/delivery/http/entry_http.go | 129 ++++++++++++--------- 2 files changed, 78 insertions(+), 64 deletions(-) diff --git a/internal/cmd/home/home.go b/internal/cmd/home/home.go index 3aec5d9..b664a19 100644 --- a/internal/cmd/home/home.go +++ b/internal/cmd/home/home.go @@ -77,18 +77,19 @@ func NewApp(logger *log.Logger, config *domain.Config) (*App, error) { head, tail := urlutil.ShiftPath(r.URL.Path) switch strings.ToLower(head) { - case "": - contentType, _, _ := mime.ParseMediaType(r.Header.Get(common.HeaderAccept)) + case "": // NOTE(toby3d): render home page or redirect to home subfolder. + mediaType, _, _ := mime.ParseMediaType(r.Header.Get(common.HeaderAccept)) - switch contentType { - case common.MIMEApplicationLdJSON: // NOTE(toby3d): show entry as ActivityPub object. + 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. + // 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) diff --git a/internal/entry/delivery/http/entry_http.go b/internal/entry/delivery/http/entry_http.go index 4a7b6d4..a609355 100644 --- a/internal/entry/delivery/http/entry_http.go +++ b/internal/entry/delivery/http/entry_http.go @@ -6,7 +6,6 @@ import ( "mime" "net/http" "strings" - "time" "github.com/go-ap/activitypub" @@ -20,11 +19,20 @@ import ( type ( Handler struct { - entries entry.UseCase + *ThemeHandler + *ActivityPubHandler sites site.UseCase + entries entry.UseCase themes theme.UseCase } + ThemeHandler struct { + themes theme.UseCase + } + + ActivityPubHandler struct{} + + /* TODO(toby3d) Profile struct { *activitypub.Person @@ -47,13 +55,16 @@ type ( // [Discoverability flag]: https://docs.joinmastodon.org/spec/activitypub/#discoverable Discoverable bool `json:"discoverable"` } + */ ) func NewHandler(sites site.UseCase, entries entry.UseCase, themes theme.UseCase) *Handler { return &Handler{ - sites: sites, - entries: entries, - themes: themes, + sites: sites, + entries: entries, + themes: themes, + ThemeHandler: NewThemeHandler(themes), + ActivityPubHandler: NewActivityPubHandler(), } } @@ -69,20 +80,68 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - contentType, params, _ := mime.ParseMediaType(r.Header.Get(common.HeaderAccept)) + e, err := h.entries.Do(r.Context(), lang, tail) + if err != nil { + if errors.Is(err, entry.ErrNotExist) { + http.NotFound(w, r) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + + return + } + + contentType, _, _ := mime.ParseMediaType(r.Header.Get(common.HeaderAccept)) switch contentType { - case common.MIMEApplicationLdJSON: // NOTE(toby3d): show entry as ActivityPub object. - if profile, ok := params["profile"]; ok && profile != "https://www.w3.org/ns/activitystreams" { - http.Error(w, "got '"+profile+"' profile value, want 'https://www.w3.org/ns/activitystreams'", - http.StatusBadRequest) + default: + h.ThemeHandler.Handle(s, e).ServeHTTP(w, r) + case common.MIMEApplicationLdJSON: + h.ActivityPubHandler.Handle(s, e).ServeHTTP(w, r) + } +} + +func NewThemeHandler(themes theme.UseCase) *ThemeHandler { + return &ThemeHandler{ + themes: themes, + } +} + +func (h *ThemeHandler) Handle(s *domain.Site, e *domain.Entry) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // NOTE(toby3d): wrap founded entry into theme template and + // answer to client. + contentLanguage := make([]string, len(e.Translations)) + for i := range e.Translations { + contentLanguage[i] = e.Translations[i].Language.Code() + } + + w.Header().Set(common.HeaderContentLanguage, strings.Join(contentLanguage, ", ")) + + template, err := h.themes.Do(r.Context(), s, e) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) return } + w.Header().Set(common.HeaderContentType, common.MIMETextHTMLCharsetUTF8) + if err = template(w); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + }) +} + +func NewActivityPubHandler() *ActivityPubHandler { + return &ActivityPubHandler{} +} + +func (ActivityPubHandler) Handle(s *domain.Site, e *domain.Entry) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set(common.HeaderContentType, common.MIMEApplicationActivityJSONCharsetUTF8) encoder := json.NewEncoder(w) + /* TODO(toby3d): handle profiles on root page. if head == "" { // NOTE(toby3d): base URL point to owner Profile. langRef := activitypub.LangRef(lang.Lang()) person := activitypub.PersonNew(activitypub.IRI(s.BaseURL.String())) @@ -96,58 +155,12 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - - e, err := h.entries.Do(r.Context(), lang, tail) - if err != nil { - if errors.Is(err, entry.ErrNotExist) { - http.NotFound(w, r) - } else { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - - return - } + */ resp := activitypub.ObjectNew(activitypub.NoteType) resp.ID = activitypub.ID(s.BaseURL.JoinPath(e.File.Path()).String()) resp.Content.Add(activitypub.LangRefValueNew(activitypub.NilLangRef, string(e.Content))) _ = encoder.Encode(resp) - - return - } - - // NOTE(toby3d): search entry for requested URL and language - // code in subdir. - e, err := h.entries.Do(r.Context(), lang, tail) - if err != nil { - if errors.Is(err, entry.ErrNotExist) { - http.NotFound(w, r) - } else { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - - return - } - - // NOTE(toby3d): wrap founded entry into theme template and - // answer to client. - contentLanguage := make([]string, len(e.Translations)) - for i := range e.Translations { - contentLanguage[i] = e.Translations[i].Language.Code() - } - - w.Header().Set(common.HeaderContentLanguage, strings.Join(contentLanguage, ", ")) - - template, err := h.themes.Do(r.Context(), s, e) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - - return - } - - w.Header().Set(common.HeaderContentType, common.MIMETextHTMLCharsetUTF8) - if err = template(w); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } + }) }