Allow caching of factbook assets
authorLanius Trolling <lanius@laniustrolling.dev>
Fri, 21 Jul 2023 17:49:59 +0000 (13:49 -0400)
committerLanius Trolling <lanius@laniustrolling.dev>
Fri, 21 Jul 2023 17:49:59 +0000 (13:49 -0400)
build.gradle.kts
src/main/kotlin/info/mechyrdia/Factbooks.kt
src/main/kotlin/info/mechyrdia/lore/view_tpl.kt

index 88c681e0c96c6619db767f21ef6542cfaede89cc..0bf1ce059438c66926bf48f83a93268619694273 100644 (file)
@@ -47,8 +47,10 @@ dependencies {
        implementation("io.ktor:ktor-server-core-jvm:2.3.2")
        implementation("io.ktor:ktor-server-netty-jvm:2.3.2")
        
+       implementation("io.ktor:ktor-server-caching-headers:2.3.2")
        implementation("io.ktor:ktor-server-call-id:2.3.2")
        implementation("io.ktor:ktor-server-call-logging:2.3.2")
+       implementation("io.ktor:ktor-server-conditional-headers:2.3.2")
        implementation("io.ktor:ktor-server-forwarded-header:2.3.2")
        implementation("io.ktor:ktor-server-html-builder:2.3.2")
        implementation("io.ktor:ktor-server-sessions-jvm:2.3.2")
@@ -72,6 +74,8 @@ dependencies {
        
        implementation("org.slf4j:slf4j-api:2.0.7")
        implementation("ch.qos.logback:logback-classic:1.4.7")
+       implementation("io.ktor:ktor-server-conditional-headers-jvm:2.3.2")
+       implementation("io.ktor:ktor-server-caching-headers-jvm:2.3.2")
 }
 
 java {
index 6203e3339b57e31d6beb625b91f227123f6133ce..cd73f1b5d9e17511c10adf8baf1e6dfcd7261b7e 100644 (file)
@@ -6,14 +6,17 @@ import info.mechyrdia.auth.*
 import info.mechyrdia.data.*
 import info.mechyrdia.lore.*
 import io.ktor.http.*
+import io.ktor.http.content.*
 import io.ktor.server.application.*
 import io.ktor.server.engine.*
 import io.ktor.server.html.*
 import io.ktor.server.http.content.*
 import io.ktor.server.netty.*
 import io.ktor.server.plugins.*
+import io.ktor.server.plugins.cachingheaders.*
 import io.ktor.server.plugins.callid.*
 import io.ktor.server.plugins.callloging.*
+import io.ktor.server.plugins.conditionalheaders.*
 import io.ktor.server.plugins.forwardedheaders.*
 import io.ktor.server.plugins.statuspages.*
 import io.ktor.server.request.*
@@ -45,6 +48,24 @@ fun Application.factbooks() {
        install(IgnoreTrailingSlash)
        install(XForwardedHeaders)
        
+       install(CachingHeaders) {
+               options { _, outgoingContent ->
+                       if (outgoingContent is JarFileContent)
+                               CachingOptions(CacheControl.MaxAge(maxAgeSeconds = 3600))
+                       else
+                               null
+               }
+       }
+       
+       install(ConditionalHeaders) {
+               version { _, outgoingContent ->
+                       if (outgoingContent is LocalFileContent)
+                               listOf(LastModifiedVersion(outgoingContent.file.lastModified()))
+                       else
+                               emptyList()
+               }
+       }
+       
        install(CallId) {
                val counter = AtomicLong(0)
                generate {
@@ -115,13 +136,16 @@ fun Application.factbooks() {
                
                staticResources("/static", "static", index = null) {
                        preCompressed(CompressedFileType.BROTLI, CompressedFileType.GZIP)
+                       enableAutoHeadResponse()
                }
                
                get("/lore/{path...}") {
                        call.respondHtml(HttpStatusCode.OK, call.loreArticlePage())
                }
                
-               staticFiles("/assets", File(Configuration.CurrentConfiguration.assetDir), index = null)
+               staticFiles("/assets", File(Configuration.CurrentConfiguration.assetDir), index = null) {
+                       enableAutoHeadResponse()
+               }
                
                // Client settings
                
index cecf7f3d56aee906bd37b97e4e141d96e1c5bdba..c1e58095aedeb62eab642fbb15f4f2ebe2b0008a 100644 (file)
@@ -6,6 +6,36 @@ import io.ktor.server.request.*
 import io.ktor.util.*
 import kotlinx.html.*
 
+private val fonts = listOf(
+       "DejaVuSans-Bold.woff",
+       "DejaVuSans-BoldOblique.woff",
+       "DejaVuSans-Oblique.woff",
+       "DejaVuSans.woff",
+       "JetBrainsMono-ExtraBold.woff",
+       "JetBrainsMono-ExtraBoldItalic.woff",
+       "JetBrainsMono-Medium.woff",
+       "JetBrainsMono-MediumItalic.woff",
+       "NotoSans-Black.woff",
+       "NotoSans-BlackItalic.woff",
+       "NotoSans-Medium.woff",
+       "NotoSans-MediumItalic.woff",
+       "NotoSansGothic-Regular.woff",
+       "Oxanium-Bold.woff",
+       "Oxanium-ExtraBold.woff",
+       "Oxanium-Regular.woff",
+       "Oxanium-SemiBold.woff",
+       "thedish-language-alphabet.woff",
+       "tylan-language-alphabet-3.woff",
+)
+
+private val images = listOf(
+       "external-link-dark.png",
+       "external-link.png",
+       "icon.png",
+       "panel-dark.png",
+       "panel.png",
+)
+
 fun ApplicationCall.page(pageTitle: String, navBar: List<NavItem>? = null, sidebar: Sidebar? = null, content: SECTIONS.() -> Unit): HTML.() -> Unit {
        val theme = request.cookies["FACTBOOK_THEME"]
        
@@ -26,6 +56,26 @@ fun ApplicationCall.page(pageTitle: String, navBar: List<NavItem>? = null, sideb
                        
                        link(rel = "icon", type = "image/svg+xml", href = "/static/images/icon.png")
                        
+                       for (font in fonts)
+                               link(
+                                       rel = "preload",
+                                       href = "/static/font/$font",
+                                       type = "font/woff"
+                               ) {
+                                       attributes["as"] = "font"
+                                       attributes["crossorigin"] = "anonymous"
+                               }
+                       
+                       for (image in images)
+                               link(
+                                       rel = "preload",
+                                       href = "/static/images/$image",
+                                       type = "image/png"
+                               ) {
+                                       attributes["as"] = "image"
+                                       attributes["crossorigin"] = "anonymous"
+                               }
+                       
                        link(rel = "stylesheet", href = "/static/style.css")
                        
                        request.queryParameters["redirect"]?.let { redirect ->