Skip to content

Instantly share code, notes, and snippets.

@yusukezzz
Created May 24, 2021 16:02
Show Gist options
  • Save yusukezzz/5ad8011297d85e3580fdae87bf447e16 to your computer and use it in GitHub Desktop.
Save yusukezzz/5ad8011297d85e3580fdae87bf447e16 to your computer and use it in GitHub Desktop.
Jte feature for ktor
package net.yusukezzz
import gg.jte.CodeResolver
import gg.jte.TemplateEngine
import gg.jte.output.WriterOutput
import gg.jte.resolve.DirectoryCodeResolver
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.response.*
import io.ktor.util.*
import io.ktor.util.cio.*
import io.ktor.utils.io.*
import java.nio.file.*
import gg.jte.ContentType as JteContentType
class JteContent(
val template: String,
val data: Any?,
val contentType: ContentType = ContentType.Text.Html.withCharset(Charsets.UTF_8)
)
suspend fun ApplicationCall.respondTemplate(
template: String,
data: Any? = null,
contentType: ContentType = ContentType.Text.Html.withCharset(Charsets.UTF_8)
): Unit = respond(JteContent(template, data, contentType))
class Jte(config: Configuration) {
private val extention: String = ".jte"
private val engine: TemplateEngine =
TemplateEngine.create(config.resolver, config.contentType)
class Configuration {
var resolver: CodeResolver =
DirectoryCodeResolver(Paths.get(ClassLoader.getSystemResource("jte").toURI()))
var contentType: JteContentType = JteContentType.Html
}
companion object Feature : ApplicationFeature<ApplicationCallPipeline, Configuration, Jte> {
override val key: AttributeKey<Jte> = AttributeKey<Jte>("Jte")
override fun install(pipeline: ApplicationCallPipeline, configure: Configuration.() -> Unit): Jte {
val configuration = Configuration().apply(configure)
val feature = Jte(configuration)
pipeline.sendPipeline.intercept(ApplicationSendPipeline.Transform) { value ->
if (value is JteContent) {
val response = feature.process(value)
proceedWith(response)
}
}
return feature
}
}
private fun process(content: JteContent): JteOutgoingContent {
return JteOutgoingContent(
engine,
resolveExtension(content.template),
content.data,
content.contentType
)
}
private fun resolveExtension(template: String): String {
return if (template.endsWith(extention)) {
template
} else {
template + extention
}
}
private class JteOutgoingContent(
val engine: TemplateEngine,
val template: String,
val data: Any?,
override val contentType: ContentType
) : OutgoingContent.WriteChannelContent() {
override suspend fun writeTo(channel: ByteWriteChannel) {
channel.bufferedWriter(contentType.charset() ?: Charsets.UTF_8).use {
engine.render(template, data, WriterOutput(it))
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment