添加http返回类型枚举

This commit is contained in:
tursom 2019-12-15 01:52:06 +08:00
parent 85291d9f59
commit 1f9372ae68
6 changed files with 210 additions and 36 deletions

View File

@ -14,6 +14,7 @@ import cn.tursom.web.result.Text
import cn.tursom.web.router.impl.SimpleRouter
import cn.tursom.web.utils.Chunked
import cn.tursom.web.utils.ContextType
import cn.tursom.web.utils.NoReturnLog
import org.slf4j.LoggerFactory
import java.io.File
import java.io.RandomAccessFile
@ -55,7 +56,7 @@ open class RoutedHttpHandler(
}
override fun handle(content: HttpContent) {
log?.debug("{}: {} {}", content.clientIp, content.method, content.uri)
log?.debug("{} {} {}", content.clientIp, content.method, content.uri)
if (content is MutableHttpContent) {
handle(content, getHandler(content, content.method, content.uri))
} else {
@ -132,19 +133,20 @@ open class RoutedHttpHandler(
}
fun addRouter(obj: Any, method: Method, route: String, router: Router<Pair<Any?, (HttpContent) -> Any?>>) {
val doLog = method.doLog
router[safeRoute(route)] = obj to (if (method.parameterTypes.isEmpty()) {
when {
method.getAnnotation(Html::class.java) != null -> { content ->
method(obj)?.let { result -> finishHtml(result, content) }
method(obj)?.let { result -> finishHtml(result, content, doLog) }
}
method.getAnnotation(Text::class.java) != null -> { content ->
method(obj)?.let { result -> finishText(result, content) }
method(obj)?.let { result -> finishText(result, content, doLog) }
}
method.getAnnotation(Json::class.java) != null -> { content ->
method(obj)?.let { result -> finishJson(result, content) }
method(obj)?.let { result -> finishJson(result, content, doLog) }
}
else -> { content ->
method(obj)?.let { result -> autoReturn(method, result, content) }
method(obj)?.let { result -> autoReturn(method, result, content, doLog) }
}
}
} else when (method.returnType) {
@ -153,16 +155,16 @@ open class RoutedHttpHandler(
Unit::class.java -> { content -> method(obj, content) }
else -> when {
method.getAnnotation(Html::class.java) != null -> { content ->
method(obj, content)?.let { result -> finishHtml(result, content) }
method(obj, content)?.let { result -> finishHtml(result, content, doLog) }
}
method.getAnnotation(Text::class.java) != null -> { content ->
method(obj, content)?.let { result -> finishText(result, content) }
method(obj, content)?.let { result -> finishText(result, content, doLog) }
}
method.getAnnotation(Json::class.java) != null -> { content ->
method(obj, content)?.let { result -> finishJson(result, content) }
method(obj, content)?.let { result -> finishJson(result, content, doLog) }
}
else -> { content: HttpContent ->
method(obj, content)?.let { result -> autoReturn(method, result, content) }
method(obj, content)?.let { result -> autoReturn(method, result, content, doLog) }
}
}
}).let {
@ -273,6 +275,8 @@ open class RoutedHttpHandler(
null
}
val Method.doLog get() = getAnnotation(NoReturnLog::class.java) == null
fun <T> T.repeatUntil(state: (T) -> Boolean, block: (T) -> T): T {
var result = this
while (state(result)) {
@ -288,15 +292,16 @@ open class RoutedHttpHandler(
if (it.endsWith('/')) it.dropLast(1) else it
}.repeatUntil({ it.contains("//") }) { it.replace(slashRegex, "/") }
fun autoReturn(method: Method, result: Any?, content: HttpContent) {
fun autoReturn(method: Method, result: Any?, content: HttpContent, doLog: Boolean? = null) {
method.getAnnotation(ContextType::class.java)?.let {
content.autoContextType(it.type)
content.setContextType(it.type.value)
log?.debug("{}: autoReturn context type auto set to {}({})", content.clientIp, it.type.key, it.type.value)
}
autoReturn(result, content)
autoReturn(result, content, doLog ?: method.doLog)
}
fun autoReturn(result: Any?, content: HttpContent) {
log?.debug("{}: autoReturn: {}", content.clientIp, result)
fun autoReturn(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (doLog) log?.debug("{}: autoReturn: {}", content.clientIp, result)
result ?: return
when (result) {
is String -> content.finishText(result.toByteArray())
@ -315,8 +320,8 @@ open class RoutedHttpHandler(
}
}
fun finishHtml(result: Any?, content: HttpContent) {
log?.debug("{}: finishHtml: {}", content.clientIp, result)
fun finishHtml(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (doLog) log?.debug("{}: finishHtml: {}", content.clientIp, result)
result ?: return
when (result) {
is ByteBuffer -> content.finishHtml(result)
@ -332,8 +337,8 @@ open class RoutedHttpHandler(
}
}
fun finishText(result: Any?, content: HttpContent) {
log?.debug("{}: finishText: {}", content.clientIp, result)
fun finishText(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (doLog) log?.debug("{}: finishText: {}", content.clientIp, result)
result ?: return
when (result) {
is ByteBuffer -> content.finishText(result)
@ -349,8 +354,8 @@ open class RoutedHttpHandler(
}
}
fun finishJson(result: Any?, content: HttpContent) {
log?.debug("{}: finishJson: {}", content.clientIp, result)
fun finishJson(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (doLog) log?.debug("{}: finishJson: {}", content.clientIp, result)
result ?: return
when (result) {
is ByteBuffer -> content.finishJson(result)
@ -365,7 +370,7 @@ open class RoutedHttpHandler(
}
else -> {
val json = json?.toJson(result)
log?.debug("{}: finishJson: generate json: {}", content.clientIp, json)
if (doLog) log?.debug("{}: finishJson: generate json: {}", content.clientIp, json)
if (json != null) {
content.finishJson(json.toByteArray())
} else {

View File

@ -1,3 +1,3 @@
package cn.tursom.web.utils
annotation class ContextType(val type: String)
annotation class ContextType(val type: ContextTypeEnum)

View File

@ -0,0 +1,160 @@
package cn.tursom.web.utils
import cn.tursom.core.datastruct.StringRadixTree
@Suppress("EnumEntryName", "unused", "SpellCheckingInspection")
enum class ContextTypeEnum(val key: String, val value: String) {
aac("aac", "audio/aac"),
abw("abw", "application/x-abiword"),
arc("arc", "application/x-freearc"),
avi("avi", "video/x-msvideo"),
azw("azw", "aapplication/vnd.amazon.ebook"),
bin("bin", "application/octet-stream"),
bmp("bmp", "image/bmp"),
bz("bz", "application/x-bzip"),
bz2("bz2", "application/x-bzip2"),
csh("csh", "application/x-csh"),
css("css", "itext/css; charset=UTF-8"),
csv("csv", "itext/csv; charset=UTF-8"),
doc("doc", "application/msword"),
docx("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
eot("eot", "application/vnd.ms-fontobject"),
epub("epub", "application/epub+zip"),
gif("gif", "image/gif"),
html("html", "text/html; charset=UTF-8"),
htm("htm", "text/html; charset=UTF-8"),
ico("ico", "image/vnd.microsoft.icon"),
ics("ics", "text/calendar; charset=UTF-8"),
jar("jar", "application/java-archive"),
jpeg("jpeg", "image/jpeg"),
jpg("jpg", "image/jpeg"),
js("js", "text/javascript; charset=UTF-8"),
json("json", "application/json; charset=UTF-8"),
jsonld("jsonld", "application/ld+json"),
mid("mid", "audio/midi"),
midi("midi", "audio/midi"),
mjs("mjs", "text/javascript"),
mp3("mp3", "audio/mpeg"),
mp4("mp4", "audio/mp4"),
mpeg("mpeg", "video/mpeg"),
mpkg("mpkg", "application/vnd.apple.installer+xml"),
odp("odp", "application/vnd.oasis.opendocument.presentation"),
ods("ods", "application/vnd.oasis.opendocument.spreadsheet"),
odt("odt", "application/vnd.oasis.opendocument.text"),
oga("oga", "audio/ogg"),
ogg("ogg", "application/ogg"),
ogv("ogv", "video/ogg"),
ogx("ogx", "application/ogg"),
otf("otf", "font/otf"),
png("png", "image/png"),
pdf("pdf", "application/pdf"),
ppt("ppt", "application/vnd.ms-powerpoint"),
pptx("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"),
rar("rar", "application/x-rar-compressed"),
rtf("rtf", "application/rtf"),
sh("sh", "application/x-sh"),
svg("svg", "image/svg+xml"),
swf("swf", "application/x-shockwave-flash"),
tar("tar", "application/x-tar"),
tif("tif", "image/tiff"),
tiff("tiff", "image/tiff"),
ttf("ttf", "font/ttf"),
txt("txt", "text/plain; charset=UTF-8"),
vsd("vsd", "application/vnd.visio"),
wav("wav", "audio/wav"),
weba("weba", "audio/webm"),
webm("webm", "video/webm"),
webp("webp", "image/webp"),
woff("woff", "font/woff"),
woff2("woff2", "font/woff2"),
xhtml("xhtml", "application/xhtml+xml"),
xls("xls", "application/vnd.ms-excel"),
xlsx("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
xml("xml", "text/xml; charset=UTF-8"),
xul("xul", "application/vnd.mozilla.xul+xml"),
zip("zip", "application/zip"),
`3gp`("3gp", "video/3gpp"),
`3g2`("3g2", "ivideo/3gpp2"),
`7z`("7z", "application/x-7z-compressed");
companion object {
private val router = StringRadixTree<ContextTypeEnum>()
init {
router["aac"] = aac
router["abw"] = abw
router["arc"] = arc
router["avi"] = avi
router["azw"] = azw
router["bin"] = bin
router["bmp"] = bmp
router["bz"] = bz
router["bz2"] = bz2
router["csh"] = csh
router["css"] = css
router["csv"] = csv
router["doc"] = doc
router["docx"] = docx
router["eot"] = eot
router["epub"] = epub
router["gif"] = gif
router["html"] = html
router["htm"] = htm
router["ico"] = ico
router["ics"] = ics
router["jar"] = jar
router["jpeg"] = jpeg
router["jpg"] = jpg
router["js"] = js
router["json"] = json
router["jsonld"] = jsonld
router["mid"] = mid
router["midi"] = midi
router["mjs"] = mjs
router["mp3"] = mp3
router["mp4"] = mp4
router["mpeg"] = mpeg
router["mpkg"] = mpkg
router["odp"] = odp
router["ods"] = ods
router["odt"] = odt
router["oga"] = oga
router["ogg"] = ogg
router["ogv"] = ogv
router["ogx"] = ogx
router["otf"] = otf
router["png"] = png
router["pdf"] = pdf
router["ppt"] = ppt
router["pptx"] = pptx
router["rar"] = rar
router["rtf"] = rtf
router["sh"] = sh
router["svg"] = svg
router["swf"] = swf
router["tar"] = tar
router["tif"] = tif
router["tiff"] = tiff
router["ttf"] = ttf
router["txt"] = txt
router["vsd"] = vsd
router["wav"] = wav
router["weba"] = weba
router["webm"] = webm
router["webp"] = webp
router["woff"] = woff
router["woff2"] = woff2
router["xhtml"] = xhtml
router["xls"] = xls
router["xlsx"] = xlsx
router["xml"] = xml
router["xul"] = xul
router["zip"] = zip
router["3gp"] = `3gp`
router["3g2"] = `3g2`
router["7z"] = `7z`
}
operator fun get(value: String) = router[value] ?: throw IllegalAccessException()
}
}

View File

@ -81,3 +81,5 @@ object ContextTypeMap {
router["7z"] = "application/x-7z-compressed"
}
}

View File

@ -0,0 +1,3 @@
package cn.tursom.web.utils
annotation class NoReturnLog

View File

@ -8,10 +8,10 @@ import cn.tursom.web.result.Json
import cn.tursom.web.result.Text
import cn.tursom.web.router.impl.SimpleRouter
import cn.tursom.web.utils.ContextType
import cn.tursom.web.utils.NoReturnLog
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.slf4j.LoggerFactory
import java.lang.reflect.Method
import kotlin.reflect.KCallable
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.jvm.jvmErasure
@ -26,7 +26,7 @@ open class AsyncRoutedHttpHandler(
protected val asyncRouterMap: HashMap<String, Router<Pair<Any?, suspend (HttpContent) -> Unit>>> = HashMap()
override fun handle(content: HttpContent) {
log?.debug("{}: {} {}", content.clientIp, content.method, content.uri)
log?.debug("{} {} {}", content.clientIp, content.method, content.uri)
if (content is MutableHttpContent) {
val handler = getAsyncHandler(content, content.method, content.uri)
if (handler != null) GlobalScope.launch {
@ -103,19 +103,20 @@ open class AsyncRoutedHttpHandler(
@Suppress("UNCHECKED_CAST")
fun addRouter(obj: Any, method: KCallable<*>, route: String, router: Router<Pair<Any?, suspend (HttpContent) -> Unit>>) {
val doLog = method.doLog
router[safeRoute(route)] = if (method.parameters.size == 1) {
obj to when {
method.findAnnotation<Html>() != null -> { content ->
(method as suspend Any.() -> Any?)(obj)?.let { result -> finishHtml(result, content) }
(method as suspend Any.() -> Any?)(obj)?.let { result -> finishHtml(result, content, doLog) }
}
method.findAnnotation<Text>() != null -> { content ->
(method as suspend Any.() -> Any?)(obj)?.let { result -> finishText(result, content) }
(method as suspend Any.() -> Any?)(obj)?.let { result -> finishText(result, content, doLog) }
}
method.findAnnotation<Json>() != null -> { content ->
(method as suspend Any.() -> Any?)(obj)?.let { result -> finishJson(result, content) }
(method as suspend Any.() -> Any?)(obj)?.let { result -> finishJson(result, content, doLog) }
}
else -> { content ->
(method as suspend Any.() -> Any?)(obj)?.let { result -> autoReturn(method, result, content) }
(method as suspend Any.() -> Any?)(obj)?.let { result -> autoReturn(method, result, content, doLog) }
}
}
} else obj to when (method.returnType.jvmErasure.java) {
@ -124,16 +125,16 @@ open class AsyncRoutedHttpHandler(
Unit::class.java -> { content -> (method as suspend Any.(HttpContent) -> Unit)(obj, content) }
else -> when {
method.findAnnotation<Html>() != null -> { content ->
(method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishHtml(result, content) }
(method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishHtml(result, content, doLog) }
}
method.findAnnotation<Text>() != null -> { content ->
(method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishText(result, content) }
(method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishText(result, content, doLog) }
}
method.findAnnotation<Json>() != null -> { content ->
(method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishJson(result, content) }
(method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishJson(result, content, doLog) }
}
else -> { content ->
(method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> autoReturn(method, result, content) }
(method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> autoReturn(method, result, content, doLog) }
}
}
}
@ -229,11 +230,14 @@ open class AsyncRoutedHttpHandler(
null
}
fun autoReturn(method: KCallable<*>, result: Any?, content: HttpContent) {
val KCallable<*>.doLog get() = findAnnotation<NoReturnLog>() == null
fun autoReturn(method: KCallable<*>, result: Any?, content: HttpContent, doLog: Boolean? = null) {
method.findAnnotation<ContextType>()?.let {
content.autoContextType(it.type)
content.setContextType(it.type.value)
log?.debug("{}: autoReturn context type auto set to {}({})", content.clientIp, it.type.key, it.type.value)
}
autoReturn(result, content)
autoReturn(result, content, doLog ?: method.doLog)
}
}
}