aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-07-01 03:46:10 -0700
committerFuwn <[email protected]>2025-07-01 03:46:10 -0700
commit6ffa4e3e35a10336aa8e7d6fa369cb51ee36ec20 (patch)
tree157be9643023a1adc63afef5555ff5305bdd9e71
parenteb81c62b839285b9d904bdff393ed2291468e41e (diff)
downloadmayu-6ffa4e3e35a10336aa8e7d6fa369cb51ee36ec20.tar.xz
mayu-6ffa4e3e35a10336aa8e7d6fa369cb51ee36ec20.zip
feat: Pre-cache themes in memory
-rw-r--r--src/cache.gleam65
-rw-r--r--src/mayu.gleam4
-rw-r--r--src/request.gleam3
-rw-r--r--src/svg.gleam45
4 files changed, 86 insertions, 31 deletions
diff --git a/src/cache.gleam b/src/cache.gleam
new file mode 100644
index 0000000..bc9144b
--- /dev/null
+++ b/src/cache.gleam
@@ -0,0 +1,65 @@
+import gleam/dict.{type Dict}
+import gleam/int
+import gleam/list
+import gleam/option.{type Option}
+import gleam/result
+import image
+import simplifile
+
+pub type CachedImage {
+ CachedImage(data: BitArray, info: image.ImageInformation)
+}
+
+pub type ThemeCache =
+ Dict(String, Dict(Int, CachedImage))
+
+pub fn load_themes() {
+ list.fold(
+ case simplifile.read_directory("./themes") {
+ Ok(files) -> files
+ Error(_) -> []
+ },
+ dict.new(),
+ fn(accumulated_themes, theme) {
+ dict.insert(
+ accumulated_themes,
+ theme,
+ list.range(0, 9)
+ |> list.fold(dict.new(), fn(accumulated_digits, digit) {
+ case
+ simplifile.read_bits(
+ from: "./themes/"
+ <> theme
+ <> "/"
+ <> int.to_string(digit)
+ <> "."
+ <> case theme {
+ "gelbooru-h" | "moebooru-h" | "lain" | "garukura" -> "png"
+ _ -> "gif"
+ },
+ )
+ {
+ Ok(image_data) -> {
+ case image.get_image_information(image_data) {
+ Ok(info) ->
+ dict.insert(
+ accumulated_digits,
+ digit,
+ CachedImage(data: image_data, info: info),
+ )
+ Error(_) -> accumulated_digits
+ }
+ }
+ Error(_) -> accumulated_digits
+ }
+ }),
+ )
+ },
+ )
+}
+
+pub fn get_image(cache, theme, digit) -> Option(CachedImage) {
+ dict.get(cache, theme)
+ |> result.then(fn(theme_images) { dict.get(theme_images, digit) })
+ |> option.from_result
+}
diff --git a/src/mayu.gleam b/src/mayu.gleam
index 95442e8..2c3d78e 100644
--- a/src/mayu.gleam
+++ b/src/mayu.gleam
@@ -1,3 +1,4 @@
+import cache
import database
import gleam/erlang/process
import mist
@@ -10,6 +11,7 @@ pub fn main() {
wisp.configure_logger()
let _ = simplifile.create_directory("./data")
+ let image_cache = cache.load_themes()
use connection <- sqlight.with_connection("./data/count.db")
@@ -18,7 +20,7 @@ pub fn main() {
let secret_key_base = wisp.random_string(64)
let assert Ok(_) =
wisp.mist_handler(
- fn(request) { request.handle(request, connection) },
+ fn(request) { request.handle(request, connection, image_cache) },
secret_key_base,
)
|> mist.new
diff --git a/src/request.gleam b/src/request.gleam
index d726a03..c66e66d 100644
--- a/src/request.gleam
+++ b/src/request.gleam
@@ -19,7 +19,7 @@ fn middleware(request, handle) {
handle(request)
}
-pub fn handle(request, connection) {
+pub fn handle(request, connection, image_cache) {
use _ <- middleware(request)
case wisp.path_segments(request) {
@@ -50,6 +50,7 @@ pub fn handle(request, connection) {
|> wisp.set_header("Content-Type", "image/svg+xml")
|> wisp.string_body(
svg.xml(
+ image_cache,
case list.key_find(wisp.get_query(request), "theme") {
Ok(theme) -> theme
_ -> "asoul"
diff --git a/src/svg.gleam b/src/svg.gleam
index d9de64f..884d6cf 100644
--- a/src/svg.gleam
+++ b/src/svg.gleam
@@ -1,9 +1,10 @@
+import cache
import gleam/bit_array
import gleam/int
import gleam/list
+import gleam/option.{Some}
import gleam/string_builder
import image
-import simplifile
type XmlImages {
XmlImages(xml: String, width: Int, height: Int)
@@ -21,43 +22,29 @@ fn image(data, image: image.ImageInformation, width) {
) <> "\"/>"
}
-fn images(theme, digits, width, height, svgs) {
+fn images(image_cache, theme, digits, width, height, svgs) {
case digits {
[] -> XmlImages(string_builder.to_string(svgs), width, height)
[digit, ..rest] ->
- case
- simplifile.read_bits(
- from: "./themes/"
- <> theme
- <> "/"
- <> int.to_string(digit)
- <> "."
- <> case theme {
- "gelbooru-h" | "moebooru-h" | "lain" | "garukura" -> "png"
- _ -> "gif"
- },
- )
- {
- Ok(data) ->
- case image.get_image_information(data) {
- Ok(information) ->
- images(
- theme,
- rest,
- width + information.width,
- int.max(height, information.height),
- string_builder.append(svgs, image(data, information, width)),
- )
- Error(_) -> XmlImages(string_builder.to_string(svgs), width, height)
- }
- Error(_) -> XmlImages(string_builder.to_string(svgs), width, height)
+ case cache.get_image(image_cache, theme, digit) {
+ Some(cached) ->
+ images(
+ image_cache,
+ theme,
+ rest,
+ width + cached.info.width,
+ int.max(height, cached.info.height),
+ string_builder.append(svgs, image(cached.data, cached.info, width)),
+ )
+ _ -> images(image_cache, theme, rest, width, height, svgs)
}
}
}
-pub fn xml(theme, number, padding) {
+pub fn xml(image_cache, theme, number, padding) {
let xml =
images(
+ image_cache,
theme,
{
let assert Ok(digits) = int.digits(number, 10)