All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commands.BakuCommandResponseFeature.kt Maven / Gradle / Ivy

package com.github.fluidsonic.baku

import com.github.fluidsonic.fluid.json.*
import io.ktor.application.ApplicationCallPipeline
import io.ktor.application.ApplicationFeature
import io.ktor.application.call
import io.ktor.client.utils.CacheControl
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.content.OutgoingContent
import io.ktor.http.content.TextContent
import io.ktor.http.withCharset
import io.ktor.response.ApplicationSendPipeline
import io.ktor.response.header
import io.ktor.util.AttributeKey
import java.io.StringWriter


internal class BakuCommandResponseFeature(
	private val additionalEncodings: List.() -> Unit>,
	private val codecProvider: JSONCodecProvider,
	private val entityResolver: EntityResolver
) : ApplicationFeature {

	override val key = AttributeKey("Baku: command response feature")


	@Suppress("UNCHECKED_CAST")
	override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit) {
		Unit.configure()

		pipeline.sendPipeline.intercept(ApplicationSendPipeline.Render) { subject ->
			subject !is OutgoingContent
				|| return@intercept

			val response = subject as? BakuCommandResponse
				?: throw BakuCommandFailure(code = "fixme", developerMessage = "FIXME", userMessage = BakuCommandFailure.genericUserMessage) // FIXME

			call.response.header(HttpHeaders.CacheControl, CacheControl.NO_CACHE)

			proceedWith(serializeCommandResponse(
				response = response,
				transaction = transaction as Transaction
			))
		}
	}


	private suspend fun serializeCommandResponse(
		response: BakuCommandResponse,
		transaction: Transaction
	): OutgoingContent {
		@Suppress("UNCHECKED_CAST")
		val factory = response.factory as BakuCommandFactory
		val writer = StringWriter()

		BakuEntityResolvingJSONEncoder(
			codecProvider = codecProvider,
			context = transaction,
			entityResolver = entityResolver,
			writer = writer
		).apply {
			writeMapStart()

			additionalEncodings.forEach { it() }

			writeMapElement("result") {
				try {
					factory.run { encodeResult(response.result) }
				}
				catch (e: JSONException) {
					e.addSuppressed(JSONException.Serialization("… when encoding result of command '${factory.name}' using ${factory::class.qualifiedName}"))
					throw e
				}
			}

			writeMapKey("entities")
			writeEntities()

			writeMapElement("status", string = "success")

			writeMapEnd()
		}

		return TextContent(
			text = writer.toString(),
			contentType = ContentType.Application.Json.withCharset(Charsets.UTF_8),
			status = null
		)
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy