diff --git a/utils/src/main/kotlin/cn/tursom/web/router/suspend/ISuspendRouter.kt b/utils/src/main/kotlin/cn/tursom/web/router/suspend/ISuspendRouter.kt deleted file mode 100644 index e74384b..0000000 --- a/utils/src/main/kotlin/cn/tursom/web/router/suspend/ISuspendRouter.kt +++ /dev/null @@ -1,14 +0,0 @@ -package cn.tursom.web.router.suspend - -interface ISuspendRouter { - suspend fun setSubRoute(route: String, value: T?, onDestroy: ((oldValue: T) -> Unit)? = null) - suspend fun delRoute(route: String, onDestroy: ((oldValue: T) -> Unit)? = null) - - suspend fun set( - route: String, - onDestroy: ((oldValue: T) -> Unit)? = null, - value: T? - ) = setSubRoute(route, value, onDestroy) - - suspend fun get(route: String): Pair>> -} \ No newline at end of file diff --git a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/SuspendColonStarRouter.kt b/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/SuspendColonStarRouter.kt deleted file mode 100644 index 4f83dd1..0000000 --- a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/SuspendColonStarRouter.kt +++ /dev/null @@ -1,145 +0,0 @@ -package cn.tursom.web.router.suspend.impl - -import cn.tursom.web.router.suspend.ISuspendRouter -import cn.tursom.web.router.suspend.impl.node.ISuspendColonStarNode -import cn.tursom.web.router.suspend.impl.node.SuspendAnyColonStarNode -import cn.tursom.web.router.suspend.impl.node.SuspendPlaceholderColonStarNode -import kotlinx.coroutines.runBlocking -import java.util.concurrent.Executors - -@Suppress("unused", "unused", "MemberVisibilityCanBePrivate", "UNUSED_PARAMETER") -class SuspendColonStarRouter : ISuspendRouter { - private val rootNode = cn.tursom.web.router.suspend.impl.node.SuspendColonStarNode(listOf(""), 0, null) - private val threadPool = Executors.newSingleThreadExecutor() - - @Volatile - private var _lastChangeTime: Long = System.currentTimeMillis() - val lashChangeTime - get() = _lastChangeTime - @Volatile - private var strBuf: String = "" - @Volatile - private var strBufTime: Long = 0 - - val root: ISuspendColonStarNode = rootNode - - override suspend fun setSubRoute( - route: String, - value: T?, - onDestroy: ((oldValue: T) -> Unit)? - ) { - val routeList = route.split('?')[0].split('/').filter { it.isNotEmpty() } - var routeNode = rootNode - var r: String - var index = 0 - while (index < routeList.size) { - r = routeList[index] - routeNode = when { - r.isEmpty() -> routeNode - - r == "*" -> routeNode.wildSubRouter ?: run { - val node = SuspendAnyColonStarNode(routeList, index, null) - routeNode.wildSubRouter = node - index = routeList.size - 1 - node - } - - r[0] == ':' -> { - val matchLength = SuspendPlaceholderColonStarNode.matchLength(routeList, index) - val node = routeNode.getPlaceholderRouter(matchLength) ?: suspend { - routeNode.addNode(routeList, index, null) - routeNode.getPlaceholderRouter(matchLength)!! - }() - index += node.size - 1 - node - } - - else -> routeNode.subRouterMap[r] ?: { - val node = cn.tursom.web.router.suspend.impl.node.SuspendColonStarNode(routeList, index, null) - routeNode.subRouterMap[r] = node - node - }() - } - index++ - } - val oldValue = routeNode.value - if (oldValue != null) onDestroy?.invoke(oldValue) - routeNode.value = value - routeNode.routeList = routeList - routeNode.index = index - 1 - _lastChangeTime = System.currentTimeMillis() - } - - override suspend fun delRoute(route: String, onDestroy: ((oldValue: T) -> Unit)?) { - this.set(route, null, onDestroy) - } - - suspend fun set( - route: String, - value: T?, - onDestroy: ((oldValue: T) -> Unit)? = null - ) = setSubRoute(route, value, onDestroy) - - override suspend fun get(route: String): Pair>> { - val list = ArrayList>() - val endIndex = route.indexOf('?') - return rootNode.get( - (if (endIndex < 0) route else route.substring(0, endIndex)) - .split('/').filter { it.isNotEmpty() }, - list - )?.value to list - } - - private suspend fun toString(node: cn.tursom.web.router.suspend.impl.node.SuspendColonStarNode, stringBuilder: StringBuilder, indentation: String) { - if ( - node.value == null && - node.subRouterMap.isEmpty() && - node.placeholderRouterListEmpty && - node.wildSubRouter == null - ) { - return - } - - if (indentation.isNotEmpty()) { - stringBuilder.append(indentation) - stringBuilder.append("- ") - } - stringBuilder.append("${node.lastRoute}${if (node.value != null) " ${node.value}" else ""}\n") - - if (node is SuspendAnyColonStarNode) return - - val subIndentation = if (indentation.isEmpty()) "|" else "$indentation |" - - node.subRouterMap.forEach { (_, u) -> - toString(u, stringBuilder, subIndentation) - } - node.forEachPlaceholderRouter { - toString(it, stringBuilder, subIndentation) - } - toString(node.wildSubRouter ?: return, stringBuilder, subIndentation) - return - } - - suspend fun suspendToString(): String { - if (strBufTime < _lastChangeTime) { - val stringBuilder = StringBuilder() - toString(rootNode, stringBuilder, "") - strBuf = stringBuilder.toString() - strBufTime = System.currentTimeMillis() - } - return strBuf - } - - override fun toString(): String { - if (strBufTime < _lastChangeTime) { - val stringBuilder = StringBuilder() - runBlocking { - toString(rootNode, stringBuilder, "") - } - strBuf = stringBuilder.toString() - strBufTime = System.currentTimeMillis() - } - return strBuf - } -} - diff --git a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/ISuspendColonStarNode.kt b/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/ISuspendColonStarNode.kt deleted file mode 100644 index 7033aba..0000000 --- a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/ISuspendColonStarNode.kt +++ /dev/null @@ -1,10 +0,0 @@ -package cn.tursom.web.router.suspend.impl.node - -interface ISuspendColonStarNode { - val value: T? - val lastRoute: String - val fullRoute: String - val empty: Boolean - - suspend fun forEach(action: suspend (node: ISuspendColonStarNode) -> Unit) -} \ No newline at end of file diff --git a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/SuspendAnyColonStarNode.kt b/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/SuspendAnyColonStarNode.kt deleted file mode 100644 index bd83a7a..0000000 --- a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/SuspendAnyColonStarNode.kt +++ /dev/null @@ -1,13 +0,0 @@ -package cn.tursom.web.router.suspend.impl.node - -import java.util.AbstractList - -internal class SuspendAnyColonStarNode( - route: List, - index: Int, - value: T? = null -) : SuspendColonStarNode(route, index, value) { - private val subNode = this to 1 - override fun match(route: List, startIndex: Int) = true to 1 - override suspend fun get(route: List, startIndex: Int, routeList: AbstractList>) = subNode -} \ No newline at end of file diff --git a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/SuspendColonStarNode.kt b/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/SuspendColonStarNode.kt deleted file mode 100644 index 88d72c6..0000000 --- a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/SuspendColonStarNode.kt +++ /dev/null @@ -1,223 +0,0 @@ -package cn.tursom.web.router.suspend.impl.node - -import cn.tursom.utils.asynclock.AsyncReadFirstRWLock -import cn.tursom.core.binarySearch - -@Suppress("MemberVisibilityCanBePrivate") -internal open class SuspendColonStarNode( - var routeList: List, - var index: Int, - override var value: T? = null -) : ISuspendColonStarNode { - val route: String = routeList[index] - var wildSubRouter: SuspendAnyColonStarNode? = null - - private val placeholderRouterListLock = AsyncReadFirstRWLock() - protected open val placeholderRouterList: ArrayList>? = ArrayList(0) - - private val subRouterMapLock = AsyncReadFirstRWLock() - val subRouterMap = HashMap>(0) - - override val lastRoute - get() = "/$route" - - override val fullRoute: String by lazy { - val stringBuilder = StringBuilder("") - for (i in 0..index) { - val s = routeList[i] - if (s.isNotEmpty()) stringBuilder.append("/$s") - } - stringBuilder.toString() - } - - val placeholderRouterListEmpty - get() = placeholderRouterList?.isEmpty() ?: true - - override val empty: Boolean - get() = value == null && - subRouterMap.isEmpty() && - placeholderRouterListEmpty && - wildSubRouter == null - - override suspend fun forEach(action: suspend (node: ISuspendColonStarNode) -> Unit) { - placeholderRouterListLock.doRead { - placeholderRouterList?.forEach { action(it) } - } - subRouterMapLock.doRead { - subRouterMap.forEach { (_, u) -> action(u) } - } - wildSubRouter?.let { action(it) } - } - - suspend fun forEachPlaceholderRouter(block: suspend (SuspendPlaceholderColonStarNode) -> Unit) { - placeholderRouterListLock.doRead { placeholderRouterList?.forEach { block(it) } } - } - - suspend fun getPlaceholderRouter(length: Int): SuspendPlaceholderColonStarNode? { - return placeholderRouterListLock.doRead { placeholderRouterList!!.binarySearch { it.size - length } } - } - - open fun match( - route: List, - startIndex: Int - ): Pair = (route.size > startIndex && route[startIndex] == this.route) to 1 - - suspend fun addNode(route: List, startIndex: Int, value: T? = null): Int { - val r = route[startIndex] - return when { - r.isEmpty() -> return addNode(route, startIndex + 1) - r == "*" -> { - wildSubRouter = SuspendAnyColonStarNode(route, startIndex, null) - 1 - } - r[0] == ':' -> { - val node: SuspendPlaceholderColonStarNode = SuspendPlaceholderColonStarNode( - route, - startIndex, - value = value - ) - // 必须保证 placeholderRouterList 存在,而且还不能有这个长度的节点 - if (placeholderRouterListLock.doRead { placeholderRouterList!!.binarySearch { it.size - node.size } } != null) { - throw Exception() - } - placeholderRouterListLock.doWrite { - placeholderRouterList?.add(node) - placeholderRouterList?.sortBy { it.size } - } - node.size - } - else -> { - subRouterMap[r] = SuspendColonStarNode(route, startIndex, value) - 1 - } - } - } - - operator fun get(route: List, startIndex: Int = 0): Pair?, Int> { - val r = route[startIndex] - if (r.isEmpty()) return this to 1 - - val value = subRouterMap[r] - if (value != null) return value to 1 - - val matchLength = route.size - startIndex - val exactRoute = placeholderRouterList?.let { list -> - list.binarySearch { matchLength - it.size } - } - if (exactRoute != null) return exactRoute to matchLength - - placeholderRouterList?.let { list -> - list.forEach { - val subRoute = it.getRoute(route, startIndex + it.size) - if (subRoute != null) return subRoute to route.size - startIndex - } - } - - return wildSubRouter to 1 - } - - fun getRoute(route: List, startIndex: Int = 0): cn.tursom.web.router.suspend.impl.node.SuspendColonStarNode? { - var index = startIndex - var routeNode = this - while (index < route.size) { - val (node, size) = routeNode[route, index] - routeNode = node ?: return null - index += size - } - return routeNode - } - - open suspend fun get( - route: List, - startIndex: Int = 0, - routeList: java.util.AbstractList> - ): Pair?, Int> { - val r = route[startIndex] - if (r.isEmpty()) { - return this to 1 - } - - val value = subRouterMapLock.doRead { subRouterMap[r] } - if (value != null) return value to 1 - - val matchLength = route.size - startIndex - val exactRoute = placeholderRouterListLock.doRead { - placeholderRouterList?.binarySearch { matchLength - it.size } - } - if (exactRoute != null) { - exactRoute.routeList.forEachIndexed { index, s -> - if (s.isNotEmpty() && s[0] == ':') routeList.add(s.substring(1) to route[index]) - } - return exactRoute to matchLength - } - - if (placeholderRouterList != null) { - val list = ArrayList>() - val detected = placeholderRouterListLock.doRead { - placeholderRouterList?.let { routerList -> - routerList.forEach { - list.clear() - val subRoute = it.getRoute(route, startIndex + it.size, list) - if (subRoute != null) { - subRoute.routeList.forEachIndexed { index, s -> - if (s.isNotEmpty()) when { - s == "*" -> for (i in index until route.size) { - routeList.add("*" to route[i]) - } - s[0] == ':' -> routeList.add(s.substring(1) to route[index]) - } - } - var listIndex = 0 - var routeIndex = 0 - while (listIndex < list.size && routeIndex <= index) { - val s = this.routeList[routeIndex++] - if (s.isNotEmpty() && s[0] == ':') { - routeList.add(s to list[listIndex++].second) - } - } - return@doRead subRoute to route.size - startIndex - } - } - } - null - } - if (detected != null) return detected - } - - for (i in startIndex until route.size) - routeList.add("*" to route[i]) - return wildSubRouter to 1 - } - - suspend fun get( - route: List, - routeList: java.util.AbstractList> - ) = getRoute(route, 0, routeList) - - suspend fun getRoute( - route: List, - startIndex: Int = 0, - routeList: java.util.AbstractList> - ): cn.tursom.web.router.suspend.impl.node.SuspendColonStarNode? { - var index = startIndex - var routeNode = this - while (index < route.size) { - val (node, size) = routeNode.get(route, index, routeList) - routeNode = node ?: return null - index += size - } - return routeNode - } - - override fun toString(): String { - val stringBuilder = StringBuilder("/") - for (i in 0..index) { - val s = routeList[i] - if (s.isNotEmpty()) stringBuilder.append("$s/") - } - if (value != null) { - stringBuilder.append(" $value") - } - return stringBuilder.toString() - } -} \ No newline at end of file diff --git a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/SuspendPlaceholderColonStarNode.kt b/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/SuspendPlaceholderColonStarNode.kt deleted file mode 100644 index 630cf07..0000000 --- a/utils/src/main/kotlin/cn/tursom/web/router/suspend/impl/node/SuspendPlaceholderColonStarNode.kt +++ /dev/null @@ -1,53 +0,0 @@ -package cn.tursom.web.router.suspend.impl.node - -internal class SuspendPlaceholderColonStarNode( - route: List, - private val startIndex: Int = 0, - endIndex: Int = startIndex + route.matchLength(startIndex), - value: T? = null -) : SuspendColonStarNode(route, endIndex - 1, value) { - override val placeholderRouterList: ArrayList>? - get() = null - - val size: Int = route.matchLength(startIndex, endIndex) - - override fun match( - route: List, - startIndex: Int - ): Pair = - (size == route.matchLength(startIndex)) to size - - override val lastRoute: String - get() { - val sb = StringBuilder() - for (i in startIndex..index) { - sb.append("/") - sb.append(routeList[i]) - } - return sb.toString() - } - - companion object { - @JvmStatic - private fun List.matchLength(startIndex: Int, endIndex: Int = size): Int { - var length = 0 - for (i in startIndex until endIndex) { - if (this[i].isEmpty()) continue - else if (this[i][0] != ':') return length - else length++ - } - return length - } - - @JvmStatic - fun matchLength(route: List, startIndex: Int): Int { - var length = 0 - for (i in startIndex until route.size) { - if (route[i].isEmpty()) continue - else if (route[i][0] != ':') return length - else length++ - } - return length - } - } -} \ No newline at end of file diff --git a/web/src/main/kotlin/cn/tursom/web/router/BlockHandler.kt b/web/src/main/kotlin/cn/tursom/web/router/BlockHandler.kt new file mode 100644 index 0000000..a38f3b5 --- /dev/null +++ b/web/src/main/kotlin/cn/tursom/web/router/BlockHandler.kt @@ -0,0 +1,3 @@ +package cn.tursom.web.router + +annotation class BlockHandler \ No newline at end of file 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 2796a85..935c229 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt +++ b/web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt @@ -13,10 +13,16 @@ import cn.tursom.web.result.Json 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 org.slf4j.LoggerFactory import java.io.File import java.io.RandomAccessFile import java.lang.reflect.Method +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.ThreadFactory +import java.util.concurrent.ThreadPoolExecutor +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicInteger /** * 自动添加路径映射的处理器 @@ -28,10 +34,20 @@ import java.lang.reflect.Method @Suppress("MemberVisibilityCanBePrivate", "unused") open class RoutedHttpHandler( target: Any? = null, - val routerMaker: () -> Router Unit>> = { SimpleRouter() } + val routerMaker: () -> Router Any?>> = { SimpleRouter() } ) : HttpHandler { - protected val router: Router Unit>> = routerMaker() - protected val routerMap: HashMap Unit>>> = HashMap() + protected val router: Router Any?>> = routerMaker() + protected val routerMap: HashMap Any?>>> = HashMap() + private val threadNumber = AtomicInteger(0) + val workerThread = ThreadPoolExecutor( + Runtime.getRuntime().availableProcessors() * 4, + Runtime.getRuntime().availableProcessors() * 4, + 0L, TimeUnit.MILLISECONDS, + LinkedBlockingQueue(), + ThreadFactory { + Thread(it, "TreeDiagramWorker-${threadNumber.incrementAndGet()}") + } + ) init { @Suppress("LeakingThis") @@ -47,7 +63,7 @@ open class RoutedHttpHandler( } } - open fun handle(content: HttpContent, handler: ((HttpContent) -> Unit)?) { + open fun handle(content: HttpContent, handler: ((HttpContent) -> Any?)?) { if (handler != null) { handler(content) } else { @@ -73,17 +89,17 @@ open class RoutedHttpHandler( } } - fun addRouter(route: String, handler: (HttpContent) -> Unit) = addRouter(route, null, handler) - fun addRouter(route: String, obj: Any?, handler: (HttpContent) -> Unit) { + fun addRouter(route: String, handler: (HttpContent) -> Any?) = addRouter(route, null, handler) + fun addRouter(route: String, obj: Any?, handler: (HttpContent) -> Any?) { router[safeRoute(route)] = obj to handler } - fun addRouter(method: String, route: String, handler: (HttpContent) -> Unit) = addRouter(method, route, null, handler) - fun addRouter(method: String, route: String, obj: Any?, handler: (HttpContent) -> Unit) { + fun addRouter(method: String, route: String, handler: (HttpContent) -> Any?) = addRouter(method, route, null, handler) + fun addRouter(method: String, route: String, obj: Any?, handler: (HttpContent) -> Any?) { getRouter(method)[safeRoute(route)] = obj to handler } - fun getHandler(content: MutableHttpContent, method: String, route: String): ((HttpContent) -> Unit)? { + fun getHandler(content: MutableHttpContent, method: String, route: String): ((HttpContent) -> Any?)? { val safeRoute = safeRoute(route) val router = getHandler(method, safeRoute) if (router.first != null) { @@ -94,7 +110,7 @@ open class RoutedHttpHandler( return router.first?.second ?: this.router[safeRoute].first?.second } - fun getHandler(method: String, route: String): Pair Unit>?, List>> { + fun getHandler(method: String, route: String): Pair Any?>?, List>> { val safeRoute = safeRoute(route) val router = getRouter(method)[safeRoute] return if (router.first != null) router else this.router[safeRoute] @@ -115,9 +131,9 @@ open class RoutedHttpHandler( } } - fun addRouter(obj: Any, method: Method, route: String, router: Router Unit>>) { - router[safeRoute(route)] = if (method.parameterTypes.isEmpty()) { - obj to when { + fun addRouter(obj: Any, method: Method, route: String, router: Router Any?>>) { + router[safeRoute(route)] = obj to (if (method.parameterTypes.isEmpty()) { + when { method.getAnnotation(Html::class.java) != null -> { content -> method(obj)?.let { result -> finishHtml(result, content) } } @@ -128,10 +144,10 @@ open class RoutedHttpHandler( method(obj)?.let { result -> finishJson(result, content) } } else -> { content -> - method(obj)?.let { result -> autoReturn(result, content) } + method(obj)?.let { result -> autoReturn(method, result, content) } } } - } else obj to when (method.returnType) { + } else when (method.returnType) { Void::class.java -> { content -> method(obj, content) } Void.TYPE -> { content -> method(obj, content) } Unit::class.java -> { content -> method(obj, content) } @@ -145,10 +161,15 @@ open class RoutedHttpHandler( method.getAnnotation(Json::class.java) != null -> { content -> method(obj, content)?.let { result -> finishJson(result, content) } } - else -> { content -> - method(obj, content)?.let { result -> autoReturn(result, content) } + else -> { content: HttpContent -> + method(obj, content)?.let { result -> autoReturn(method, result, content) } } } + }).let { + if (method.getAnnotation(BlockHandler::class.java) != null) { content -> + workerThread.execute { it(content) } + } else + it } } @@ -185,7 +206,7 @@ open class RoutedHttpHandler( } } - protected fun deleteMapping(obj: Any, route: String, router: Router Unit>>) { + protected fun deleteMapping(obj: Any, route: String, router: Router Any?>>) { val handler = router[safeRoute(route)].first if (handler?.first == obj) { router.delRoute(safeRoute(route)) @@ -226,7 +247,7 @@ open class RoutedHttpHandler( else -> null } - protected fun getRouter(method: String): Router Unit>> = when { + protected fun getRouter(method: String): Router Any?>> = when { method.isEmpty() -> router else -> { val upperCaseMethod = method.toUpperCase() @@ -267,6 +288,13 @@ 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) { + method.getAnnotation(ContextType::class.java)?.let { + content.autoContextType(it.type) + } + autoReturn(result, content) + } + fun autoReturn(result: Any?, content: HttpContent) { log?.debug("{}: autoReturn: {}", content.clientIp, result) result ?: return @@ -294,6 +322,12 @@ open class RoutedHttpHandler( is ByteBuffer -> content.finishHtml(result) is ByteArray -> content.finishHtml(result) is String -> content.finishHtml(result.toByteArray()) + is StringBuffer -> content.finishHtml(result.toString().toByteArray()) + is StringBuilder -> content.finishHtml(result.toString().toByteArray()) + is Chunked -> { + content.responseHtml() + content.finishChunked(result) + } else -> content.finishHtml(result.toString().toByteArray()) } } @@ -305,6 +339,12 @@ open class RoutedHttpHandler( is ByteBuffer -> content.finishText(result) is ByteArray -> content.finishText(result) is String -> content.finishText(result.toByteArray()) + is StringBuffer -> content.finishHtml(result.toString().toByteArray()) + is StringBuilder -> content.finishHtml(result.toString().toByteArray()) + is Chunked -> { + content.responseText() + content.finishChunked(result) + } else -> content.finishText(result.toString().toByteArray()) } } @@ -316,7 +356,13 @@ open class RoutedHttpHandler( is ByteBuffer -> content.finishJson(result) is ByteArray -> content.finishJson(result) is String -> content.finishJson("\"$result\"".toByteArray()) - is Byte, Short, Int, Long, Float, Double, Boolean -> content.finishJson(result.toString().toByteArray()) + is StringBuffer -> content.finishHtml(result.toString().toByteArray()) + is java.lang.StringBuilder -> content.finishHtml(result.toString().toByteArray()) + is Number, Boolean -> content.finishJson(result.toString().toByteArray()) + is Chunked -> { + content.responseJson() + content.finishChunked(result) + } else -> { val json = json?.toJson(result) log?.debug("{}: finishJson: generate json: {}", content.clientIp, json) diff --git a/web/src/main/kotlin/cn/tursom/web/utils/ContextType.kt b/web/src/main/kotlin/cn/tursom/web/utils/ContextType.kt new file mode 100644 index 0000000..2dcb696 --- /dev/null +++ b/web/src/main/kotlin/cn/tursom/web/utils/ContextType.kt @@ -0,0 +1,3 @@ +package cn.tursom.web.utils + +annotation class ContextType(val type: String) \ 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 e659824..16c2904 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 @@ -7,9 +7,11 @@ import cn.tursom.web.result.Html 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 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 @@ -17,7 +19,7 @@ import kotlin.reflect.jvm.jvmErasure @Suppress("ProtectedInFinal", "unused", "MemberVisibilityCanBePrivate") open class AsyncRoutedHttpHandler( target: Any? = null, - routerMaker: () -> Router Unit>> = { SimpleRouter() }, + routerMaker: () -> Router Any?>> = { SimpleRouter() }, val asyncRouterMaker: () -> Router Unit>> = { SimpleRouter() } ) : RoutedHttpHandler(target, routerMaker) { protected val asyncRouter: Router Unit>> = asyncRouterMaker() @@ -113,7 +115,7 @@ open class AsyncRoutedHttpHandler( (method as suspend Any.() -> Any?)(obj)?.let { result -> finishJson(result, content) } } else -> { content -> - (method as suspend Any.() -> Any?)(obj)?.let { result -> autoReturn(result, content) } + (method as suspend Any.() -> Any?)(obj)?.let { result -> autoReturn(method, result, content) } } } } else obj to when (method.returnType.jvmErasure.java) { @@ -131,7 +133,7 @@ open class AsyncRoutedHttpHandler( (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> finishJson(result, content) } } else -> { content -> - (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> autoReturn(result, content) } + (method as suspend Any.(HttpContent) -> Any?)(obj, content)?.let { result -> autoReturn(method, result, content) } } } } @@ -226,5 +228,12 @@ open class AsyncRoutedHttpHandler( } catch (e: Throwable) { null } + + fun autoReturn(method: KCallable<*>, result: Any?, content: HttpContent) { + method.findAnnotation()?.let { + content.autoContextType(it.type) + } + autoReturn(result, content) + } } } \ No newline at end of file