diff --git a/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt b/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt index 935c229..a399fe9 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt +++ b/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt @@ -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 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.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 { diff --git a/web/src/main/kotlin/cn/tursom/web/utils/ContextType.kt b/web/src/main/kotlin/cn/tursom/web/utils/ContextType.kt index 2dcb696..29a4757 100644 --- a/web/src/main/kotlin/cn/tursom/web/utils/ContextType.kt +++ b/web/src/main/kotlin/cn/tursom/web/utils/ContextType.kt @@ -1,3 +1,3 @@ package cn.tursom.web.utils -annotation class ContextType(val type: String) \ No newline at end of file +annotation class ContextType(val type: ContextTypeEnum) \ No newline at end of file diff --git a/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeEnum.kt b/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeEnum.kt new file mode 100644 index 0000000..db5cc60 --- /dev/null +++ b/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeEnum.kt @@ -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() + + 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() + } +} diff --git a/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeMap.kt b/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeMap.kt index d2e2ef7..e5525f0 100644 --- a/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeMap.kt +++ b/web/src/main/kotlin/cn/tursom/web/utils/ContextTypeMap.kt @@ -80,4 +80,6 @@ object ContextTypeMap { router["3g2"] = "ivideo/3gpp2" router["7z"] = "application/x-7z-compressed" } -} \ No newline at end of file +} + + diff --git a/web/src/main/kotlin/cn/tursom/web/utils/NoReturnLog.kt b/web/src/main/kotlin/cn/tursom/web/utils/NoReturnLog.kt new file mode 100644 index 0000000..2621866 --- /dev/null +++ b/web/src/main/kotlin/cn/tursom/web/utils/NoReturnLog.kt @@ -0,0 +1,3 @@ +package cn.tursom.web.utils + +annotation class NoReturnLog \ No newline at end of file diff --git a/web/web-coroutine/src/main/kotlin/cn/tursom/web/router/AsyncRoutedHttpHandler.kt b/web/web-coroutine/src/main/kotlin/cn/tursom/web/router/AsyncRoutedHttpHandler.kt index 16c2904..5048872 100644 --- a/web/web-coroutine/src/main/kotlin/cn/tursom/web/router/AsyncRoutedHttpHandler.kt +++ b/web/web-coroutine/src/main/kotlin/cn/tursom/web/router/AsyncRoutedHttpHandler.kt @@ -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 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 Unit>>) { + val doLog = method.doLog router[safeRoute(route)] = if (method.parameters.size == 1) { obj to when { method.findAnnotation() != 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() != 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() != 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() != 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() != 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() != 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() == null + + fun autoReturn(method: KCallable<*>, result: Any?, content: HttpContent, doLog: Boolean? = null) { method.findAnnotation()?.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) } } } \ No newline at end of file