summaryrefslogtreecommitdiff
path: root/internal/router
diff refs
from: back
to: back
| flip
diff options
context:
space:
mode:
Diffstat (limited to 'internal/router')
-rw-r--r--internal/router/api-v1-blog-search.go31
-rw-r--r--internal/router/api-v1-general-page-body.go51
-rw-r--r--internal/router/api-v1-general-page-bottom-embeds.go35
-rw-r--r--internal/router/api-v1-general-page-footer.go36
-rw-r--r--internal/router/api-v1-general-page-header.go38
-rw-r--r--internal/router/api-v1-general-page-top-embeds.go36
-rw-r--r--internal/router/api-v1-general-page.go57
-rw-r--r--internal/router/client-cache.go169
-rw-r--r--internal/router/lang-blog-title.go13
-rw-r--r--internal/router/lang-blog.go12
-rw-r--r--internal/router/lang-map.go13
-rw-r--r--internal/router/page-cache.go5
12 files changed, 108 insertions, 388 deletions
diff --git a/internal/router/api-v1-blog-search.go b/internal/router/api-v1-blog-search.go
index ab5425c..e22fabe 100644
--- a/internal/router/api-v1-blog-search.go
+++ b/internal/router/api-v1-blog-search.go
@@ -1,7 +1,6 @@
package router
import (
- "encoding/json"
"fmt"
"log/slog"
"net/url"
@@ -10,7 +9,6 @@ import (
"strings"
"time"
- "github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/internal/b2"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/gofiber/fiber/v2"
@@ -20,39 +18,27 @@ func init() {
tm.Add("catalogue-blog-cards", "views/partials/catalogue-blog-cards.html", "views/partials/catalogue-blog-card-tags.html")
}
-func Api_V1_BlogSearch(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
+func Api_V1_BlogSearch(l map[string]*locale.LocaleConfig, langs []string, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
sort := c.Query("sort")
lang := c.Query("lang")
tz := c.Query("tz")
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
+ if !slices.Contains(langs, lang) {
+ c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
+ return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language", lang))
}
- c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
- return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language", lang))
- langIsAvailable:
loc, err := time.LoadLocation(tz)
if err != nil {
loc = time.UTC
slog.Warn("unable to parse a client timezone, defaulting to UTC", slog.String("error", err.Error()), slog.String("tz", tz))
}
- cacheKey := "blog-search." + lang + ".pages-list"
- var pages []*b2.BlogPage
- if pagesBytes, ok := PCache.Get(cacheKey); pagesBytes != nil || ok {
- json.Unmarshal(pagesBytes, &pages)
- } else {
- pages, err = b2Client.Scan(lang + "/")
- if err != nil {
- c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
- return c.Status(fiber.ErrInternalServerError.Code).SendString(fmt.Sprintf("failed to scan pages for '%s' lang: %v", lang, err))
- }
- pagesBytes, _ := json.Marshal(pages)
- PCache.SetWithTTL(cacheKey, pagesBytes, int64(len(pagesBytes)), 5*time.Minute)
+ pages, err := b2Client.Scan(lang + "/")
+ if err != nil {
+ c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
+ return c.Status(fiber.ErrInternalServerError.Code).SendString(fmt.Sprintf("failed to scan pages for '%s' lang: %v", lang, err))
}
encodedQuery := c.Request().URI().QueryString()
@@ -84,7 +70,6 @@ func Api_V1_BlogSearch(l map[string]*locale.LocaleConfig, langs []config.Availab
"Thumbnail": page.Metadata.Thumbnail,
"Tags": page.Metadata.Tags,
"LikeCount": CCache.GetLikeCount(page.FileName),
- "ViewCount": CCache.GetViewCount(page.FileName),
})
break
}
diff --git a/internal/router/api-v1-general-page-body.go b/internal/router/api-v1-general-page-body.go
index fe21957..4108a4f 100644
--- a/internal/router/api-v1-general-page-body.go
+++ b/internal/router/api-v1-general-page-body.go
@@ -4,28 +4,22 @@ import (
"fmt"
"html/template"
"log/slog"
- "math/rand"
"net/url"
"regexp"
"slices"
"strings"
- "time"
- "github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/internal/b2"
- "github.com/SayaAndy/saya-today-web/internal/factgiver"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/gofiber/fiber/v2"
"github.com/yuin/goldmark"
)
-var FactGiver *factgiver.FactGiver
-
func init() {
tm.Add("general-page-body", "views/partials/general-page-body.html")
}
-func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig, b2Client *b2.B2Client, md goldmark.Markdown) func(c *fiber.Ctx) error {
+func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []string, b2Client *b2.B2Client, md goldmark.Markdown) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
@@ -39,33 +33,19 @@ func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []config.A
}
path := urlStruct.EscapedPath()
-
- cacheKey := fmt.Sprintf("body.%s", path)
- if val, ok := PCache.Get(cacheKey); val != nil && ok {
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
- return c.Status(fiber.StatusOK).Type("html").Send(val)
- }
-
- lang := ""
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 1 && pathParts[0] == "" {
- pathParts = []string{}
- }
- if len(pathParts) > 0 {
- lang = pathParts[0]
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
- }
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
- langIsAvailable:
+ lang := pathParts[0]
+ if !slices.Contains(langs, lang) {
+ return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang))
+ }
+
values := fiber.Map{
"L": l[lang],
"Lang": lang,
- "Path": strings.Trim(path, "/"),
"QueryString": string(c.Request().URI().QueryString()),
}
var additionalTemplates []string
@@ -120,7 +100,6 @@ func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []config.A
values["Tags"] = tagsArray
values["QuerySort"] = querySort
values["QueryTags"] = strings.Join(queryTags, ",")
- values["Title"] = l[lang].BlogSearch.Header
additionalTemplates = append(additionalTemplates, "views/pages/blog-catalogue.html")
} else if len(pathParts) == 3 && pathParts[1] == "blog" {
@@ -144,23 +123,8 @@ func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []config.A
values["MapLocationAreaMeters"] = areaError
values["Title"] = metadata.Title
values["ParsedMarkdown"] = template.HTML(parsedMarkdown)
- values["PublishedDate"] = metadata.PublishedTime.Format("2006-01-02 15:04:05 -07:00")
- values["ActionDate"] = metadata.ActionDate
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
-
- go CCache.View(c.IP(), pathParts[2])
- } else if len(pathParts) == 1 {
- values["Title"] = l[lang].HomePage.Header
- values["FilledHeartCount"] = uint(40)
- values["OutlineHeartCount"] = uint(40)
- values["GifName"] = fmt.Sprintf("otter-%d.gif", rand.Int()%3+1)
- values["FunFacts"] = FactGiver.Give(lang)
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
- } else if len(pathParts) == 0 {
- values["Title"] = "Choose Your Language"
- values["AvailableLanguages"] = langs
- additionalTemplates = append(additionalTemplates, "views/pages/language-pick.html")
}
content, err := tm.Render("general-page-body", values, additionalTemplates...)
@@ -169,7 +133,6 @@ func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []config.A
return c.Status(fiber.ErrInternalServerError.Code).SendString("failed to generate div")
}
- go PCache.SetWithTTL(cacheKey, content, int64(len(content)), 5*time.Minute)
c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
return c.Status(fiber.StatusOK).Type("html").Send(content)
}
diff --git a/internal/router/api-v1-general-page-bottom-embeds.go b/internal/router/api-v1-general-page-bottom-embeds.go
index 0a2030f..f0957f3 100644
--- a/internal/router/api-v1-general-page-bottom-embeds.go
+++ b/internal/router/api-v1-general-page-bottom-embeds.go
@@ -4,10 +4,9 @@ import (
"fmt"
"log/slog"
"net/url"
+ "slices"
"strings"
- "time"
- "github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/internal/b2"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/gofiber/fiber/v2"
@@ -17,7 +16,7 @@ func init() {
tm.Add("general-page-bottom-embeds", "views/partials/general-page-bottom-embeds.html")
}
-func Api_V1_GeneralPage_BottomEmbeds(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
+func Api_V1_GeneralPage_BottomEmbeds(l map[string]*locale.LocaleConfig, langs []string, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
@@ -31,32 +30,19 @@ func Api_V1_GeneralPage_BottomEmbeds(l map[string]*locale.LocaleConfig, langs []
}
path := urlStruct.EscapedPath()
- cacheKey := fmt.Sprintf("bottom-embeds.%s", path)
- if val, ok := PCache.Get(cacheKey); val != nil && ok {
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
- return c.Status(fiber.StatusOK).Type("html").Send(val)
- }
-
- lang := ""
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 1 && pathParts[0] == "" {
- pathParts = []string{}
- }
- if len(pathParts) > 0 {
- lang = pathParts[0]
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
- }
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
- langIsAvailable:
+ lang := pathParts[0]
+ if !slices.Contains(langs, lang) {
+ return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang))
+ }
+
values := fiber.Map{
"L": l[lang],
"Lang": lang,
- "Path": strings.Trim(path, "/"),
"QueryString": string(c.Request().URI().QueryString()),
}
var additionalTemplates []string
@@ -65,10 +51,6 @@ func Api_V1_GeneralPage_BottomEmbeds(l map[string]*locale.LocaleConfig, langs []
additionalTemplates = append(additionalTemplates, "views/pages/blog-catalogue.html")
} else if len(pathParts) == 3 && pathParts[1] == "blog" {
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
- } else if len(pathParts) == 1 {
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
- } else if len(pathParts) == 0 {
- additionalTemplates = append(additionalTemplates, "views/pages/language-pick.html")
}
content, err := tm.Render("general-page-bottom-embeds", values, additionalTemplates...)
@@ -77,7 +59,6 @@ func Api_V1_GeneralPage_BottomEmbeds(l map[string]*locale.LocaleConfig, langs []
return c.Status(fiber.ErrInternalServerError.Code).SendString("failed to generate div")
}
- go PCache.SetWithTTL(cacheKey, content, int64(len(content)), 5*time.Minute)
c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
return c.Status(fiber.StatusOK).Type("html").Send(content)
}
diff --git a/internal/router/api-v1-general-page-footer.go b/internal/router/api-v1-general-page-footer.go
index 2030b3b..39b6bea 100644
--- a/internal/router/api-v1-general-page-footer.go
+++ b/internal/router/api-v1-general-page-footer.go
@@ -4,10 +4,9 @@ import (
"fmt"
"log/slog"
"net/url"
+ "slices"
"strings"
- "time"
- "github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/gofiber/fiber/v2"
)
@@ -16,7 +15,7 @@ func init() {
tm.Add("general-page-footer", "views/partials/general-page-footer.html")
}
-func Api_V1_GeneralPage_Footer(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig) func(c *fiber.Ctx) error {
+func Api_V1_GeneralPage_Footer(l map[string]*locale.LocaleConfig, langs []string) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
@@ -30,33 +29,19 @@ func Api_V1_GeneralPage_Footer(l map[string]*locale.LocaleConfig, langs []config
}
path := urlStruct.EscapedPath()
-
- cacheKey := fmt.Sprintf("footer.%s", path)
- if val, ok := PCache.Get(cacheKey); val != nil && ok {
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
- return c.Status(fiber.StatusOK).Type("html").Send(val)
- }
-
- lang := ""
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 1 && pathParts[0] == "" {
- pathParts = []string{}
- }
- if len(pathParts) > 0 {
- lang = pathParts[0]
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
- }
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
- langIsAvailable:
+ lang := pathParts[0]
+ if !slices.Contains(langs, lang) {
+ return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang))
+ }
+
values := fiber.Map{
"L": l[lang],
"Lang": lang,
- "Path": strings.Trim(path, "/"),
"QueryString": string(c.Request().URI().QueryString()),
}
var additionalTemplates []string
@@ -65,10 +50,6 @@ func Api_V1_GeneralPage_Footer(l map[string]*locale.LocaleConfig, langs []config
additionalTemplates = append(additionalTemplates, "views/pages/blog-catalogue.html")
} else if len(pathParts) == 3 && pathParts[1] == "blog" {
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
- } else if len(pathParts) == 1 {
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
- } else if len(pathParts) == 0 {
- additionalTemplates = append(additionalTemplates, "views/pages/language-pick.html")
}
content, err := tm.Render("general-page-footer", values, additionalTemplates...)
@@ -77,7 +58,6 @@ func Api_V1_GeneralPage_Footer(l map[string]*locale.LocaleConfig, langs []config
return c.Status(fiber.ErrInternalServerError.Code).SendString("failed to generate div")
}
- go PCache.SetWithTTL(cacheKey, content, int64(len(content)), 5*time.Minute)
c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
return c.Status(fiber.StatusOK).Type("html").Send(content)
}
diff --git a/internal/router/api-v1-general-page-header.go b/internal/router/api-v1-general-page-header.go
index a2c832b..0529ba6 100644
--- a/internal/router/api-v1-general-page-header.go
+++ b/internal/router/api-v1-general-page-header.go
@@ -4,10 +4,9 @@ import (
"fmt"
"log/slog"
"net/url"
+ "slices"
"strings"
- "time"
- "github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/internal/b2"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/gofiber/fiber/v2"
@@ -17,7 +16,7 @@ func init() {
tm.Add("general-page-header", "views/partials/general-page-header.html")
}
-func Api_V1_GeneralPage_Header(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
+func Api_V1_GeneralPage_Header(l map[string]*locale.LocaleConfig, langs []string, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
@@ -31,33 +30,19 @@ func Api_V1_GeneralPage_Header(l map[string]*locale.LocaleConfig, langs []config
}
path := urlStruct.EscapedPath()
-
- cacheKey := fmt.Sprintf("header.%s", path)
- if val, ok := PCache.Get(cacheKey); val != nil && ok {
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
- return c.Status(fiber.StatusOK).Type("html").Send(val)
- }
-
- lang := ""
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 1 && pathParts[0] == "" {
- pathParts = []string{}
- }
- if len(pathParts) > 0 {
- lang = pathParts[0]
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
- }
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
- langIsAvailable:
+ lang := pathParts[0]
+ if !slices.Contains(langs, lang) {
+ return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang))
+ }
+
values := fiber.Map{
"L": l[lang],
"Lang": lang,
- "Path": strings.Trim(path, "/"),
"QueryString": string(c.Request().URI().QueryString()),
}
var additionalTemplates []string
@@ -74,12 +59,6 @@ func Api_V1_GeneralPage_Header(l map[string]*locale.LocaleConfig, langs []config
values["PublishedDate"] = metadata.PublishedTime.Format("2006-01-02 15:04:05 -07:00")
values["ActionDate"] = metadata.ActionDate
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
- } else if len(pathParts) == 1 {
- values["Title"] = l[lang].HomePage.Header
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
- } else if len(pathParts) == 0 {
- values["Title"] = "Choose Your Language"
- additionalTemplates = append(additionalTemplates, "views/pages/language-pick.html")
}
content, err := tm.Render("general-page-header", values, additionalTemplates...)
@@ -88,7 +67,6 @@ func Api_V1_GeneralPage_Header(l map[string]*locale.LocaleConfig, langs []config
return c.Status(fiber.ErrInternalServerError.Code).SendString("failed to generate div")
}
- go PCache.SetWithTTL(cacheKey, content, int64(len(content)), 5*time.Minute)
c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
return c.Status(fiber.StatusOK).Type("html").Send(content)
}
diff --git a/internal/router/api-v1-general-page-top-embeds.go b/internal/router/api-v1-general-page-top-embeds.go
index 544e3a4..090107b 100644
--- a/internal/router/api-v1-general-page-top-embeds.go
+++ b/internal/router/api-v1-general-page-top-embeds.go
@@ -4,10 +4,9 @@ import (
"fmt"
"log/slog"
"net/url"
+ "slices"
"strings"
- "time"
- "github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/gofiber/fiber/v2"
)
@@ -16,7 +15,7 @@ func init() {
tm.Add("general-page-top-embeds", "views/partials/general-page-top-embeds.html")
}
-func Api_V1_GeneralPage_TopEmbeds(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig) func(c *fiber.Ctx) error {
+func Api_V1_GeneralPage_TopEmbeds(l map[string]*locale.LocaleConfig, langs []string) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
@@ -30,33 +29,19 @@ func Api_V1_GeneralPage_TopEmbeds(l map[string]*locale.LocaleConfig, langs []con
}
path := urlStruct.EscapedPath()
-
- cacheKey := fmt.Sprintf("top-embeds.%s", path)
- if val, ok := PCache.Get(cacheKey); val != nil && ok {
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
- return c.Status(fiber.StatusOK).Type("html").Send(val)
- }
-
- lang := ""
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 1 && pathParts[0] == "" {
- pathParts = []string{}
- }
- if len(pathParts) > 0 {
- lang = pathParts[0]
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
- }
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
- langIsAvailable:
+ lang := pathParts[0]
+ if !slices.Contains(langs, lang) {
+ return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang))
+ }
+
values := fiber.Map{
"L": l[lang],
"Lang": lang,
- "Path": strings.Trim(path, "/"),
"QueryString": string(c.Request().URI().QueryString()),
}
var additionalTemplates []string
@@ -65,10 +50,6 @@ func Api_V1_GeneralPage_TopEmbeds(l map[string]*locale.LocaleConfig, langs []con
additionalTemplates = append(additionalTemplates, "views/pages/blog-catalogue.html")
} else if len(pathParts) == 3 && pathParts[1] == "blog" {
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
- } else if len(pathParts) == 1 {
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
- } else if len(pathParts) == 0 {
- additionalTemplates = append(additionalTemplates, "views/pages/language-pick.html")
}
content, err := tm.Render("general-page-top-embeds", values, additionalTemplates...)
@@ -77,7 +58,6 @@ func Api_V1_GeneralPage_TopEmbeds(l map[string]*locale.LocaleConfig, langs []con
return c.Status(fiber.ErrInternalServerError.Code).SendString("failed to generate div")
}
- go PCache.SetWithTTL(cacheKey, content, int64(len(content)), 5*time.Minute)
c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
return c.Status(fiber.StatusOK).Type("html").Send(content)
}
diff --git a/internal/router/api-v1-general-page.go b/internal/router/api-v1-general-page.go
deleted file mode 100644
index a77fc5e..0000000
--- a/internal/router/api-v1-general-page.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package router
-
-import (
- "log/slog"
- "strings"
-
- "github.com/SayaAndy/saya-today-web/config"
- "github.com/SayaAndy/saya-today-web/locale"
- "github.com/gofiber/fiber/v2"
-)
-
-func init() {
- tm.Add("general-page", "views/layouts/general-page.html")
-}
-
-func Api_V1_GeneralPage(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig) func(c *fiber.Ctx) error {
- return func(c *fiber.Ctx) error {
- c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
- path := c.Path()
-
- lang := ""
- pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 1 && pathParts[0] == "" {
- pathParts = []string{}
- }
- if len(pathParts) > 0 {
- lang = pathParts[0]
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
- }
- return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
- }
-
- langIsAvailable:
- cacheKey := "general-page." + lang
- if val, ok := PCache.Get(cacheKey); val != nil && ok {
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
- return c.Status(fiber.StatusOK).Type("html").Send(val)
- }
-
- content, err := tm.Render("general-page", fiber.Map{
- "L": l[lang],
- "Lang": lang,
- "QueryString": string(c.Request().URI().QueryString()),
- })
- if err != nil {
- slog.Warn("failed to generate div", slog.String("path", path), slog.String("error", err.Error()))
- return c.Status(fiber.ErrInternalServerError.Code).SendString("failed to generate div")
- }
-
- go PCache.Set(cacheKey, content, int64(len(content)))
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
- return c.Status(fiber.StatusOK).Type("html").Send(content)
- }
-}
diff --git a/internal/router/client-cache.go b/internal/router/client-cache.go
index d607cdd..81d7641 100644
--- a/internal/router/client-cache.go
+++ b/internal/router/client-cache.go
@@ -11,12 +11,16 @@ import (
"golang.org/x/crypto/argon2"
)
+type PageLike struct {
+ PageRef string
+ UserId string
+}
+
type ClientCache struct {
hashMap map[string]string
hashMapMutex sync.RWMutex
likePageMap map[string]map[string]struct{}
- viewPageMap map[string]map[string]struct{}
pageMutexMap map[string]*sync.RWMutex
pageMutexMapMutex sync.Mutex
@@ -39,7 +43,6 @@ func NewClientCache(db *sql.DB, salt []byte) (*ClientCache, error) {
}
likePageMap := make(map[string]map[string]struct{})
- viewPageMap := make(map[string]map[string]struct{})
pageMutexMap := make(map[string]*sync.RWMutex)
for rows.Next() {
@@ -52,32 +55,9 @@ func NewClientCache(db *sql.DB, salt []byte) (*ClientCache, error) {
userIdString := base64.RawStdEncoding.EncodeToString(userId)
if _, ok := likePageMap[pageRef]; !ok {
likePageMap[pageRef] = make(map[string]struct{})
- viewPageMap[pageRef] = make(map[string]struct{})
pageMutexMap[pageRef] = &sync.RWMutex{}
}
likePageMap[pageRef][userIdString] = struct{}{}
- viewPageMap[pageRef][userIdString] = struct{}{}
- }
-
- rows, err = tx.Query("select * from blog_views;")
- if err != nil {
- tx.Rollback()
- return nil, fmt.Errorf("fail to query db for blog_views to fill cache: %w", err)
- }
-
- for rows.Next() {
- var pageRef string
- var userId []byte
- if err = rows.Scan(&pageRef, &userId); err != nil {
- tx.Rollback()
- return nil, fmt.Errorf("fail scanning blog_views to fill cache: %w", err)
- }
- userIdString := base64.RawStdEncoding.EncodeToString(userId)
- if _, ok := viewPageMap[pageRef]; !ok {
- viewPageMap[pageRef] = make(map[string]struct{})
- pageMutexMap[pageRef] = &sync.RWMutex{}
- }
- viewPageMap[pageRef][userIdString] = struct{}{}
}
if err = tx.Commit(); err != nil {
@@ -87,7 +67,6 @@ func NewClientCache(db *sql.DB, salt []byte) (*ClientCache, error) {
return &ClientCache{
hashMap: make(map[string]string),
likePageMap: likePageMap,
- viewPageMap: viewPageMap,
pageMutexMap: pageMutexMap,
salt: salt,
db: db,
@@ -100,14 +79,51 @@ func (c *ClientCache) Close() error {
return fmt.Errorf("fail to init transaction with db to dump cache: %w", err)
}
- if err = batchSave(tx, "blog_likes", c.likePageMap); err != nil {
+ if _, err = tx.Exec("delete from blog_likes;"); err != nil {
tx.Rollback()
- return fmt.Errorf("fail to save blog_likes: %s", err)
+ return fmt.Errorf("fail to truncate table blog_likes: %w", err)
}
- if err = batchSave(tx, "blog_views", c.viewPageMap); err != nil {
- tx.Rollback()
- return fmt.Errorf("fail to save blog_views: %s", err)
+ userIdBytes := make(map[string][]byte)
+
+ sqlStatement := fmt.Sprintf(`
+ INSERT OR IGNORE INTO blog_likes (page_ref, user_id)
+ VALUES %s(?, ?);
+ `, strings.Repeat("(?, ?), ", 99))
+ sqlStatementVars := make([]any, 0, 200)
+
+ for pageRef, userSet := range c.likePageMap {
+ for userId := range userSet {
+ if _, ok := userIdBytes[userId]; !ok {
+ userIdBytes[userId], err = base64.RawStdEncoding.DecodeString(userId)
+ if err != nil {
+ slog.Warn("couldn't parse one of user hashes into bytes back", slog.String("hash", userId), slog.String("error", err.Error()))
+ continue
+ }
+ }
+
+ sqlStatementVars = append(sqlStatementVars, any(pageRef), any(userIdBytes[userId]))
+ if len(sqlStatementVars) < 200 {
+ continue
+ }
+
+ if _, err := tx.Exec(sqlStatement, sqlStatementVars...); err != nil {
+ slog.Warn("couldn't insert blog like pairs into db", slog.String("error", err.Error()))
+ }
+
+ sqlStatementVars = make([]any, 0, 200)
+ }
+ }
+
+ if len(sqlStatementVars) > 0 {
+ sqlStatement = fmt.Sprintf(`
+ INSERT OR IGNORE INTO blog_likes (page_ref, user_id)
+ VALUES %s(?, ?);
+ `, strings.Repeat("(?, ?), ", len(sqlStatementVars)/2-1))
+
+ if _, err := tx.Exec(sqlStatement, sqlStatementVars...); err != nil {
+ slog.Warn("couldn't insert blog like pairs into db", slog.String("error", err.Error()))
+ }
}
return tx.Commit()
@@ -211,94 +227,3 @@ func (c *ClientCache) LikeOff(id string, page string) (alreadyUnliked bool) {
delete(c.likePageMap[page], hash)
return false
}
-
-func (c *ClientCache) GetViewStatus(id string, page string) bool {
- page = strings.Clone(page)
-
- mutex := c.getPageMutex(page)
- mutex.RLock()
- defer mutex.RUnlock()
-
- if _, ok := c.viewPageMap[page]; !ok {
- return false
- }
- _, ok := c.viewPageMap[page][c.GetHash(id)]
- return ok
-}
-
-func (c *ClientCache) GetViewCount(page string) int {
- page = strings.Clone(page)
-
- mutex := c.getPageMutex(page)
- mutex.RLock()
- defer mutex.RUnlock()
-
- if userSet, ok := c.viewPageMap[page]; ok {
- return len(userSet)
- }
- return 0
-}
-
-func (c *ClientCache) View(id string, page string) {
- page = strings.Clone(page)
- hash := c.GetHash(id)
-
- mutex := c.getPageMutex(page)
- mutex.Lock()
- defer mutex.Unlock()
-
- if _, ok := c.viewPageMap[page]; !ok {
- c.viewPageMap[page] = make(map[string]struct{})
- }
- c.viewPageMap[page][hash] = struct{}{}
-}
-
-func batchSave(tx *sql.Tx, table string, pageMap map[string]map[string]struct{}) (err error) {
- if _, err = tx.Exec(fmt.Sprintf("delete from %s;", table)); err != nil {
- return fmt.Errorf("fail to truncate table %s: %w", table, err)
- }
-
- userIdBytes := make(map[string][]byte)
-
- sqlStatement := fmt.Sprintf(`
- INSERT OR IGNORE INTO %s (page_ref, user_id)
- VALUES %s(?, ?);
- `, table, strings.Repeat("(?, ?), ", 99))
- sqlStatementVars := make([]any, 0, 200)
-
- for pageRef, userSet := range pageMap {
- for userId := range userSet {
- if _, ok := userIdBytes[userId]; !ok {
- userIdBytes[userId], err = base64.RawStdEncoding.DecodeString(userId)
- if err != nil {
- slog.Warn("couldn't parse one of user hashes into bytes back", slog.String("hash", userId), slog.String("error", err.Error()))
- continue
- }
- }
-
- sqlStatementVars = append(sqlStatementVars, any(pageRef), any(userIdBytes[userId]))
- if len(sqlStatementVars) < 200 {
- continue
- }
-
- if _, err := tx.Exec(sqlStatement, sqlStatementVars...); err != nil {
- slog.Warn("couldn't insert blog stat pairs into db", slog.String("table", table), slog.String("error", err.Error()))
- }
-
- sqlStatementVars = make([]any, 0, 200)
- }
- }
-
- if len(sqlStatementVars) > 0 {
- sqlStatement = fmt.Sprintf(`
- INSERT OR IGNORE INTO %s (page_ref, user_id)
- VALUES %s(?, ?);
- `, table, strings.Repeat("(?, ?), ", len(sqlStatementVars)/2-1))
-
- if _, err := tx.Exec(sqlStatement, sqlStatementVars...); err != nil {
- slog.Warn("couldn't insert blog stat pairs into db", slog.String("table", table), slog.String("error", err.Error()))
- }
- }
-
- return nil
-}
diff --git a/internal/router/lang-blog-title.go b/internal/router/lang-blog-title.go
index 6e80671..d6ca917 100644
--- a/internal/router/lang-blog-title.go
+++ b/internal/router/lang-blog-title.go
@@ -5,10 +5,10 @@ import (
"fmt"
"html/template"
"log/slog"
+ "slices"
"strconv"
"strings"
- "github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/internal/b2"
"github.com/SayaAndy/saya-today-web/internal/frontmatter"
"github.com/SayaAndy/saya-today-web/locale"
@@ -20,20 +20,17 @@ func init() {
tm.Add("blog-page", "views/layouts/general-page.html", "views/pages/blog-page.html")
}
-func Lang_Blog_Title(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig, b2Client *b2.B2Client, md goldmark.Markdown) func(c *fiber.Ctx) error {
+func Lang_Blog_Title(l map[string]*locale.LocaleConfig, langs []string, b2Client *b2.B2Client, md goldmark.Markdown) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
ip := c.IP()
slog.Debug("client entering blog page", slog.String("ip", ip), slog.String("page", c.Path()))
lang := c.Params("lang")
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
+ if !slices.Contains(langs, lang) {
+ c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
+ return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang))
}
- return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language", lang))
- langIsAvailable:
metadata, parsedMarkdown, err := readBlogPost(md, b2Client, lang+"/"+c.Params("title"))
if err != nil {
c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
diff --git a/internal/router/lang-blog.go b/internal/router/lang-blog.go
index 960ac3d..38a6597 100644
--- a/internal/router/lang-blog.go
+++ b/internal/router/lang-blog.go
@@ -8,7 +8,6 @@ import (
"slices"
"strings"
- "github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/internal/b2"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/gofiber/fiber/v2"
@@ -18,17 +17,14 @@ func init() {
tm.Add("blog-catalogue", "views/layouts/general-page.html", "views/pages/blog-catalogue.html")
}
-func Lang_Blog(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
+func Lang_Blog(l map[string]*locale.LocaleConfig, langs []string, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
lang := c.Params("lang")
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
+ if !slices.Contains(langs, lang) {
+ c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
+ return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang))
}
- return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language", lang))
- langIsAvailable:
querySort := c.Query("sort")
if querySort == "" {
querySort = "publicationDateDesc"
diff --git a/internal/router/lang-map.go b/internal/router/lang-map.go
index a744f02..e94d756 100644
--- a/internal/router/lang-map.go
+++ b/internal/router/lang-map.go
@@ -3,10 +3,10 @@ package router
import (
"fmt"
"log/slog"
+ "slices"
"strconv"
"strings"
- "github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/internal/b2"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/gofiber/fiber/v2"
@@ -16,17 +16,14 @@ func init() {
tm.Add("global-map", "views/pages/global-map.html")
}
-func Lang_Map(l map[string]*locale.LocaleConfig, langs []config.AvailableLanguageConfig, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
+func Lang_Map(l map[string]*locale.LocaleConfig, langs []string, b2Client *b2.B2Client) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
lang := c.Params("lang")
- for _, availableLang := range langs {
- if availableLang.Name == lang {
- goto langIsAvailable
- }
+ if !slices.Contains(langs, lang) {
+ c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
+ return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language... yet??", lang))
}
- return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("server does not support '%s' language", lang))
- langIsAvailable:
pages, err := b2Client.Scan(lang + "/")
status := fiber.StatusOK
if err != nil {
diff --git a/internal/router/page-cache.go b/internal/router/page-cache.go
deleted file mode 100644
index 01e4792..0000000
--- a/internal/router/page-cache.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package router
-
-import "github.com/dgraph-io/ristretto/v2"
-
-var PCache *ristretto.Cache[string, []byte]