mirror of
https://github.com/tursom/TursomServer.git
synced 2024-12-28 05:40:12 +08:00
add coroutine ticker
This commit is contained in:
parent
d86018ea4d
commit
4ea5450819
@ -8,44 +8,44 @@ import java.lang.reflect.Proxy
|
||||
|
||||
class ProxyHandler(private val target: Any, private val aspect: Aspect) : InvocationHandler {
|
||||
|
||||
fun getTopBean(): Any {
|
||||
var bean = target
|
||||
while (Proxy.isProxyClass(bean.javaClass)) {
|
||||
val handler = Proxy.getInvocationHandler(bean)
|
||||
if (handler is ProxyHandler)
|
||||
bean = handler.target
|
||||
else break
|
||||
}
|
||||
return bean
|
||||
}
|
||||
fun getTopBean(): Any {
|
||||
var bean = target
|
||||
while (Proxy.isProxyClass(bean.javaClass)) {
|
||||
val handler = Proxy.getInvocationHandler(bean)
|
||||
if (handler is ProxyHandler)
|
||||
bean = handler.target
|
||||
else break
|
||||
}
|
||||
return bean
|
||||
}
|
||||
|
||||
override fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {
|
||||
return if (aspect.pointcut.matchMethod(method)) {
|
||||
aspect.advice.invoke(AdviceContent(target, method, args))
|
||||
} else {
|
||||
method.invoke(target, args)
|
||||
}
|
||||
}
|
||||
override fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {
|
||||
return if (aspect.pointcut.matchMethod(method)) {
|
||||
aspect.advice.invoke(AdviceContent(target, method, args))
|
||||
} else {
|
||||
method.invoke(target, args)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun proxyEnhance(bean: Any, aspect: Aspect): Any {
|
||||
val clazz = bean.javaClass
|
||||
return Proxy.newProxyInstance(
|
||||
clazz.classLoader,
|
||||
clazz.interfaces,
|
||||
ProxyHandler(bean, aspect)
|
||||
)
|
||||
}
|
||||
companion object {
|
||||
fun proxyEnhance(bean: Any, aspect: Aspect): Any {
|
||||
val clazz = bean.javaClass
|
||||
return Proxy.newProxyInstance(
|
||||
clazz.classLoader,
|
||||
clazz.interfaces,
|
||||
ProxyHandler(bean, aspect)
|
||||
)
|
||||
}
|
||||
|
||||
fun getTopBean(target: Any): Any {
|
||||
var bean = target
|
||||
while (Proxy.isProxyClass(bean.javaClass)) {
|
||||
val handler = Proxy.getInvocationHandler(bean)
|
||||
if (handler is ProxyHandler)
|
||||
bean = handler.target
|
||||
else break
|
||||
}
|
||||
return bean
|
||||
}
|
||||
}
|
||||
fun getTopBean(target: Any): Any {
|
||||
var bean = target
|
||||
while (Proxy.isProxyClass(bean.javaClass)) {
|
||||
val handler = Proxy.getInvocationHandler(bean)
|
||||
if (handler is ProxyHandler)
|
||||
bean = handler.target
|
||||
else break
|
||||
}
|
||||
return bean
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package cn.tursom.aop.advice
|
||||
|
||||
interface Advice {
|
||||
operator fun invoke(content: AdviceContent): Any?
|
||||
operator fun invoke(content: AdviceContent): Any?
|
||||
}
|
||||
|
||||
|
@ -6,22 +6,22 @@ import java.lang.reflect.Proxy
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class AdviceContent(
|
||||
val target: Any,
|
||||
val method: Method,
|
||||
val args: Array<out Any>?
|
||||
val target: Any,
|
||||
val method: Method,
|
||||
val args: Array<out Any>?
|
||||
) {
|
||||
val bean: Any = if (Proxy.isProxyClass(target.javaClass)) {
|
||||
val handler = Proxy.getInvocationHandler(target)
|
||||
if (handler is ProxyHandler)
|
||||
handler.getTopBean()
|
||||
else target
|
||||
} else target
|
||||
val bean: Any = if (Proxy.isProxyClass(target.javaClass)) {
|
||||
val handler = Proxy.getInvocationHandler(target)
|
||||
if (handler is ProxyHandler)
|
||||
handler.getTopBean()
|
||||
else target
|
||||
} else target
|
||||
|
||||
fun invoke() {
|
||||
if (args != null) {
|
||||
method.invoke(target, *args)
|
||||
} else {
|
||||
method.invoke(target)
|
||||
}
|
||||
}
|
||||
fun invoke() {
|
||||
if (args != null) {
|
||||
method.invoke(target, *args)
|
||||
} else {
|
||||
method.invoke(target)
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ import cn.tursom.aop.advice.Advice
|
||||
import cn.tursom.aop.pointcut.Pointcut
|
||||
|
||||
interface Aspect {
|
||||
val pointcut: Pointcut
|
||||
val advice: Advice
|
||||
val pointcut: Pointcut
|
||||
val advice: Advice
|
||||
}
|
||||
|
||||
|
@ -12,139 +12,139 @@ import java.io.File
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
object IocContainerFactory {
|
||||
/**
|
||||
* example:
|
||||
* <IOC>
|
||||
* <bean class="cn.tursom.Example1" id="exampleBean1"/>
|
||||
* <bean class="cn.tursom.Example2" id="exampleBean2">
|
||||
* <property name="propertyField" value="test"/>
|
||||
* <ref name="refField" id="exampleBean1" />
|
||||
* <bean name="beanField" class="cn.tursom.BeanField" />
|
||||
* </bean>
|
||||
* <aspect>
|
||||
* <advice class="cn.tursom.AdviceExample" />
|
||||
* <advice class="cn.tursom.AdviceExample2" />
|
||||
* <RegexPointcut class="cn\.tursom\.aop\..*" method=".*" />
|
||||
* <pointcut pointcut="RegexPointcut" class="cn\.tursom\.aop\.ioc\..*" method=".*" />
|
||||
* </aspect>
|
||||
* </IOC>
|
||||
*/
|
||||
fun loadFromXml(path: String): IocContainer = loadFromXml(path, Thread.currentThread().contextClassLoader)
|
||||
/**
|
||||
* example:
|
||||
* <IOC>
|
||||
* <bean class="cn.tursom.Example1" id="exampleBean1"/>
|
||||
* <bean class="cn.tursom.Example2" id="exampleBean2">
|
||||
* <property name="propertyField" value="test"/>
|
||||
* <ref name="refField" id="exampleBean1" />
|
||||
* <bean name="beanField" class="cn.tursom.BeanField" />
|
||||
* </bean>
|
||||
* <aspect>
|
||||
* <advice class="cn.tursom.AdviceExample" />
|
||||
* <advice class="cn.tursom.AdviceExample2" />
|
||||
* <RegexPointcut class="cn\.tursom\.aop\..*" method=".*" />
|
||||
* <pointcut pointcut="RegexPointcut" class="cn\.tursom\.aop\.ioc\..*" method=".*" />
|
||||
* </aspect>
|
||||
* </IOC>
|
||||
*/
|
||||
fun loadFromXml(path: String): IocContainer = loadFromXml(path, Thread.currentThread().contextClassLoader)
|
||||
|
||||
fun loadFromXml(path: String, classLoader: ClassLoader): IocContainer {
|
||||
val element: Element = Xml.saxReader.read(File(path)).rootElement
|
||||
val iocContainer = DefaultIocContainer()
|
||||
element.elements("bean").forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val id = it.attribute("id").value
|
||||
val bean = getXmlBean(it, classLoader, iocContainer)
|
||||
iocContainer.addBean(id, bean)
|
||||
}
|
||||
element.elements("aspect").forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val advices = getXmlAdvices(it, classLoader)
|
||||
val pointcuts = getXmlPointCuts(it)
|
||||
advices.forEach { advice ->
|
||||
pointcuts.forEach { pointcut ->
|
||||
iocContainer.addAspect(DefaultAspect(pointcut, advice))
|
||||
}
|
||||
}
|
||||
}
|
||||
return iocContainer
|
||||
}
|
||||
fun loadFromXml(path: String, classLoader: ClassLoader): IocContainer {
|
||||
val element: Element = Xml.saxReader.read(File(path)).rootElement
|
||||
val iocContainer = DefaultIocContainer()
|
||||
element.elements("bean").forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val id = it.attribute("id").value
|
||||
val bean = getXmlBean(it, classLoader, iocContainer)
|
||||
iocContainer.addBean(id, bean)
|
||||
}
|
||||
element.elements("aspect").forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val advices = getXmlAdvices(it, classLoader)
|
||||
val pointcuts = getXmlPointCuts(it)
|
||||
advices.forEach { advice ->
|
||||
pointcuts.forEach { pointcut ->
|
||||
iocContainer.addAspect(DefaultAspect(pointcut, advice))
|
||||
}
|
||||
}
|
||||
}
|
||||
return iocContainer
|
||||
}
|
||||
|
||||
fun getXmlPointCuts(root: Element): List<Pointcut> {
|
||||
val pointcuts = ArrayList<Pointcut>()
|
||||
root.elements("RegexPointcut").forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val clazz = it.attributeValue("class")
|
||||
val method = it.attributeValue("method")
|
||||
pointcuts.add(RegexPointcut(clazz, method))
|
||||
}
|
||||
root.elements().forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val clazz = it.attributeValue("class")
|
||||
val method = it.attributeValue("method")
|
||||
pointcuts.add(RegexPointcut(clazz, method))
|
||||
}
|
||||
return pointcuts
|
||||
}
|
||||
fun getXmlPointCuts(root: Element): List<Pointcut> {
|
||||
val pointcuts = ArrayList<Pointcut>()
|
||||
root.elements("RegexPointcut").forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val clazz = it.attributeValue("class")
|
||||
val method = it.attributeValue("method")
|
||||
pointcuts.add(RegexPointcut(clazz, method))
|
||||
}
|
||||
root.elements().forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val clazz = it.attributeValue("class")
|
||||
val method = it.attributeValue("method")
|
||||
pointcuts.add(RegexPointcut(clazz, method))
|
||||
}
|
||||
return pointcuts
|
||||
}
|
||||
|
||||
fun getXmlAdvices(root: Element, classLoader: ClassLoader): List<Advice> {
|
||||
val advices = ArrayList<Advice>()
|
||||
root.elements("advice").forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val clazzName = it.attributeValue("class")
|
||||
val clazz = classLoader.loadClass(clazzName)
|
||||
advices.add(clazz.newInstance() as Advice)
|
||||
}
|
||||
return advices
|
||||
}
|
||||
fun getXmlAdvices(root: Element, classLoader: ClassLoader): List<Advice> {
|
||||
val advices = ArrayList<Advice>()
|
||||
root.elements("advice").forEach {
|
||||
if (it !is Element) return@forEach
|
||||
val clazzName = it.attributeValue("class")
|
||||
val clazz = classLoader.loadClass(clazzName)
|
||||
advices.add(clazz.newInstance() as Advice)
|
||||
}
|
||||
return advices
|
||||
}
|
||||
|
||||
fun getXmlBean(root: Element, classLoader: ClassLoader, iocContainer: IocContainer): Any {
|
||||
val clazz = classLoader.loadClass(root.attribute("class").value)
|
||||
val bean = clazz.newInstance()
|
||||
root.elements()?.forEach subForEach@{ sub ->
|
||||
if (sub !is Element) return@subForEach
|
||||
when (sub.name) {
|
||||
"property" -> {
|
||||
val name = sub.attributeValue("name")
|
||||
val value = sub.attributeValue("value")
|
||||
val field = clazz.getDeclaredField(name)
|
||||
field.isAccessible = true
|
||||
field.set(bean, value)
|
||||
}
|
||||
"ref" -> {
|
||||
val name = sub.attributeValue("name")
|
||||
val refId = sub.attributeValue("id")
|
||||
val field = clazz.getDeclaredField(name)
|
||||
field.isAccessible = true
|
||||
field.set(bean, iocContainer[refId])
|
||||
}
|
||||
"bean" -> {
|
||||
val name = sub.attributeValue("name")
|
||||
val field = clazz.getDeclaredField(name)
|
||||
field.isAccessible = true
|
||||
field.set(bean, getXmlBean(sub, classLoader, iocContainer))
|
||||
}
|
||||
}
|
||||
}
|
||||
return bean
|
||||
}
|
||||
fun getXmlBean(root: Element, classLoader: ClassLoader, iocContainer: IocContainer): Any {
|
||||
val clazz = classLoader.loadClass(root.attribute("class").value)
|
||||
val bean = clazz.newInstance()
|
||||
root.elements()?.forEach subForEach@{ sub ->
|
||||
if (sub !is Element) return@subForEach
|
||||
when (sub.name) {
|
||||
"property" -> {
|
||||
val name = sub.attributeValue("name")
|
||||
val value = sub.attributeValue("value")
|
||||
val field = clazz.getDeclaredField(name)
|
||||
field.isAccessible = true
|
||||
field.set(bean, value)
|
||||
}
|
||||
"ref" -> {
|
||||
val name = sub.attributeValue("name")
|
||||
val refId = sub.attributeValue("id")
|
||||
val field = clazz.getDeclaredField(name)
|
||||
field.isAccessible = true
|
||||
field.set(bean, iocContainer[refId])
|
||||
}
|
||||
"bean" -> {
|
||||
val name = sub.attributeValue("name")
|
||||
val field = clazz.getDeclaredField(name)
|
||||
field.isAccessible = true
|
||||
field.set(bean, getXmlBean(sub, classLoader, iocContainer))
|
||||
}
|
||||
}
|
||||
}
|
||||
return bean
|
||||
}
|
||||
|
||||
/**
|
||||
* example:
|
||||
* {
|
||||
* "beans": [
|
||||
* {
|
||||
* "id": "exampleBean1",
|
||||
* "class": "cn.tursom.Example1"
|
||||
* },
|
||||
* {
|
||||
* "id": "exampleBean2",
|
||||
* "class": "cn.tursom.Example2",
|
||||
* "properties": [
|
||||
* {
|
||||
* "style": "property",
|
||||
* "name": "propertyField",
|
||||
* "value": "test"
|
||||
* },
|
||||
* {
|
||||
* "style": "ref",
|
||||
* "name": "refField",
|
||||
* "id": "exampleBean1"
|
||||
* },
|
||||
* {
|
||||
* "style": "bean",
|
||||
* "id": "refFiled",
|
||||
* "class": "cn.tursom.BeanField"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
fun loadFromJson(json: String): IocContainer {
|
||||
TODO()
|
||||
}
|
||||
/**
|
||||
* example:
|
||||
* {
|
||||
* "beans": [
|
||||
* {
|
||||
* "id": "exampleBean1",
|
||||
* "class": "cn.tursom.Example1"
|
||||
* },
|
||||
* {
|
||||
* "id": "exampleBean2",
|
||||
* "class": "cn.tursom.Example2",
|
||||
* "properties": [
|
||||
* {
|
||||
* "style": "property",
|
||||
* "name": "propertyField",
|
||||
* "value": "test"
|
||||
* },
|
||||
* {
|
||||
* "style": "ref",
|
||||
* "name": "refField",
|
||||
* "id": "exampleBean1"
|
||||
* },
|
||||
* {
|
||||
* "style": "bean",
|
||||
* "id": "refFiled",
|
||||
* "class": "cn.tursom.BeanField"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
fun loadFromJson(json: String): IocContainer {
|
||||
TODO()
|
||||
}
|
||||
}
|
@ -5,65 +5,65 @@ import cn.tursom.aop.ProxyHandler
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
class DefaultIocContainer : IocContainer {
|
||||
private val benDefinitionMap = HashMap<String, Class<*>>()
|
||||
private val beanMap = HashMap<String, Any>()
|
||||
private val aspectSet: java.util.AbstractSet<Aspect> = HashSet<Aspect>()
|
||||
private val benDefinitionMap = HashMap<String, Class<*>>()
|
||||
private val beanMap = HashMap<String, Any>()
|
||||
private val aspectSet: java.util.AbstractSet<Aspect> = HashSet<Aspect>()
|
||||
|
||||
override val aspects: Set<Aspect> get() = aspectSet
|
||||
override val aspects: Set<Aspect> get() = aspectSet
|
||||
|
||||
override fun addBeanDefinition(beanName: String, clazz: Class<*>) {
|
||||
benDefinitionMap[beanName] = clazz
|
||||
}
|
||||
override fun addBeanDefinition(beanName: String, clazz: Class<*>) {
|
||||
benDefinitionMap[beanName] = clazz
|
||||
}
|
||||
|
||||
override fun addBean(beanName: String, bean: Any) {
|
||||
beanMap[beanName] = proxyEnhance(bean)
|
||||
}
|
||||
override fun addBean(beanName: String, bean: Any) {
|
||||
beanMap[beanName] = proxyEnhance(bean)
|
||||
}
|
||||
|
||||
override fun getBean(beanName: String): Any {
|
||||
return beanMap[beanName] ?: run {
|
||||
val bean = createInstance(beanName)
|
||||
val proxyBean = proxyEnhance(bean)
|
||||
beanMap[beanName] = proxyBean
|
||||
proxyBean
|
||||
}
|
||||
}
|
||||
override fun getBean(beanName: String): Any {
|
||||
return beanMap[beanName] ?: run {
|
||||
val bean = createInstance(beanName)
|
||||
val proxyBean = proxyEnhance(bean)
|
||||
beanMap[beanName] = proxyBean
|
||||
proxyBean
|
||||
}
|
||||
}
|
||||
|
||||
private fun proxyEnhance(bean: Any): Any {
|
||||
val clazz = getTopBean(bean).javaClass
|
||||
var enhanceBean = bean
|
||||
aspectSet.forEach {
|
||||
if (it.pointcut.matchClass(clazz)) {
|
||||
enhanceBean = ProxyHandler.proxyEnhance(enhanceBean, it)
|
||||
}
|
||||
}
|
||||
return enhanceBean
|
||||
}
|
||||
private fun proxyEnhance(bean: Any): Any {
|
||||
val clazz = getTopBean(bean).javaClass
|
||||
var enhanceBean = bean
|
||||
aspectSet.forEach {
|
||||
if (it.pointcut.matchClass(clazz)) {
|
||||
enhanceBean = ProxyHandler.proxyEnhance(enhanceBean, it)
|
||||
}
|
||||
}
|
||||
return enhanceBean
|
||||
}
|
||||
|
||||
private fun createInstance(beanName: String): Any {
|
||||
return (benDefinitionMap[beanName] ?: throw NullPointerException()).newInstance()
|
||||
}
|
||||
private fun createInstance(beanName: String): Any {
|
||||
return (benDefinitionMap[beanName] ?: throw NullPointerException()).newInstance()
|
||||
}
|
||||
|
||||
override fun addAspect(aspect: Aspect) {
|
||||
if (aspectSet.contains(aspect)) return
|
||||
override fun addAspect(aspect: Aspect) {
|
||||
if (aspectSet.contains(aspect)) return
|
||||
|
||||
aspectSet.add(aspect)
|
||||
beanMap.forEach { (t, u) ->
|
||||
val bean = getTopBean(u)
|
||||
if (aspect.pointcut.matchClass(bean.javaClass)) {
|
||||
beanMap[t] = ProxyHandler.proxyEnhance(u, aspect)
|
||||
}
|
||||
}
|
||||
}
|
||||
aspectSet.add(aspect)
|
||||
beanMap.forEach { (t, u) ->
|
||||
val bean = getTopBean(u)
|
||||
if (aspect.pointcut.matchClass(bean.javaClass)) {
|
||||
beanMap[t] = ProxyHandler.proxyEnhance(u, aspect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun getTopBean(bean: Any): Any {
|
||||
return if (Proxy.isProxyClass(bean.javaClass)) {
|
||||
val handler = Proxy.getInvocationHandler(bean)
|
||||
if (handler is ProxyHandler) handler.getTopBean()
|
||||
else bean
|
||||
} else {
|
||||
bean
|
||||
}
|
||||
}
|
||||
private fun getTopBean(bean: Any): Any {
|
||||
return if (Proxy.isProxyClass(bean.javaClass)) {
|
||||
val handler = Proxy.getInvocationHandler(bean)
|
||||
if (handler is ProxyHandler) handler.getTopBean()
|
||||
else bean
|
||||
} else {
|
||||
bean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,15 @@ package cn.tursom.aop.ioc
|
||||
import cn.tursom.aop.aspect.Aspect
|
||||
|
||||
interface IocContainer {
|
||||
val aspects: Set<Aspect>
|
||||
val aspects: Set<Aspect>
|
||||
|
||||
fun addAspect(aspect: Aspect)
|
||||
fun addBeanDefinition(beanName: String, clazz: Class<*>)
|
||||
fun addBean(beanName: String, bean: Any)
|
||||
operator fun set(beanName: String, bean: Any) = addBean(beanName, bean)
|
||||
fun getBean(beanName: String): Any
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
operator fun <T> get(beanName: String): T = getBean(beanName) as T
|
||||
fun addAspect(aspect: Aspect)
|
||||
fun addBeanDefinition(beanName: String, clazz: Class<*>)
|
||||
fun addBean(beanName: String, bean: Any)
|
||||
operator fun set(beanName: String, bean: Any) = addBean(beanName, bean)
|
||||
fun getBean(beanName: String): Any
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
operator fun <T> get(beanName: String): T = getBean(beanName) as T
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ package cn.tursom.aop.pointcut
|
||||
import java.lang.reflect.Method
|
||||
|
||||
interface Pointcut {
|
||||
fun matchClass(clazz: Class<*>): Boolean
|
||||
fun matchMethod(method: Method): Boolean
|
||||
fun matchClass(clazz: Class<*>): Boolean
|
||||
fun matchMethod(method: Method): Boolean
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,11 @@ package cn.tursom.aop.pointcut
|
||||
import java.lang.reflect.Method
|
||||
|
||||
data class RegexPointcut(
|
||||
private val classRegex: Regex,
|
||||
private val methodRegex: Regex
|
||||
private val classRegex: Regex,
|
||||
private val methodRegex: Regex
|
||||
) : Pointcut {
|
||||
constructor(classRegex: String, methodRegex: String) : this(classRegex.toRegex(), methodRegex.toRegex())
|
||||
constructor(classRegex: String, methodRegex: String) : this(classRegex.toRegex(), methodRegex.toRegex())
|
||||
|
||||
override fun matchClass(clazz: Class<*>) = classRegex.matches(clazz.name)
|
||||
override fun matchMethod(method: Method) = methodRegex.matches(method.name)
|
||||
override fun matchClass(clazz: Class<*>) = classRegex.matches(clazz.name)
|
||||
override fun matchMethod(method: Method) = methodRegex.matches(method.name)
|
||||
}
|
104
build.gradle.kts
104
build.gradle.kts
@ -2,85 +2,85 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
ext["netty.version"] = "4.1.59.Final"
|
||||
ext["excludeTest"] = { project: Project, tasks: TaskContainer ->
|
||||
if (project.gradle.startParameter.taskNames.firstOrNull { taskName ->
|
||||
taskName.endsWith(":test")
|
||||
} == null) {
|
||||
tasks {
|
||||
test { enabled = false }
|
||||
testClasses { enabled = false }
|
||||
compileTestJava { enabled = false }
|
||||
compileTestKotlin { enabled = false }
|
||||
processTestResources { enabled = false }
|
||||
}
|
||||
if (project.gradle.startParameter.taskNames.firstOrNull { taskName ->
|
||||
taskName.endsWith(":test")
|
||||
} == null) {
|
||||
tasks {
|
||||
test { enabled = false }
|
||||
testClasses { enabled = false }
|
||||
compileTestJava { enabled = false }
|
||||
compileTestKotlin { enabled = false }
|
||||
processTestResources { enabled = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.5.20"
|
||||
`maven-publish`
|
||||
kotlin("jvm") version "1.5.20"
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = "cn.tursom"
|
||||
version = "0.2"
|
||||
group = "cn.tursom"
|
||||
version = "0.2"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
|
||||
}
|
||||
|
||||
if (project.gradle.startParameter.taskNames.firstOrNull { taskName ->
|
||||
taskName.endsWith(":test")
|
||||
} == null) {
|
||||
tasks.withType<Test> {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
|
||||
//kotlinOptions.useIR = true
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
|
||||
}
|
||||
|
||||
if (project.gradle.startParameter.taskNames.firstOrNull { taskName ->
|
||||
taskName.endsWith(":test")
|
||||
} == null) {
|
||||
tasks.withType<Test> {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
|
||||
//kotlinOptions.useIR = true
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
api(kotlin("reflect"))
|
||||
testImplementation(group = "junit", name = "junit", version = "4.12")
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
api(kotlin("reflect"))
|
||||
testImplementation(group = "junit", name = "junit", version = "4.12")
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives(tasks["kotlinSourcesJar"])
|
||||
archives(tasks["kotlinSourcesJar"])
|
||||
}
|
||||
|
||||
tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,153 +69,153 @@ fun Double.hours() = Hours(toLong())
|
||||
fun Double.days() = Days(toLong())
|
||||
|
||||
sealed interface Time {
|
||||
val duration: Long
|
||||
val timeUnit: TimeUnit
|
||||
fun convert(timeUnit: TimeUnit): Long = this.timeUnit.convert(duration, timeUnit)
|
||||
fun toNanos(): Long = timeUnit.toNanos(duration)
|
||||
fun toMicros(): Long = timeUnit.toMicros(duration)
|
||||
fun toMillis(): Long = timeUnit.toMillis(duration)
|
||||
fun toSeconds(): Long = timeUnit.toSeconds(duration)
|
||||
fun toMinutes(): Long = timeUnit.toMinutes(duration)
|
||||
fun toHours(): Long = timeUnit.toHours(duration)
|
||||
fun toDays(): Long = timeUnit.toDays(duration)
|
||||
fun timedWait(obj: Any) = timeUnit.timedWait(obj, duration)
|
||||
fun timedJoin(thread: Thread) = timeUnit.timedJoin(thread, duration)
|
||||
fun sleep() = timeUnit.sleep(duration)
|
||||
suspend fun delay() {
|
||||
kotlinx.coroutines.delay(timeUnit.toMillis(duration))
|
||||
}
|
||||
val duration: Long
|
||||
val timeUnit: TimeUnit
|
||||
fun convert(timeUnit: TimeUnit): Long = this.timeUnit.convert(duration, timeUnit)
|
||||
fun toNanos(): Long = timeUnit.toNanos(duration)
|
||||
fun toMicros(): Long = timeUnit.toMicros(duration)
|
||||
fun toMillis(): Long = timeUnit.toMillis(duration)
|
||||
fun toSeconds(): Long = timeUnit.toSeconds(duration)
|
||||
fun toMinutes(): Long = timeUnit.toMinutes(duration)
|
||||
fun toHours(): Long = timeUnit.toHours(duration)
|
||||
fun toDays(): Long = timeUnit.toDays(duration)
|
||||
fun timedWait(obj: Any) = timeUnit.timedWait(obj, duration)
|
||||
fun timedJoin(thread: Thread) = timeUnit.timedJoin(thread, duration)
|
||||
fun sleep() = timeUnit.sleep(duration)
|
||||
suspend fun delay() {
|
||||
kotlinx.coroutines.delay(timeUnit.toMillis(duration))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class NanoSeconds(override val duration: Long) : Time {
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.NANOSECONDS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.NANOSECONDS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.NANOSECONDS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.NANOSECONDS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.NANOSECONDS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.NANOSECONDS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.NANOSECONDS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.NANOSECONDS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.NANOSECONDS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.NANOSECONDS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.NANOSECONDS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.NANOSECONDS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.NANOSECONDS.toMillis(duration))
|
||||
}
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.NANOSECONDS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.NANOSECONDS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.NANOSECONDS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.NANOSECONDS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.NANOSECONDS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.NANOSECONDS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.NANOSECONDS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.NANOSECONDS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.NANOSECONDS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.NANOSECONDS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.NANOSECONDS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.NANOSECONDS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.NANOSECONDS.toMillis(duration))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class MicroSeconds(override val duration: Long) : Time {
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.MICROSECONDS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.MICROSECONDS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.MICROSECONDS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.MICROSECONDS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.MICROSECONDS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.MICROSECONDS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.MICROSECONDS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.MICROSECONDS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.MICROSECONDS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.MICROSECONDS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.MICROSECONDS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.MICROSECONDS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.MICROSECONDS.toMillis(duration))
|
||||
}
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.MICROSECONDS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.MICROSECONDS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.MICROSECONDS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.MICROSECONDS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.MICROSECONDS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.MICROSECONDS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.MICROSECONDS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.MICROSECONDS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.MICROSECONDS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.MICROSECONDS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.MICROSECONDS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.MICROSECONDS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.MICROSECONDS.toMillis(duration))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class MilliSeconds(override val duration: Long) : Time {
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.MILLISECONDS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.MILLISECONDS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.MILLISECONDS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.MILLISECONDS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.MILLISECONDS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.MILLISECONDS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.MILLISECONDS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.MILLISECONDS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.MILLISECONDS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.MILLISECONDS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.MILLISECONDS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.MILLISECONDS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.MILLISECONDS.toMillis(duration))
|
||||
}
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.MILLISECONDS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.MILLISECONDS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.MILLISECONDS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.MILLISECONDS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.MILLISECONDS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.MILLISECONDS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.MILLISECONDS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.MILLISECONDS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.MILLISECONDS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.MILLISECONDS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.MILLISECONDS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.MILLISECONDS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.MILLISECONDS.toMillis(duration))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class Seconds(override val duration: Long) : Time {
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.SECONDS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.SECONDS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.SECONDS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.SECONDS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.SECONDS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.SECONDS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.SECONDS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.SECONDS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.SECONDS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.SECONDS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.SECONDS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.SECONDS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.SECONDS.toMillis(duration))
|
||||
}
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.SECONDS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.SECONDS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.SECONDS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.SECONDS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.SECONDS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.SECONDS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.SECONDS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.SECONDS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.SECONDS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.SECONDS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.SECONDS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.SECONDS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.SECONDS.toMillis(duration))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class Minutes(override val duration: Long) : Time {
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.MINUTES
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.MINUTES.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.MINUTES.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.MINUTES.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.MINUTES.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.MINUTES.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.MINUTES.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.MINUTES.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.MINUTES.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.MINUTES.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.MINUTES.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.MINUTES.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.MINUTES.toMillis(duration))
|
||||
}
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.MINUTES
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.MINUTES.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.MINUTES.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.MINUTES.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.MINUTES.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.MINUTES.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.MINUTES.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.MINUTES.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.MINUTES.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.MINUTES.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.MINUTES.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.MINUTES.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.MINUTES.toMillis(duration))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class Hours(override val duration: Long) : Time {
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.HOURS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.HOURS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.HOURS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.HOURS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.HOURS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.HOURS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.HOURS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.HOURS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.HOURS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.HOURS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.HOURS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.HOURS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.HOURS.toMillis(duration))
|
||||
}
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.HOURS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.HOURS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.HOURS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.HOURS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.HOURS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.HOURS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.HOURS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.HOURS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.HOURS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.HOURS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.HOURS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.HOURS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.HOURS.toMillis(duration))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class Days(override val duration: Long) : Time {
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.DAYS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.DAYS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.DAYS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.DAYS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.DAYS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.DAYS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.DAYS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.DAYS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.DAYS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.DAYS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.DAYS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.DAYS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.DAYS.toMillis(duration))
|
||||
}
|
||||
override val timeUnit: TimeUnit get() = TimeUnit.DAYS
|
||||
override fun convert(timeUnit: TimeUnit): Long = TimeUnit.DAYS.convert(duration, timeUnit)
|
||||
override fun toNanos(): Long = TimeUnit.DAYS.toNanos(duration)
|
||||
override fun toMicros(): Long = TimeUnit.DAYS.toMicros(duration)
|
||||
override fun toMillis(): Long = TimeUnit.DAYS.toMillis(duration)
|
||||
override fun toSeconds(): Long = TimeUnit.DAYS.toSeconds(duration)
|
||||
override fun toMinutes(): Long = TimeUnit.DAYS.toMinutes(duration)
|
||||
override fun toHours(): Long = TimeUnit.DAYS.toHours(duration)
|
||||
override fun toDays(): Long = TimeUnit.DAYS.toDays(duration)
|
||||
override fun timedWait(obj: Any) = TimeUnit.DAYS.timedWait(obj, duration)
|
||||
override fun timedJoin(thread: Thread) = TimeUnit.DAYS.timedJoin(thread, duration)
|
||||
override fun sleep() = TimeUnit.DAYS.sleep(duration)
|
||||
override suspend fun delay() {
|
||||
kotlinx.coroutines.delay(TimeUnit.DAYS.toMillis(duration))
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,14 @@ import io.netty.handler.codec.http.websocketx.TextWebSocketFrame
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
object WebSocketFrameWrapper : ChannelOutboundHandlerAdapter() {
|
||||
override fun write(ctx: ChannelHandlerContext, msg: Any?, promise: ChannelPromise?) {
|
||||
ctx.write(when (msg) {
|
||||
is String -> TextWebSocketFrame(msg)
|
||||
is ByteArray -> BinaryWebSocketFrame(Unpooled.wrappedBuffer(msg))
|
||||
is ByteBuf -> BinaryWebSocketFrame(msg)
|
||||
else -> msg
|
||||
}, promise)
|
||||
}
|
||||
override fun write(ctx: ChannelHandlerContext, msg: Any?, promise: ChannelPromise?) {
|
||||
ctx.write(
|
||||
when (msg) {
|
||||
is String -> TextWebSocketFrame(msg)
|
||||
is ByteArray -> BinaryWebSocketFrame(Unpooled.wrappedBuffer(msg))
|
||||
is ByteBuf -> BinaryWebSocketFrame(msg)
|
||||
else -> msg
|
||||
}, promise
|
||||
)
|
||||
}
|
||||
}
|
@ -14,308 +14,308 @@ import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
object AsyncHttpRequest {
|
||||
val defaultClient: OkHttpClient = OkHttpClient().newBuilder()
|
||||
.retryOnConnectionFailure(true)
|
||||
.build()
|
||||
val socketClient: OkHttpClient = proxyClient()
|
||||
val httpProxyClient: OkHttpClient =
|
||||
proxyClient(port = 8080, type = Proxy.Type.HTTP)
|
||||
val defaultClient: OkHttpClient = OkHttpClient().newBuilder()
|
||||
.retryOnConnectionFailure(true)
|
||||
.build()
|
||||
val socketClient: OkHttpClient = proxyClient()
|
||||
val httpProxyClient: OkHttpClient =
|
||||
proxyClient(port = 8080, type = Proxy.Type.HTTP)
|
||||
|
||||
fun proxyClient(
|
||||
host: String = "127.0.0.1",
|
||||
port: Int = 1080,
|
||||
type: Proxy.Type = Proxy.Type.SOCKS
|
||||
): OkHttpClient = OkHttpClient().newBuilder()
|
||||
.proxy(Proxy(type, InetSocketAddress(host, port) as SocketAddress))
|
||||
.retryOnConnectionFailure(true)
|
||||
.build()
|
||||
fun proxyClient(
|
||||
host: String = "127.0.0.1",
|
||||
port: Int = 1080,
|
||||
type: Proxy.Type = Proxy.Type.SOCKS
|
||||
): OkHttpClient = OkHttpClient().newBuilder()
|
||||
.proxy(Proxy(type, InetSocketAddress(host, port) as SocketAddress))
|
||||
.retryOnConnectionFailure(true)
|
||||
.build()
|
||||
|
||||
suspend fun sendRequest(call: Call): Response = suspendCoroutine {
|
||||
call.enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
it.resumeWithException(e)
|
||||
}
|
||||
suspend fun sendRequest(call: Call): Response = suspendCoroutine {
|
||||
call.enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
it.resumeWithException(e)
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
it.resume(response)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
suspend fun get(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
): Response {
|
||||
val paramSB = StringBuilder()
|
||||
param?.forEach {
|
||||
paramSB.append("${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}&")
|
||||
}
|
||||
if (paramSB.isNotEmpty())
|
||||
paramSB.deleteCharAt(paramSB.length - 1)
|
||||
|
||||
val requestBuilder = Request.Builder().get()
|
||||
.url("$url?$paramSB")
|
||||
|
||||
headers?.forEach { t, u ->
|
||||
requestBuilder.addHeader(t, u)
|
||||
}
|
||||
|
||||
return sendRequest(
|
||||
client.newCall(
|
||||
requestBuilder.build()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun post(
|
||||
url: String,
|
||||
body: RequestBody,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
): Response {
|
||||
val requestBuilder = Request.Builder()
|
||||
.post(body)
|
||||
.url(url)
|
||||
|
||||
headers?.forEach { t, u ->
|
||||
requestBuilder.addHeader(t, u)
|
||||
}
|
||||
|
||||
return sendRequest(client.newCall(requestBuilder.build()))
|
||||
}
|
||||
|
||||
suspend fun post(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
): Response {
|
||||
val formBuilder = FormBody.Builder()
|
||||
param.forEach { (t, u) ->
|
||||
formBuilder.add(t, u)
|
||||
}
|
||||
return post(url, formBuilder.build(), headers, client)
|
||||
}
|
||||
|
||||
suspend fun post(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
) = post(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun post(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
) = post(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("application/octet-stream"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun post(
|
||||
url: String,
|
||||
body: ByteArray,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
) = post(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("application/octet-stream"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
it.resume(response)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
suspend fun getStr(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null
|
||||
): String {
|
||||
return getStr(url, param, headers, defaultClient)
|
||||
}
|
||||
suspend fun get(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
): Response {
|
||||
val paramSB = StringBuilder()
|
||||
param?.forEach {
|
||||
paramSB.append("${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}&")
|
||||
}
|
||||
if (paramSB.isNotEmpty())
|
||||
paramSB.deleteCharAt(paramSB.length - 1)
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
suspend fun getStr(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String {
|
||||
val response = get(url, param, headers, client)
|
||||
return response.body()!!.string()
|
||||
}
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
private suspend fun postStr(
|
||||
url: String,
|
||||
body: RequestBody,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String = post(url, body, headers, client).body()!!.string()
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null
|
||||
): String =
|
||||
postStr(url, param, headers, defaultClient)
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String {
|
||||
val formBuilder = FormBody.Builder()
|
||||
param.forEach { (t, u) ->
|
||||
formBuilder.add(t, u)
|
||||
}
|
||||
return postStr(url, formBuilder.build(), headers, client)
|
||||
}
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null
|
||||
): String =
|
||||
postStr(url, body, headers, defaultClient)
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String = postStr(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null
|
||||
): String =
|
||||
postStr(url, body, headers, defaultClient)
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String = postStr(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("application/octet-stream"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun getByteArray(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null
|
||||
): ByteArray = getByteArray(
|
||||
url,
|
||||
param,
|
||||
headers,
|
||||
defaultClient
|
||||
)
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
suspend fun getByteArray(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray = get(url, param, headers, client).body()!!.bytes()
|
||||
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
private suspend fun postByteArray(
|
||||
url: String,
|
||||
body: RequestBody,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray = post(url, body, headers, client).body()!!.bytes()
|
||||
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
param,
|
||||
headers,
|
||||
defaultClient
|
||||
)
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray {
|
||||
val formBuilder = FormBody.Builder()
|
||||
param.forEach { (t, u) ->
|
||||
formBuilder.add(t, u)
|
||||
}
|
||||
return postByteArray(url, formBuilder.build(), headers, client)
|
||||
}
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
body,
|
||||
headers,
|
||||
defaultClient
|
||||
)
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
body,
|
||||
headers,
|
||||
defaultClient
|
||||
)
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("application/octet-stream"), body),
|
||||
headers,
|
||||
client
|
||||
val requestBuilder = Request.Builder().get()
|
||||
.url("$url?$paramSB")
|
||||
|
||||
headers?.forEach { t, u ->
|
||||
requestBuilder.addHeader(t, u)
|
||||
}
|
||||
|
||||
return sendRequest(
|
||||
client.newCall(
|
||||
requestBuilder.build()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun post(
|
||||
url: String,
|
||||
body: RequestBody,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
): Response {
|
||||
val requestBuilder = Request.Builder()
|
||||
.post(body)
|
||||
.url(url)
|
||||
|
||||
headers?.forEach { t, u ->
|
||||
requestBuilder.addHeader(t, u)
|
||||
}
|
||||
|
||||
return sendRequest(client.newCall(requestBuilder.build()))
|
||||
}
|
||||
|
||||
suspend fun post(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
): Response {
|
||||
val formBuilder = FormBody.Builder()
|
||||
param.forEach { (t, u) ->
|
||||
formBuilder.add(t, u)
|
||||
}
|
||||
return post(url, formBuilder.build(), headers, client)
|
||||
}
|
||||
|
||||
suspend fun post(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
) = post(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun post(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
) = post(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("application/octet-stream"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun post(
|
||||
url: String,
|
||||
body: ByteArray,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient = defaultClient
|
||||
) = post(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("application/octet-stream"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun getStr(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null
|
||||
): String {
|
||||
return getStr(url, param, headers, defaultClient)
|
||||
}
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
suspend fun getStr(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String {
|
||||
val response = get(url, param, headers, client)
|
||||
return response.body()!!.string()
|
||||
}
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
private suspend fun postStr(
|
||||
url: String,
|
||||
body: RequestBody,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String = post(url, body, headers, client).body()!!.string()
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null
|
||||
): String =
|
||||
postStr(url, param, headers, defaultClient)
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String {
|
||||
val formBuilder = FormBody.Builder()
|
||||
param.forEach { (t, u) ->
|
||||
formBuilder.add(t, u)
|
||||
}
|
||||
return postStr(url, formBuilder.build(), headers, client)
|
||||
}
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null
|
||||
): String =
|
||||
postStr(url, body, headers, defaultClient)
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String = postStr(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null
|
||||
): String =
|
||||
postStr(url, body, headers, defaultClient)
|
||||
|
||||
suspend fun postStr(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): String = postStr(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("application/octet-stream"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun getByteArray(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null
|
||||
): ByteArray = getByteArray(
|
||||
url,
|
||||
param,
|
||||
headers,
|
||||
defaultClient
|
||||
)
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
suspend fun getByteArray(
|
||||
url: String,
|
||||
param: Map<String, String>? = null,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray = get(url, param, headers, client).body()!!.bytes()
|
||||
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
private suspend fun postByteArray(
|
||||
url: String,
|
||||
body: RequestBody,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray = post(url, body, headers, client).body()!!.bytes()
|
||||
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
param,
|
||||
headers,
|
||||
defaultClient
|
||||
)
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
param: Map<String, String>,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray {
|
||||
val formBuilder = FormBody.Builder()
|
||||
param.forEach { (t, u) ->
|
||||
formBuilder.add(t, u)
|
||||
}
|
||||
return postByteArray(url, formBuilder.build(), headers, client)
|
||||
}
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
body,
|
||||
headers,
|
||||
defaultClient
|
||||
)
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
body: String,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
body,
|
||||
headers,
|
||||
defaultClient
|
||||
)
|
||||
|
||||
suspend fun postByteArray(
|
||||
url: String,
|
||||
body: File,
|
||||
headers: Map<String, String>? = null,
|
||||
client: OkHttpClient
|
||||
): ByteArray = postByteArray(
|
||||
url,
|
||||
RequestBody.create(MediaType.parse("application/octet-stream"), body),
|
||||
headers,
|
||||
client
|
||||
)
|
||||
}
|
||||
|
@ -15,194 +15,194 @@ import cn.tursom.core.isStatic
|
||||
class UnsupportedException : Exception()
|
||||
|
||||
fun ByteBuffer.serialize(obj: Any) {
|
||||
when (obj) {
|
||||
is Char -> put(obj)
|
||||
is Short -> put(obj)
|
||||
is Int -> put(obj)
|
||||
is Long -> put(obj)
|
||||
is Float -> put(obj)
|
||||
is Double -> put(obj)
|
||||
is String -> serialize(obj.toByteArray())
|
||||
is ByteArray -> {
|
||||
put(obj.size)
|
||||
put(obj)
|
||||
}
|
||||
is CharArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach {
|
||||
put(it)
|
||||
}
|
||||
}
|
||||
is ShortArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is IntArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is LongArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is FloatArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is DoubleArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is Array<*> -> {
|
||||
put(obj.size)
|
||||
obj.forEach { serialize(it ?: return@forEach) }
|
||||
}
|
||||
is Collection<*> -> {
|
||||
put(obj.size)
|
||||
obj.forEach { serialize(it ?: return@forEach) }
|
||||
}
|
||||
is Map<*, *> -> {
|
||||
put(obj.size)
|
||||
obj.forEach { (k, v) ->
|
||||
serialize(k ?: return@forEach)
|
||||
serialize(v ?: return@forEach)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
obj.javaClass.declaredFields.forEach {
|
||||
if (it.isStatic()) return@forEach
|
||||
it.isAccessible = true
|
||||
serialize(it.get(obj) ?: return@forEach)
|
||||
}
|
||||
}
|
||||
}
|
||||
when (obj) {
|
||||
is Char -> put(obj)
|
||||
is Short -> put(obj)
|
||||
is Int -> put(obj)
|
||||
is Long -> put(obj)
|
||||
is Float -> put(obj)
|
||||
is Double -> put(obj)
|
||||
is String -> serialize(obj.toByteArray())
|
||||
is ByteArray -> {
|
||||
put(obj.size)
|
||||
put(obj)
|
||||
}
|
||||
is CharArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach {
|
||||
put(it)
|
||||
}
|
||||
}
|
||||
is ShortArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is IntArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is LongArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is FloatArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is DoubleArray -> {
|
||||
put(obj.size)
|
||||
obj.forEach { put(it) }
|
||||
}
|
||||
is Array<*> -> {
|
||||
put(obj.size)
|
||||
obj.forEach { serialize(it ?: return@forEach) }
|
||||
}
|
||||
is Collection<*> -> {
|
||||
put(obj.size)
|
||||
obj.forEach { serialize(it ?: return@forEach) }
|
||||
}
|
||||
is Map<*, *> -> {
|
||||
put(obj.size)
|
||||
obj.forEach { (k, v) ->
|
||||
serialize(k ?: return@forEach)
|
||||
serialize(v ?: return@forEach)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
obj.javaClass.declaredFields.forEach {
|
||||
if (it.isStatic()) return@forEach
|
||||
it.isAccessible = true
|
||||
serialize(it.get(obj) ?: return@forEach)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> ByteBuffer.unSerialize(clazz: Class<T>): T {
|
||||
when {
|
||||
clazz == Byte::class.java -> {
|
||||
return get() as T
|
||||
}
|
||||
clazz == Char::class.java -> {
|
||||
return getChar() as T
|
||||
}
|
||||
clazz == Short::class.java -> {
|
||||
return getShort() as T
|
||||
}
|
||||
clazz == Int::class.java -> {
|
||||
return getInt() as T
|
||||
}
|
||||
clazz == Long::class.java -> {
|
||||
return getLong() as T
|
||||
}
|
||||
clazz == Float::class.java -> {
|
||||
return getFloat() as T
|
||||
}
|
||||
clazz == Double::class.java -> {
|
||||
return getDouble() as T
|
||||
}
|
||||
|
||||
clazz == java.lang.Byte::class.java -> {
|
||||
return get() as T
|
||||
}
|
||||
clazz == java.lang.Character::class.java -> {
|
||||
return getChar() as T
|
||||
}
|
||||
clazz == java.lang.Short::class.java -> {
|
||||
return getShort() as T
|
||||
}
|
||||
clazz == java.lang.Integer::class.java -> {
|
||||
return getInt() as T
|
||||
}
|
||||
clazz == java.lang.Long::class.java -> {
|
||||
return getLong() as T
|
||||
}
|
||||
clazz == java.lang.Float::class.java -> {
|
||||
return getFloat() as T
|
||||
}
|
||||
clazz == java.lang.Double::class.java -> {
|
||||
return getDouble() as T
|
||||
}
|
||||
|
||||
clazz == String::class.java -> {
|
||||
return getString(getInt()) as T
|
||||
}
|
||||
|
||||
clazz == ByteArray::class.java -> {
|
||||
val array = ByteArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = get()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == CharArray::class.java -> {
|
||||
val array = CharArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getChar()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == ShortArray::class.java -> {
|
||||
val array = ShortArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getShort()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == IntArray::class.java -> {
|
||||
val array = IntArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getInt()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == LongArray::class.java -> {
|
||||
val array = LongArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getLong()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == FloatArray::class.java -> {
|
||||
val array = FloatArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getFloat()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == DoubleArray::class.java -> {
|
||||
val array = DoubleArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getDouble()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz.isArray -> {
|
||||
val componentType = clazz.componentType
|
||||
val newArray = java.lang.reflect.Array.newInstance(componentType, getInt())
|
||||
repeat(java.lang.reflect.Array.getLength(newArray)) {
|
||||
java.lang.reflect.Array.set(newArray, it, unSerialize(componentType))
|
||||
}
|
||||
return newArray as T
|
||||
}
|
||||
else -> {
|
||||
//TODO
|
||||
val instance = try {
|
||||
clazz.newInstance()
|
||||
} catch (e: Throwable) {
|
||||
unsafe.allocateInstance(clazz)
|
||||
}
|
||||
clazz.declaredFields.forEach {
|
||||
if (it.isStatic()) return@forEach
|
||||
it.isAccessible = true
|
||||
it.set(instance, unSerialize(it.type))
|
||||
}
|
||||
return instance as T
|
||||
}
|
||||
}
|
||||
when {
|
||||
clazz == Byte::class.java -> {
|
||||
return get() as T
|
||||
}
|
||||
clazz == Char::class.java -> {
|
||||
return getChar() as T
|
||||
}
|
||||
clazz == Short::class.java -> {
|
||||
return getShort() as T
|
||||
}
|
||||
clazz == Int::class.java -> {
|
||||
return getInt() as T
|
||||
}
|
||||
clazz == Long::class.java -> {
|
||||
return getLong() as T
|
||||
}
|
||||
clazz == Float::class.java -> {
|
||||
return getFloat() as T
|
||||
}
|
||||
clazz == Double::class.java -> {
|
||||
return getDouble() as T
|
||||
}
|
||||
|
||||
clazz == java.lang.Byte::class.java -> {
|
||||
return get() as T
|
||||
}
|
||||
clazz == java.lang.Character::class.java -> {
|
||||
return getChar() as T
|
||||
}
|
||||
clazz == java.lang.Short::class.java -> {
|
||||
return getShort() as T
|
||||
}
|
||||
clazz == java.lang.Integer::class.java -> {
|
||||
return getInt() as T
|
||||
}
|
||||
clazz == java.lang.Long::class.java -> {
|
||||
return getLong() as T
|
||||
}
|
||||
clazz == java.lang.Float::class.java -> {
|
||||
return getFloat() as T
|
||||
}
|
||||
clazz == java.lang.Double::class.java -> {
|
||||
return getDouble() as T
|
||||
}
|
||||
|
||||
clazz == String::class.java -> {
|
||||
return getString(getInt()) as T
|
||||
}
|
||||
|
||||
clazz == ByteArray::class.java -> {
|
||||
val array = ByteArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = get()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == CharArray::class.java -> {
|
||||
val array = CharArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getChar()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == ShortArray::class.java -> {
|
||||
val array = ShortArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getShort()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == IntArray::class.java -> {
|
||||
val array = IntArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getInt()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == LongArray::class.java -> {
|
||||
val array = LongArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getLong()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == FloatArray::class.java -> {
|
||||
val array = FloatArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getFloat()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz == DoubleArray::class.java -> {
|
||||
val array = DoubleArray(getInt())
|
||||
repeat(array.size) {
|
||||
array[it] = getDouble()
|
||||
}
|
||||
return array as T
|
||||
}
|
||||
clazz.isArray -> {
|
||||
val componentType = clazz.componentType
|
||||
val newArray = java.lang.reflect.Array.newInstance(componentType, getInt())
|
||||
repeat(java.lang.reflect.Array.getLength(newArray)) {
|
||||
java.lang.reflect.Array.set(newArray, it, unSerialize(componentType))
|
||||
}
|
||||
return newArray as T
|
||||
}
|
||||
else -> {
|
||||
//TODO
|
||||
val instance = try {
|
||||
clazz.newInstance()
|
||||
} catch (e: Throwable) {
|
||||
unsafe.allocateInstance(clazz)
|
||||
}
|
||||
clazz.declaredFields.forEach {
|
||||
if (it.isStatic()) return@forEach
|
||||
it.isAccessible = true
|
||||
it.set(instance, unSerialize(it.type))
|
||||
}
|
||||
return instance as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> ByteBuffer.unSerialize(): T {
|
||||
return unSerialize(T::class.java)
|
||||
return unSerialize(T::class.java)
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
package cn.tursom.core.coroutine
|
||||
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.ReceiveChannel
|
||||
import kotlinx.coroutines.channels.SendChannel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.ref.Reference
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
class BufferTickerProvider(
|
||||
val delayMillis: Long,
|
||||
val capacity: Int = 16,
|
||||
) {
|
||||
private val channels = ConcurrentLinkedQueue<Reference<out SendChannel<Unit>>>()
|
||||
|
||||
init {
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
GlobalScope.launch {
|
||||
var time = System.currentTimeMillis()
|
||||
@Suppress("ControlFlowWithEmptyBody")
|
||||
while (true) {
|
||||
val iterator = channels.iterator()
|
||||
iterator.forEach { reference ->
|
||||
val channel = reference.get()
|
||||
if (channel == null) {
|
||||
iterator.remove()
|
||||
return@forEach
|
||||
}
|
||||
if (channel.trySend(Unit).isClosed) {
|
||||
channel.close()
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
delay(delayMillis - (System.currentTimeMillis() - time))
|
||||
time = System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun get(capacity: Int = this.capacity): ReceiveChannel<Unit> {
|
||||
val channel = Channel<Unit>(capacity)
|
||||
channels.add(WeakReference(channel))
|
||||
return channel
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ import cn.tursom.core.forAllFields
|
||||
import cn.tursom.core.isInheritanceFrom
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.ReceiveChannel
|
||||
import kotlinx.coroutines.channels.produce
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
@ -234,4 +236,27 @@ suspend fun <T> runOnUiThread(
|
||||
action: suspend CoroutineScope.() -> T
|
||||
): T {
|
||||
return withContext(coroutineContext + Dispatchers.Main, action)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class, DelicateCoroutinesApi::class)
|
||||
fun bufferTicker(
|
||||
delayMillis: Long,
|
||||
capacity: Int = 16,
|
||||
waitTimeout: Long = 0,
|
||||
initialDelayMillis: Long = delayMillis,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
): ReceiveChannel<Unit> {
|
||||
return GlobalScope.produce(Dispatchers.Unconfined + context, capacity = capacity) {
|
||||
if (initialDelayMillis > 0) {
|
||||
delay(initialDelayMillis)
|
||||
}
|
||||
while (true) {
|
||||
if (waitTimeout > 0) withTimeoutOrNull(waitTimeout) {
|
||||
channel.send(Unit)
|
||||
} ?: return@produce else {
|
||||
channel.send(Unit)
|
||||
}
|
||||
delay(delayMillis)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,45 +3,45 @@ package cn.tursom.core.coroutine.lock
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
class AsyncMutexLock : AsyncLock {
|
||||
private val lock = AtomicBoolean(false)
|
||||
private val waitList = AsyncWaitList()
|
||||
private val lock = AtomicBoolean(false)
|
||||
private val waitList = AsyncWaitList()
|
||||
|
||||
suspend fun wait() {
|
||||
var loopTime = 20
|
||||
while (loopTime-- > 0) if (!lock.get()) return
|
||||
waitList.wait()
|
||||
waitList.resume()
|
||||
}
|
||||
suspend fun wait() {
|
||||
var loopTime = 20
|
||||
while (loopTime-- > 0) if (!lock.get()) return
|
||||
waitList.wait()
|
||||
waitList.resume()
|
||||
}
|
||||
|
||||
override suspend fun sync(block: suspend () -> Unit) {
|
||||
invoke(block)
|
||||
}
|
||||
override suspend fun sync(block: suspend () -> Unit) {
|
||||
invoke(block)
|
||||
}
|
||||
|
||||
override suspend fun isLock(): Boolean {
|
||||
return lock.get()
|
||||
}
|
||||
override suspend fun isLock(): Boolean {
|
||||
return lock.get()
|
||||
}
|
||||
|
||||
override suspend operator fun <T> invoke(block: suspend () -> T): T {
|
||||
lock.lock()
|
||||
try {
|
||||
return block()
|
||||
} finally {
|
||||
lock.release()
|
||||
}
|
||||
}
|
||||
override suspend operator fun <T> invoke(block: suspend () -> T): T {
|
||||
lock.lock()
|
||||
try {
|
||||
return block()
|
||||
} finally {
|
||||
lock.release()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun AtomicBoolean.lock() {
|
||||
var loopTime = 20
|
||||
while (loopTime-- > 0) if (compareAndSet(false, true)) return
|
||||
waitList.wait()
|
||||
}
|
||||
private suspend fun AtomicBoolean.lock() {
|
||||
var loopTime = 20
|
||||
while (loopTime-- > 0) if (compareAndSet(false, true)) return
|
||||
waitList.wait()
|
||||
}
|
||||
|
||||
override suspend fun AtomicBoolean.release() {
|
||||
if (waitList.notEmpty) {
|
||||
waitList.resume()
|
||||
} else {
|
||||
set(false)
|
||||
}
|
||||
}
|
||||
override suspend fun AtomicBoolean.release() {
|
||||
if (waitList.notEmpty) {
|
||||
waitList.resume()
|
||||
} else {
|
||||
set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,35 +7,35 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class AsyncReadFirstRWLock() : AsyncRWLock {
|
||||
private val lock = AsyncMutexLock()
|
||||
private val readNumber = AtomicInteger(0)
|
||||
private val writeList = AsyncWaitList()
|
||||
private val lock = AsyncMutexLock()
|
||||
private val readNumber = AtomicInteger(0)
|
||||
private val writeList = AsyncWaitList()
|
||||
|
||||
override suspend fun <T> doRead(block: suspend () -> T): T {
|
||||
readNumber.incrementAndGet()
|
||||
lock.wait()
|
||||
try {
|
||||
return block()
|
||||
} finally {
|
||||
readNumber.decrementAndGet()
|
||||
if (readNumber.get() == 0) writeList.resume()
|
||||
}
|
||||
}
|
||||
override suspend fun <T> doRead(block: suspend () -> T): T {
|
||||
readNumber.incrementAndGet()
|
||||
lock.wait()
|
||||
try {
|
||||
return block()
|
||||
} finally {
|
||||
readNumber.decrementAndGet()
|
||||
if (readNumber.get() == 0) writeList.resume()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun <T> doWrite(block: suspend () -> T): T {
|
||||
return invoke(block)
|
||||
}
|
||||
override suspend fun <T> doWrite(block: suspend () -> T): T {
|
||||
return invoke(block)
|
||||
}
|
||||
|
||||
override suspend fun sync(block: suspend () -> Unit) {
|
||||
invoke(block)
|
||||
}
|
||||
override suspend fun sync(block: suspend () -> Unit) {
|
||||
invoke(block)
|
||||
}
|
||||
|
||||
override suspend fun <T> invoke(block: suspend () -> T): T {
|
||||
while (readNumber.get() != 0) writeList.wait()
|
||||
return lock { block() }
|
||||
}
|
||||
override suspend fun <T> invoke(block: suspend () -> T): T {
|
||||
while (readNumber.get() != 0) writeList.wait()
|
||||
return lock { block() }
|
||||
}
|
||||
|
||||
override suspend fun isLock(): Boolean {
|
||||
return lock.isLock()
|
||||
}
|
||||
override suspend fun isLock(): Boolean {
|
||||
return lock.isLock()
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,34 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":"))
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-buffer"))
|
||||
implementation(project(":ts-core:ts-hash"))
|
||||
implementation(project(":"))
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-buffer"))
|
||||
implementation(project(":ts-core:ts-hash"))
|
||||
}
|
||||
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||
|
||||
tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,18 @@ package cn.tursom.core.datastruct
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
class KPropertyEntries(val target: Any, private val propertyMap: Map<String, KProperty1<Any, *>> = KPropertyValueMap[target]) : Set<Map.Entry<String, Any?>> {
|
||||
override val size: Int = propertyMap.size
|
||||
override fun isEmpty(): Boolean = propertyMap.isEmpty()
|
||||
override fun iterator(): Iterator<Map.Entry<String, Any?>> = KPropertyEntriesIterator(target, propertyMap)
|
||||
override fun contains(element: Map.Entry<String, Any?>): Boolean = propertyMap[element.key]?.get(target) == element.value
|
||||
override fun containsAll(elements: Collection<Map.Entry<String, Any?>>): Boolean {
|
||||
elements.forEach { if (!contains(it)) return false }
|
||||
return true
|
||||
}
|
||||
class KPropertyEntries(
|
||||
val target: Any,
|
||||
private val propertyMap: Map<String, KProperty1<Any, *>> = KPropertyValueMap[target]
|
||||
) : Set<Map.Entry<String, Any?>> {
|
||||
override val size: Int = propertyMap.size
|
||||
override fun isEmpty(): Boolean = propertyMap.isEmpty()
|
||||
override fun iterator(): Iterator<Map.Entry<String, Any?>> = KPropertyEntriesIterator(target, propertyMap)
|
||||
override fun contains(element: Map.Entry<String, Any?>): Boolean =
|
||||
propertyMap[element.key]?.get(target) == element.value
|
||||
|
||||
override fun containsAll(elements: Collection<Map.Entry<String, Any?>>): Boolean {
|
||||
elements.forEach { if (!contains(it)) return false }
|
||||
return true
|
||||
}
|
||||
}
|
@ -2,19 +2,22 @@ package cn.tursom.core.datastruct
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
class KPropertyValueCollection(val target: Any, private val propertyMap: Map<String, KProperty1<Any, *>> = KPropertyValueMap[target]) : Collection<Any?> {
|
||||
override val size: Int get() = propertyMap.size
|
||||
override fun isEmpty(): Boolean = propertyMap.isEmpty()
|
||||
override fun iterator(): Iterator<Any?> = KPropertyValueCollectionIterator(target, propertyMap)
|
||||
class KPropertyValueCollection(
|
||||
val target: Any,
|
||||
private val propertyMap: Map<String, KProperty1<Any, *>> = KPropertyValueMap[target]
|
||||
) : Collection<Any?> {
|
||||
override val size: Int get() = propertyMap.size
|
||||
override fun isEmpty(): Boolean = propertyMap.isEmpty()
|
||||
override fun iterator(): Iterator<Any?> = KPropertyValueCollectionIterator(target, propertyMap)
|
||||
|
||||
override fun contains(element: Any?): Boolean {
|
||||
propertyMap.forEach { (_, u) -> if (u.get(target) == element) return true }
|
||||
return false
|
||||
}
|
||||
override fun contains(element: Any?): Boolean {
|
||||
propertyMap.forEach { (_, u) -> if (u.get(target) == element) return true }
|
||||
return false
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<Any?>): Boolean {
|
||||
val mutableElements = elements.toMutableSet()
|
||||
propertyMap.forEach { (_, u) -> mutableElements.remove(u.get(target)) }
|
||||
return mutableElements.isEmpty()
|
||||
}
|
||||
override fun containsAll(elements: Collection<Any?>): Boolean {
|
||||
val mutableElements = elements.toMutableSet()
|
||||
propertyMap.forEach { (_, u) -> mutableElements.remove(u.get(target)) }
|
||||
return mutableElements.isEmpty()
|
||||
}
|
||||
}
|
@ -7,34 +7,34 @@ import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
|
||||
class KPropertyValueMap(val target: Any) : Map<String, Any?> {
|
||||
private val propertyMap = Companion[target]
|
||||
override val entries: Set<Map.Entry<String, Any?>> = KPropertyEntries(target, propertyMap)
|
||||
override val keys: Set<String> get() = propertyMap.keys
|
||||
override val size: Int get() = propertyMap.size
|
||||
override val values: Collection<Any?> = KPropertyValueCollection(target, propertyMap)
|
||||
override fun containsKey(key: String): Boolean = propertyMap.containsKey(key)
|
||||
override fun containsValue(value: Any?): Boolean = values.contains(value)
|
||||
override fun get(key: String): Any? = propertyMap[key]?.get(target)
|
||||
override fun isEmpty(): Boolean = propertyMap.isEmpty()
|
||||
private val propertyMap = Companion[target]
|
||||
override val entries: Set<Map.Entry<String, Any?>> = KPropertyEntries(target, propertyMap)
|
||||
override val keys: Set<String> get() = propertyMap.keys
|
||||
override val size: Int get() = propertyMap.size
|
||||
override val values: Collection<Any?> = KPropertyValueCollection(target, propertyMap)
|
||||
override fun containsKey(key: String): Boolean = propertyMap.containsKey(key)
|
||||
override fun containsValue(value: Any?): Boolean = values.contains(value)
|
||||
override fun get(key: String): Any? = propertyMap[key]?.get(target)
|
||||
override fun isEmpty(): Boolean = propertyMap.isEmpty()
|
||||
|
||||
companion object {
|
||||
private val propertiesMapCache = ReadWriteMap(HashMap<KClass<*>, SoftArrayMap<String, KProperty1<Any, *>>>())
|
||||
operator fun get(obj: Any) = get(obj::class)
|
||||
operator fun get(clazz: KClass<*>): SoftArrayMap<String, KProperty1<Any, *>> {
|
||||
var map = propertiesMapCache[clazz]
|
||||
if (map == null) {
|
||||
map = clazz.memberProperties.uncheckedCast<Collection<KProperty1<Any, *>>>().let { properties ->
|
||||
val valueMap = SoftArrayMap<String, KProperty1<Any, *>>(properties.size)
|
||||
properties.forEach {
|
||||
it.isAccessible = true
|
||||
valueMap[it.name] = it
|
||||
}
|
||||
valueMap
|
||||
}
|
||||
propertiesMapCache[clazz] = map
|
||||
}
|
||||
return map
|
||||
companion object {
|
||||
private val propertiesMapCache = ReadWriteMap(HashMap<KClass<*>, SoftArrayMap<String, KProperty1<Any, *>>>())
|
||||
operator fun get(obj: Any) = get(obj::class)
|
||||
operator fun get(clazz: KClass<*>): SoftArrayMap<String, KProperty1<Any, *>> {
|
||||
var map = propertiesMapCache[clazz]
|
||||
if (map == null) {
|
||||
map = clazz.memberProperties.uncheckedCast<Collection<KProperty1<Any, *>>>().let { properties ->
|
||||
val valueMap = SoftArrayMap<String, KProperty1<Any, *>>(properties.size)
|
||||
properties.forEach {
|
||||
it.isAccessible = true
|
||||
valueMap[it.name] = it
|
||||
}
|
||||
valueMap
|
||||
}
|
||||
propertiesMapCache[clazz] = map
|
||||
}
|
||||
return map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,76 +5,76 @@ import kotlin.reflect.full.memberProperties
|
||||
|
||||
@Suppress("unused")
|
||||
class MappedValue<V : Any>(val value: V) : Map<String, Any?> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val properties = (value::class as KClass<V>).memberProperties.associateBy { it.name }
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val properties = (value::class as KClass<V>).memberProperties.associateBy { it.name }
|
||||
|
||||
override val entries: Set<Map.Entry<String, Any?>> = Entries()
|
||||
override val keys: Set<String> = Keys()
|
||||
override val size: Int get() = properties.size
|
||||
override val values: Collection<Any?> = Values()
|
||||
override val entries: Set<Map.Entry<String, Any?>> = Entries()
|
||||
override val keys: Set<String> = Keys()
|
||||
override val size: Int get() = properties.size
|
||||
override val values: Collection<Any?> = Values()
|
||||
|
||||
override fun containsKey(key: String): Boolean = properties.containsKey(key)
|
||||
override fun containsValue(value: Any?): Boolean {
|
||||
properties.forEach { (_, u) ->
|
||||
if (u.get(this.value) == value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
override fun containsKey(key: String): Boolean = properties.containsKey(key)
|
||||
override fun containsValue(value: Any?): Boolean {
|
||||
properties.forEach { (_, u) ->
|
||||
if (u.get(this.value) == value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun get(key: String): Any? = properties[key]?.get(value)
|
||||
override fun isEmpty(): Boolean = properties.isEmpty()
|
||||
|
||||
private inner class Entries : Set<Map.Entry<String, Any?>> {
|
||||
override val size: Int get() = this@MappedValue.size
|
||||
override fun isEmpty(): Boolean = this@MappedValue.isEmpty()
|
||||
override fun iterator(): Iterator<Map.Entry<String, Any?>> = MapIterator()
|
||||
override fun contains(element: Map.Entry<String, Any?>): Boolean = this@MappedValue[element.key] == element.value
|
||||
override fun containsAll(elements: Collection<Map.Entry<String, Any?>>): Boolean {
|
||||
elements.forEach {
|
||||
if (!contains(it))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private inner class MapIterator : Iterator<Map.Entry<String, Any?>> {
|
||||
private val iterator = properties.iterator()
|
||||
override fun hasNext(): Boolean = iterator.hasNext()
|
||||
override fun next(): Map.Entry<String, Any?> = iterator.next().let { Entry(it.key, it.value.get(value)) }
|
||||
}
|
||||
|
||||
private class Entry(override val key: String, override val value: Any?) : Map.Entry<String, Any?>
|
||||
|
||||
private inner class Values : Collection<Any?> {
|
||||
override val size: Int get() = this@MappedValue.size
|
||||
override fun isEmpty(): Boolean = this@MappedValue.isEmpty()
|
||||
override fun iterator(): Iterator<Any?> = ValuesIterator(this@MappedValue.iterator())
|
||||
|
||||
override fun contains(element: Any?): Boolean {
|
||||
properties.forEach { (_, u) -> if (u == element) return true }
|
||||
return false
|
||||
}
|
||||
|
||||
override fun get(key: String): Any? = properties[key]?.get(value)
|
||||
override fun isEmpty(): Boolean = properties.isEmpty()
|
||||
|
||||
private inner class Entries : Set<Map.Entry<String, Any?>> {
|
||||
override val size: Int get() = this@MappedValue.size
|
||||
override fun isEmpty(): Boolean = this@MappedValue.isEmpty()
|
||||
override fun iterator(): Iterator<Map.Entry<String, Any?>> = MapIterator()
|
||||
override fun contains(element: Map.Entry<String, Any?>): Boolean = this@MappedValue[element.key] == element.value
|
||||
override fun containsAll(elements: Collection<Map.Entry<String, Any?>>): Boolean {
|
||||
elements.forEach {
|
||||
if (!contains(it))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
override fun containsAll(elements: Collection<Any?>): Boolean {
|
||||
elements.forEach {
|
||||
if (!contains(it)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private inner class MapIterator : Iterator<Map.Entry<String, Any?>> {
|
||||
private val iterator = properties.iterator()
|
||||
override fun hasNext(): Boolean = iterator.hasNext()
|
||||
override fun next(): Map.Entry<String, Any?> = iterator.next().let { Entry(it.key, it.value.get(value)) }
|
||||
}
|
||||
private class ValuesIterator(val iterator: Iterator<Map.Entry<String, Any?>>) : Iterator<Any?> {
|
||||
override fun hasNext(): Boolean = iterator.hasNext()
|
||||
override fun next(): Any? = iterator.next().value
|
||||
}
|
||||
|
||||
private class Entry(override val key: String, override val value: Any?) : Map.Entry<String, Any?>
|
||||
|
||||
private inner class Values : Collection<Any?> {
|
||||
override val size: Int get() = this@MappedValue.size
|
||||
override fun isEmpty(): Boolean = this@MappedValue.isEmpty()
|
||||
override fun iterator(): Iterator<Any?> = ValuesIterator(this@MappedValue.iterator())
|
||||
|
||||
override fun contains(element: Any?): Boolean {
|
||||
properties.forEach { (_, u) -> if (u == element) return true }
|
||||
return false
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<Any?>): Boolean {
|
||||
elements.forEach {
|
||||
if (!contains(it)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private class ValuesIterator(val iterator: Iterator<Map.Entry<String, Any?>>) : Iterator<Any?> {
|
||||
override fun hasNext(): Boolean = iterator.hasNext()
|
||||
override fun next(): Any? = iterator.next().value
|
||||
}
|
||||
|
||||
private inner class Keys : Set<String> {
|
||||
override val size: Int get() = this@MappedValue.size
|
||||
override fun isEmpty(): Boolean = this@MappedValue.isEmpty()
|
||||
override fun contains(element: String): Boolean = properties.keys.contains(element)
|
||||
override fun containsAll(elements: Collection<String>): Boolean = properties.keys.containsAll(elements)
|
||||
override fun iterator(): Iterator<String> = properties.keys.iterator()
|
||||
}
|
||||
private inner class Keys : Set<String> {
|
||||
override val size: Int get() = this@MappedValue.size
|
||||
override fun isEmpty(): Boolean = this@MappedValue.isEmpty()
|
||||
override fun contains(element: String): Boolean = properties.keys.contains(element)
|
||||
override fun containsAll(elements: Collection<String>): Boolean = properties.keys.containsAll(elements)
|
||||
override fun iterator(): Iterator<String> = properties.keys.iterator()
|
||||
}
|
||||
}
|
@ -1,32 +1,32 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":ts-core"))
|
||||
compileOnly(group = "io.netty", name = "netty-all", version = "4.1.43.Final")
|
||||
implementation(project(":ts-core"))
|
||||
compileOnly(group = "io.netty", name = "netty-all", version = "4.1.43.Final")
|
||||
}
|
||||
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||
|
||||
tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,22 +4,22 @@ import cn.tursom.core.uncheckedCast
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
class ThreadLocalMutableDelegatedField<in T, V>(
|
||||
private val threadLocal: ThreadLocal<V?> = ThreadLocal(),
|
||||
private val threadLocal: ThreadLocal<V?> = ThreadLocal(),
|
||||
) : MutableDelegatedField<T, V?> {
|
||||
|
||||
override fun <K> get(key: DelegatedFieldAttachmentKey<K>): K? {
|
||||
return if (key == Companion) {
|
||||
threadLocal.uncheckedCast()
|
||||
} else {
|
||||
super.get(key)
|
||||
}
|
||||
override fun <K> get(key: DelegatedFieldAttachmentKey<K>): K? {
|
||||
return if (key == Companion) {
|
||||
threadLocal.uncheckedCast()
|
||||
} else {
|
||||
super.get(key)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setValue(value: V?) = threadLocal.set(value)
|
||||
override fun getValue(): V? = threadLocal.get()
|
||||
override fun setValue(value: V?) = threadLocal.set(value)
|
||||
override fun getValue(): V? = threadLocal.get()
|
||||
|
||||
companion object : DelegatedFieldAttachmentKey<ThreadLocal<*>> {
|
||||
fun <T> getKey() = this.uncheckedCast<DelegatedFieldAttachmentKey<ThreadLocal<T>>>()
|
||||
fun <T> getKey(property: KProperty0<T>) = this.uncheckedCast<DelegatedFieldAttachmentKey<ThreadLocal<T>>>()
|
||||
}
|
||||
companion object : DelegatedFieldAttachmentKey<ThreadLocal<*>> {
|
||||
fun <T> getKey() = this.uncheckedCast<DelegatedFieldAttachmentKey<ThreadLocal<T>>>()
|
||||
fun <T> getKey(property: KProperty0<T>) = this.uncheckedCast<DelegatedFieldAttachmentKey<ThreadLocal<T>>>()
|
||||
}
|
||||
}
|
@ -1,32 +1,32 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-delegation"))
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-delegation"))
|
||||
}
|
||||
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||
|
||||
tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cn.tursom.core.delegation.observer
|
||||
|
||||
interface ListenableListener<out T, V> : Listener<T, V> {
|
||||
infix fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V>
|
||||
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ListenableListener<T, V>
|
||||
infix fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V>
|
||||
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ListenableListener<T, V>
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.core.delegation.observer
|
||||
|
||||
interface Listener<out T, V> {
|
||||
fun cancel(): Boolean
|
||||
infix fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Listener<T, V>
|
||||
infix fun finally(handler: T.(old: V, new: V) -> Unit): Listener<T, V>
|
||||
fun cancel(): Boolean
|
||||
infix fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Listener<T, V>
|
||||
infix fun finally(handler: T.(old: V, new: V) -> Unit): Listener<T, V>
|
||||
}
|
@ -1,9 +1,14 @@
|
||||
package cn.tursom.core.delegation.observer
|
||||
|
||||
class UnmonitoredFieldException : Exception {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(message, cause, enableSuppression, writableStackTrace)
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||
message,
|
||||
cause,
|
||||
enableSuppression,
|
||||
writableStackTrace
|
||||
)
|
||||
}
|
@ -1,34 +1,34 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-buffer"))
|
||||
implementation(project(":ts-core:ts-pool"))
|
||||
implementation(project(":ts-core:ts-datastruct"))
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-buffer"))
|
||||
implementation(project(":ts-core:ts-pool"))
|
||||
implementation(project(":ts-core:ts-datastruct"))
|
||||
}
|
||||
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||
|
||||
tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,32 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-buffer"))
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-buffer"))
|
||||
}
|
||||
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||
|
||||
tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,11 @@ object Json {
|
||||
|
||||
private fun jumpWhitespace(content: JsonParseContent) {
|
||||
@Suppress("ControlFlowWithEmptyBody")
|
||||
if (jumpWhitespaceLoopCondition(content.json, content.index)) while (jumpWhitespaceLoopCondition(content.json, ++content.index));
|
||||
if (jumpWhitespaceLoopCondition(content.json, content.index)) while (jumpWhitespaceLoopCondition(
|
||||
content.json,
|
||||
++content.index
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private fun charToInt(char: Char): Int {
|
||||
|
@ -8,29 +8,29 @@ import ch.qos.logback.core.spi.AppenderAttachableImpl
|
||||
import cn.tursom.core.delegation.ReflectionDelegatedField.Companion.superField
|
||||
|
||||
class AsyncAppender : AsyncAppenderBase<ILoggingEvent>() {
|
||||
private var includeCallerData = false
|
||||
private val aai: AppenderAttachableImpl<ILoggingEvent> by superField("aai")
|
||||
private var appenderCount: Int by superField("appenderCount")
|
||||
private var includeCallerData = false
|
||||
private val aai: AppenderAttachableImpl<ILoggingEvent> by superField("aai")
|
||||
private var appenderCount: Int by superField("appenderCount")
|
||||
|
||||
/**
|
||||
* Events of level TRACE, DEBUG and INFO are deemed to be discardable.
|
||||
* @param event
|
||||
* @return true if the event is of level TRACE, DEBUG or INFO false otherwise.
|
||||
*/
|
||||
override fun isDiscardable(event: ILoggingEvent): Boolean {
|
||||
val level = event.level
|
||||
return level.toInt() <= Level.INFO_INT
|
||||
}
|
||||
/**
|
||||
* Events of level TRACE, DEBUG and INFO are deemed to be discardable.
|
||||
* @param event
|
||||
* @return true if the event is of level TRACE, DEBUG or INFO false otherwise.
|
||||
*/
|
||||
override fun isDiscardable(event: ILoggingEvent): Boolean {
|
||||
val level = event.level
|
||||
return level.toInt() <= Level.INFO_INT
|
||||
}
|
||||
|
||||
override fun preprocess(eventObject: ILoggingEvent) {
|
||||
eventObject.prepareForDeferredProcessing()
|
||||
if (includeCallerData) eventObject.callerData
|
||||
}
|
||||
override fun preprocess(eventObject: ILoggingEvent) {
|
||||
eventObject.prepareForDeferredProcessing()
|
||||
if (includeCallerData) eventObject.callerData
|
||||
}
|
||||
|
||||
override fun addAppender(newAppender: Appender<ILoggingEvent>) {
|
||||
addInfo("Attaching appender named [${newAppender.name}] to AsyncAppender.")
|
||||
aai.addAppender(newAppender)
|
||||
appenderCount++
|
||||
}
|
||||
override fun addAppender(newAppender: Appender<ILoggingEvent>) {
|
||||
addInfo("Attaching appender named [${newAppender.name}] to AsyncAppender.")
|
||||
aai.addAppender(newAppender)
|
||||
appenderCount++
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,5 +40,6 @@ data class GroupEmailData(
|
||||
transport.close()
|
||||
}
|
||||
|
||||
fun clone(): GroupEmailData = GroupEmailData(host, port, name, password, from, to, subject, html, text, image, attachment)
|
||||
fun clone(): GroupEmailData =
|
||||
GroupEmailData(host, port, name, password, from, to, subject, html, text, image, attachment)
|
||||
}
|
@ -108,7 +108,13 @@ fun getText(message: Message): String? = when (val content: Any = message.conten
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun forEachUnreadMail(host: String, port: Int, account: String, password: String, onMsg: (from: InternetAddress, msg: String) -> Boolean) {
|
||||
fun forEachUnreadMail(
|
||||
host: String,
|
||||
port: Int,
|
||||
account: String,
|
||||
password: String,
|
||||
onMsg: (from: InternetAddress, msg: String) -> Boolean
|
||||
) {
|
||||
forEachMail(host, port, account, password) { message ->
|
||||
// 跳过已读邮件
|
||||
if (message.flags.contains(Flags.Flag.SEEN)) return@forEachMail
|
||||
|
@ -33,9 +33,11 @@ class WebSocketClientHandshakerAdapter<T : WebSocketClient<T, H>, H : WebSocketH
|
||||
handler.onOpen(client)
|
||||
return
|
||||
} else {
|
||||
throw Exception("Unexpected FullHttpResponse (getStatus=${msg.status()}, content=${
|
||||
msg.content().toString(CharsetUtil.UTF_8)
|
||||
})")
|
||||
throw Exception(
|
||||
"Unexpected FullHttpResponse (getStatus=${msg.status()}, content=${
|
||||
msg.content().toString(CharsetUtil.UTF_8)
|
||||
})"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,75 +3,78 @@ package cn.tursom.core.xml
|
||||
import cn.tursom.core.xml.interfaces.*
|
||||
|
||||
object XmlDocument {
|
||||
fun tag(name: String? = null, action: (TextPotableXmlElement.() -> Unit)? = null): TextXmlElement {
|
||||
val textXml = TextXml()
|
||||
if (name != null) textXml.name = name
|
||||
if (action != null) {
|
||||
textXml.action()
|
||||
}
|
||||
return textXml
|
||||
}
|
||||
fun tag(name: String? = null, action: (TextPotableXmlElement.() -> Unit)? = null): TextXmlElement {
|
||||
val textXml = TextXml()
|
||||
if (name != null) textXml.name = name
|
||||
if (action != null) {
|
||||
textXml.action()
|
||||
}
|
||||
return textXml
|
||||
}
|
||||
|
||||
fun text(name: String? = null, action: (TextPotableXmlElement.() -> String?)? = null): TextXmlElement {
|
||||
val textXml = TextXml()
|
||||
if (name != null) textXml.name = name
|
||||
val text = action?.let { textXml.it() }
|
||||
if (text != null) textXml.text = text
|
||||
return textXml
|
||||
}
|
||||
fun text(name: String? = null, action: (TextPotableXmlElement.() -> String?)? = null): TextXmlElement {
|
||||
val textXml = TextXml()
|
||||
if (name != null) textXml.name = name
|
||||
val text = action?.let { textXml.it() }
|
||||
if (text != null) textXml.text = text
|
||||
return textXml
|
||||
}
|
||||
|
||||
fun text(name: String? = null, text: String): TextXmlElement {
|
||||
val textXml = TextXml()
|
||||
if (name != null) textXml.name = name
|
||||
textXml.text = text
|
||||
return textXml
|
||||
}
|
||||
fun text(name: String? = null, text: String): TextXmlElement {
|
||||
val textXml = TextXml()
|
||||
if (name != null) textXml.name = name
|
||||
textXml.text = text
|
||||
return textXml
|
||||
}
|
||||
|
||||
fun subElement(name: String? = null, action: (ElementContainerPotableXmlElement.() -> Unit)? = null): ElementContainerXmlElement {
|
||||
val container = ElementContainer()
|
||||
if (name != null) container.name = name
|
||||
if (action != null) {
|
||||
container.action()
|
||||
}
|
||||
return container
|
||||
}
|
||||
fun subElement(
|
||||
name: String? = null,
|
||||
action: (ElementContainerPotableXmlElement.() -> Unit)? = null
|
||||
): ElementContainerXmlElement {
|
||||
val container = ElementContainer()
|
||||
if (name != null) container.name = name
|
||||
if (action != null) {
|
||||
container.action()
|
||||
}
|
||||
return container
|
||||
}
|
||||
|
||||
operator fun invoke(
|
||||
advanceIndentation: String = " ",
|
||||
indentation: String = "",
|
||||
action: XmlDocument.() -> XmlElement
|
||||
): String {
|
||||
return this.action().toString(StringBuilder(), indentation, advanceIndentation)
|
||||
}
|
||||
operator fun invoke(
|
||||
advanceIndentation: String = " ",
|
||||
indentation: String = "",
|
||||
action: XmlDocument.() -> XmlElement
|
||||
): String {
|
||||
return this.action().toString(StringBuilder(), indentation, advanceIndentation)
|
||||
}
|
||||
|
||||
class TextXml(override var name: String = "Text") : TextPotableXmlElement {
|
||||
override var text: String = ""
|
||||
class TextXml(override var name: String = "Text") : TextPotableXmlElement {
|
||||
override var text: String = ""
|
||||
|
||||
override val attribute: HashMap<String, String> = HashMap()
|
||||
override val attribute: HashMap<String, String> = HashMap()
|
||||
|
||||
override fun setAttribute(key: String, value: String) {
|
||||
attribute[key] = value
|
||||
}
|
||||
}
|
||||
override fun setAttribute(key: String, value: String) {
|
||||
attribute[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
class ElementContainer(override var name: String = "ElementContainer") : ElementContainerPotableXmlElement {
|
||||
override val attribute: HashMap<String, String> = HashMap()
|
||||
override val subElement: ArrayList<XmlElement> = ArrayList()
|
||||
override val size: Int get() = subElement.size
|
||||
class ElementContainer(override var name: String = "ElementContainer") : ElementContainerPotableXmlElement {
|
||||
override val attribute: HashMap<String, String> = HashMap()
|
||||
override val subElement: ArrayList<XmlElement> = ArrayList()
|
||||
override val size: Int get() = subElement.size
|
||||
|
||||
override fun addSubElement(element: XmlElement): ElementContainerPotableXmlElement {
|
||||
subElement.add(element)
|
||||
return this
|
||||
}
|
||||
override fun addSubElement(element: XmlElement): ElementContainerPotableXmlElement {
|
||||
subElement.add(element)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun setAttribute(key: String, value: String) {
|
||||
attribute[key] = value
|
||||
}
|
||||
override fun setAttribute(key: String, value: String) {
|
||||
attribute[key] = value
|
||||
}
|
||||
|
||||
override fun removeElement(index: Int): ElementContainerPotableXmlElement {
|
||||
subElement.removeAt(index)
|
||||
return this
|
||||
}
|
||||
}
|
||||
override fun removeElement(index: Int): ElementContainerPotableXmlElement {
|
||||
subElement.removeAt(index)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.core.xml
|
||||
|
||||
enum class ElementTarget {
|
||||
Attribute, ElementText, SubElement
|
||||
Attribute, ElementText, SubElement
|
||||
}
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
|
@ -1,12 +1,12 @@
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface ElementContainerPotableXmlElement : ElementContainerXmlElement, PotableXmlElement {
|
||||
val size: Int
|
||||
val size: Int
|
||||
|
||||
fun addSubElement(element: XmlElement): ElementContainerPotableXmlElement
|
||||
operator fun plus(element: XmlElement): ElementContainerPotableXmlElement = addSubElement(element)
|
||||
operator fun XmlElement.unaryPlus() = addSubElement(this)
|
||||
fun addSubElement(element: XmlElement): ElementContainerPotableXmlElement
|
||||
operator fun plus(element: XmlElement): ElementContainerPotableXmlElement = addSubElement(element)
|
||||
operator fun XmlElement.unaryPlus() = addSubElement(this)
|
||||
|
||||
fun removeElement(index: Int): ElementContainerPotableXmlElement
|
||||
operator fun minus(index: Int) = removeElement(index)
|
||||
fun removeElement(index: Int): ElementContainerPotableXmlElement
|
||||
operator fun minus(index: Int) = removeElement(index)
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface ElementContainerXmlElement : XmlElement {
|
||||
val subElement: List<XmlElement>
|
||||
val subElement: List<XmlElement>
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface PotableXmlElement : XmlElement {
|
||||
override var name: String
|
||||
fun setAttribute(key: String, value: String)
|
||||
operator fun set(key: String, value: String) = setAttribute(key, value)
|
||||
operator fun String.rangeTo(value: String) = setAttribute(this, value)
|
||||
override var name: String
|
||||
fun setAttribute(key: String, value: String)
|
||||
operator fun set(key: String, value: String) = setAttribute(key, value)
|
||||
operator fun String.rangeTo(value: String) = setAttribute(this, value)
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface TextPotableXmlElement : TextXmlElement, PotableXmlElement {
|
||||
override var text: String
|
||||
override var text: String
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface TextXmlElement : XmlElement {
|
||||
val text: String
|
||||
val text: String
|
||||
}
|
@ -1,51 +1,53 @@
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface XmlElement {
|
||||
val name: String
|
||||
val attribute: Map<String, String>?
|
||||
val name: String
|
||||
val attribute: Map<String, String>?
|
||||
|
||||
fun toString(
|
||||
builder: StringBuilder,
|
||||
indentation: String,
|
||||
advanceIndentation: String
|
||||
): String {
|
||||
builder.append(indentation)
|
||||
when (this) {
|
||||
is TextXmlElement -> {
|
||||
builder.append(if (text.isEmpty())
|
||||
"<${getElementHead()} />"
|
||||
else
|
||||
"<${getElementHead()}>${text}</${name}>")
|
||||
}
|
||||
is ElementContainerXmlElement -> {
|
||||
if (subElement.isEmpty()) {
|
||||
builder.append("<${getElementHead()}></${getElementHead()}>")
|
||||
} else {
|
||||
builder.append("<${getElementHead()}>\n")
|
||||
subElement.forEach {
|
||||
it.toString(builder, indentation + advanceIndentation, advanceIndentation)
|
||||
}
|
||||
builder.append("$indentation</${name}>")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
builder.append("<${getElementHead()} />")
|
||||
}
|
||||
}
|
||||
builder.append('\n')
|
||||
return builder.toString()
|
||||
}
|
||||
fun toString(
|
||||
builder: StringBuilder,
|
||||
indentation: String,
|
||||
advanceIndentation: String
|
||||
): String {
|
||||
builder.append(indentation)
|
||||
when (this) {
|
||||
is TextXmlElement -> {
|
||||
builder.append(
|
||||
if (text.isEmpty())
|
||||
"<${getElementHead()} />"
|
||||
else
|
||||
"<${getElementHead()}>${text}</${name}>"
|
||||
)
|
||||
}
|
||||
is ElementContainerXmlElement -> {
|
||||
if (subElement.isEmpty()) {
|
||||
builder.append("<${getElementHead()}></${getElementHead()}>")
|
||||
} else {
|
||||
builder.append("<${getElementHead()}>\n")
|
||||
subElement.forEach {
|
||||
it.toString(builder, indentation + advanceIndentation, advanceIndentation)
|
||||
}
|
||||
builder.append("$indentation</${name}>")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
builder.append("<${getElementHead()} />")
|
||||
}
|
||||
}
|
||||
builder.append('\n')
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private fun getElementHead(): String {
|
||||
val attribute = attribute ?: return name
|
||||
val sb = StringBuilder(name)
|
||||
attribute.forEach { (t, u) ->
|
||||
var value = u
|
||||
if (value.contains('&')) value = value.replace("&", "&")
|
||||
if (value.contains('"')) value = value.replace("\"", """)
|
||||
sb.append(" $t=\"$value\"")
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
private fun getElementHead(): String {
|
||||
val attribute = attribute ?: return name
|
||||
val sb = StringBuilder(name)
|
||||
attribute.forEach { (t, u) ->
|
||||
var value = u
|
||||
if (value.contains('&')) value = value.replace("&", "&")
|
||||
if (value.contains('"')) value = value.replace("\"", """)
|
||||
sb.append(" $t=\"$value\"")
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,33 +1,33 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":ts-core"))
|
||||
// 解析YAML
|
||||
implementation(group = "org.yaml", name = "snakeyaml", version = "1.28")
|
||||
implementation(project(":ts-core"))
|
||||
// 解析YAML
|
||||
implementation(group = "org.yaml", name = "snakeyaml", version = "1.28")
|
||||
}
|
||||
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||
|
||||
tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ dependencies {
|
||||
compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.6")
|
||||
}
|
||||
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||
|
||||
tasks.register("install") {
|
||||
|
@ -16,140 +16,140 @@ import kotlin.reflect.KProperty
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate", "unused", "HasPlatformType")
|
||||
object CriteriaBuilder : MongoName, BsonConverter {
|
||||
const val where = "\$where"
|
||||
fun String.asJs() = where equal this
|
||||
fun String.asObjectId() = ObjectId(this)
|
||||
const val where = "\$where"
|
||||
fun String.asJs() = where equal this
|
||||
fun String.asObjectId() = ObjectId(this)
|
||||
|
||||
infix fun where(where: String) = Criteria.where(where)
|
||||
infix fun where(where: KProperty<*>) = Criteria.where(where.mongoName)
|
||||
fun String.asWhere() = Criteria.where(this)
|
||||
fun KProperty<*>.asWhere() = mongoName.asWhere()
|
||||
infix fun where(where: String) = Criteria.where(where)
|
||||
infix fun where(where: KProperty<*>) = Criteria.where(where.mongoName)
|
||||
fun String.asWhere() = Criteria.where(this)
|
||||
fun KProperty<*>.asWhere() = mongoName.asWhere()
|
||||
|
||||
infix fun Criteria.and(where: Criteria) = Criteria().andOperator(this, where)
|
||||
infix operator fun Criteria.plus(where: Criteria) = and(where)
|
||||
infix fun Criteria.and(where: Criteria) = Criteria().andOperator(this, where)
|
||||
infix operator fun Criteria.plus(where: Criteria) = and(where)
|
||||
|
||||
private val orOperator: Criteria.(Array<out Criteria>) -> Criteria = Criteria::orOperator
|
||||
private val andOperator: Criteria.(Array<out Criteria>) -> Criteria = Criteria::andOperator
|
||||
private val orOperator: Criteria.(Array<out Criteria>) -> Criteria = Criteria::orOperator
|
||||
private val andOperator: Criteria.(Array<out Criteria>) -> Criteria = Criteria::andOperator
|
||||
|
||||
fun or(vararg where: Criteria) = Criteria().orOperator(where)
|
||||
val or: (Array<out Criteria>) -> Criteria = CriteriaBuilder::or
|
||||
fun and(vararg where: Criteria) = Criteria().andOperator(where)
|
||||
val and: (Array<out Criteria>) -> Criteria = CriteriaBuilder::and
|
||||
fun or(vararg where: Criteria) = Criteria().orOperator(where)
|
||||
val or: (Array<out Criteria>) -> Criteria = CriteriaBuilder::or
|
||||
fun and(vararg where: Criteria) = Criteria().andOperator(where)
|
||||
val and: (Array<out Criteria>) -> Criteria = CriteriaBuilder::and
|
||||
|
||||
infix fun Criteria.or(where: Criteria) = or(this, where)
|
||||
infix fun Criteria.or(where: Criteria) = or(this, where)
|
||||
|
||||
infix fun Criteria.gt(where: Any) = gt(where.bsonValue()) // >
|
||||
infix fun Criteria.gte(where: Any) = gte(where.bsonValue()) // >=
|
||||
infix fun Criteria.gt(where: Any) = gt(where.bsonValue()) // >
|
||||
infix fun Criteria.gte(where: Any) = gte(where.bsonValue()) // >=
|
||||
|
||||
infix fun Criteria.`in`(where: Collection<Any?>) = `in`(where.mapNotNull { it?.bsonValue() }) // contains
|
||||
infix fun Criteria.`is`(where: Any?) = `is`(where?.bsonValue()) // ==
|
||||
infix fun Criteria.ne(where: Any?) = ne(where?.bsonValue()) // !=
|
||||
infix fun Criteria.lt(where: Any) = lt(where.bsonValue()) // <
|
||||
infix fun Criteria.lte(where: Any) = lte(where.bsonValue()) // <=
|
||||
infix fun Criteria.nin(where: Collection<Any?>) = nin(where.bsonValue()) // not contains
|
||||
infix fun Criteria.`in`(where: Collection<Any?>) = `in`(where.mapNotNull { it?.bsonValue() }) // contains
|
||||
infix fun Criteria.`is`(where: Any?) = `is`(where?.bsonValue()) // ==
|
||||
infix fun Criteria.ne(where: Any?) = ne(where?.bsonValue()) // !=
|
||||
infix fun Criteria.lt(where: Any) = lt(where.bsonValue()) // <
|
||||
infix fun Criteria.lte(where: Any) = lte(where.bsonValue()) // <=
|
||||
infix fun Criteria.nin(where: Collection<Any?>) = nin(where.bsonValue()) // not contains
|
||||
|
||||
infix fun Criteria.all(where: Any?) = all(where?.bsonValue())
|
||||
infix fun Criteria.all(where: Collection<Any?>) = all(where.bsonValue())
|
||||
infix fun Criteria.size(s: Int) = size(s)
|
||||
infix fun Criteria.exists(b: Boolean) = exists(b)
|
||||
infix fun Criteria.type(t: Int) = type(t)
|
||||
operator fun Criteria.not() = not()
|
||||
infix fun Criteria.regex(re: String) = regex(re)
|
||||
infix fun Criteria.regex(pattern: Pattern) = regex(pattern)
|
||||
infix fun Criteria.regex(pattern: Regex) = regex(pattern.toPattern())
|
||||
infix fun Criteria.regex(regex: BsonRegularExpression) = regex(regex)
|
||||
infix fun Criteria.withinSphere(circle: Circle) = withinSphere(circle)
|
||||
infix fun Criteria.within(shape: Shape) = within(shape)
|
||||
infix fun Criteria.near(point: Point) = near(point)
|
||||
infix fun Criteria.nearSphere(point: Point) = nearSphere(point)
|
||||
infix fun Criteria.intersects(point: GeoJson<*>) = intersects(point)
|
||||
infix fun Criteria.maxDistance(maxDistance: Double) = maxDistance(maxDistance)
|
||||
infix fun Criteria.minDistance(maxDistance: Double) = minDistance(maxDistance)
|
||||
infix fun Criteria.elemMatch(c: Criteria) = elemMatch(c)
|
||||
infix fun Criteria.alike(sample: Example<*>) = alike(sample)
|
||||
infix fun Criteria.andDocumentStructureMatches(schema: MongoJsonSchema) = andDocumentStructureMatches(schema)
|
||||
infix fun Criteria.all(where: Any?) = all(where?.bsonValue())
|
||||
infix fun Criteria.all(where: Collection<Any?>) = all(where.bsonValue())
|
||||
infix fun Criteria.size(s: Int) = size(s)
|
||||
infix fun Criteria.exists(b: Boolean) = exists(b)
|
||||
infix fun Criteria.type(t: Int) = type(t)
|
||||
operator fun Criteria.not() = not()
|
||||
infix fun Criteria.regex(re: String) = regex(re)
|
||||
infix fun Criteria.regex(pattern: Pattern) = regex(pattern)
|
||||
infix fun Criteria.regex(pattern: Regex) = regex(pattern.toPattern())
|
||||
infix fun Criteria.regex(regex: BsonRegularExpression) = regex(regex)
|
||||
infix fun Criteria.withinSphere(circle: Circle) = withinSphere(circle)
|
||||
infix fun Criteria.within(shape: Shape) = within(shape)
|
||||
infix fun Criteria.near(point: Point) = near(point)
|
||||
infix fun Criteria.nearSphere(point: Point) = nearSphere(point)
|
||||
infix fun Criteria.intersects(point: GeoJson<*>) = intersects(point)
|
||||
infix fun Criteria.maxDistance(maxDistance: Double) = maxDistance(maxDistance)
|
||||
infix fun Criteria.minDistance(maxDistance: Double) = minDistance(maxDistance)
|
||||
infix fun Criteria.elemMatch(c: Criteria) = elemMatch(c)
|
||||
infix fun Criteria.alike(sample: Example<*>) = alike(sample)
|
||||
infix fun Criteria.andDocumentStructureMatches(schema: MongoJsonSchema) = andDocumentStructureMatches(schema)
|
||||
|
||||
infix fun Criteria.eq(where: Any?) = `is`(where?.bsonValue())
|
||||
infix fun Criteria.equal(where: Any?) = `is`(where?.bsonValue())
|
||||
infix fun Criteria.eq(where: Any?) = `is`(where?.bsonValue())
|
||||
infix fun Criteria.equal(where: Any?) = `is`(where?.bsonValue())
|
||||
|
||||
infix fun KProperty<*>.gt(where: Any) = asWhere() gt where // >
|
||||
infix fun KProperty<*>.gte(where: Any) = asWhere() gte where // >=
|
||||
fun KProperty<*>.`in`(vararg where: Any?) = asWhere() `in` where.asList() // contains
|
||||
infix fun KProperty<*>.`in`(where: Collection<Any?>) = asWhere() `in` where // contains
|
||||
infix fun KProperty<*>.`is`(where: Any?) = asWhere() `is` where // ==
|
||||
infix fun KProperty<*>.ne(where: Any?) = asWhere() ne where // !=
|
||||
infix fun KProperty<*>.lt(where: Any) = asWhere() lt where // <
|
||||
infix fun KProperty<*>.lte(where: Any) = asWhere() lte where // <=
|
||||
fun KProperty<*>.nin(vararg where: Any?) = asWhere() nin where.asList() // not contains
|
||||
infix fun KProperty<*>.nin(where: Collection<Any?>) = asWhere() nin where // not contains
|
||||
infix fun KProperty<*>.gt(where: Any) = asWhere() gt where // >
|
||||
infix fun KProperty<*>.gte(where: Any) = asWhere() gte where // >=
|
||||
fun KProperty<*>.`in`(vararg where: Any?) = asWhere() `in` where.asList() // contains
|
||||
infix fun KProperty<*>.`in`(where: Collection<Any?>) = asWhere() `in` where // contains
|
||||
infix fun KProperty<*>.`is`(where: Any?) = asWhere() `is` where // ==
|
||||
infix fun KProperty<*>.ne(where: Any?) = asWhere() ne where // !=
|
||||
infix fun KProperty<*>.lt(where: Any) = asWhere() lt where // <
|
||||
infix fun KProperty<*>.lte(where: Any) = asWhere() lte where // <=
|
||||
fun KProperty<*>.nin(vararg where: Any?) = asWhere() nin where.asList() // not contains
|
||||
infix fun KProperty<*>.nin(where: Collection<Any?>) = asWhere() nin where // not contains
|
||||
|
||||
infix fun KProperty<*>.all(where: Any?) = asWhere() all where
|
||||
infix fun KProperty<*>.all(where: Collection<Any?>) = asWhere() all where
|
||||
infix fun KProperty<*>.size(s: Int) = asWhere() size s
|
||||
infix fun KProperty<*>.exists(b: Boolean) = asWhere() exists b
|
||||
infix fun KProperty<*>.type(t: Int) = asWhere() type t
|
||||
operator fun KProperty<*>.not() = asWhere().not()
|
||||
infix fun KProperty<*>.regex(re: String) = asWhere() regex re
|
||||
infix fun KProperty<*>.regex(pattern: Pattern) = asWhere() regex pattern
|
||||
infix fun KProperty<*>.regex(pattern: Regex) = asWhere() regex pattern.toPattern()
|
||||
infix fun KProperty<*>.regex(regex: BsonRegularExpression) = asWhere() regex regex
|
||||
infix fun KProperty<*>.withinSphere(circle: Circle) = asWhere() withinSphere circle
|
||||
infix fun KProperty<*>.within(shape: Shape) = asWhere() within shape
|
||||
infix fun KProperty<*>.near(point: Point) = asWhere() near point
|
||||
infix fun KProperty<*>.nearSphere(point: Point) = asWhere() nearSphere point
|
||||
infix fun KProperty<*>.intersects(point: GeoJson<*>) = asWhere() intersects point
|
||||
infix fun KProperty<*>.maxDistance(maxDistance: Double) = asWhere() maxDistance maxDistance
|
||||
infix fun KProperty<*>.minDistance(maxDistance: Double) = asWhere() minDistance maxDistance
|
||||
infix fun KProperty<*>.elemMatch(c: Criteria) = asWhere() elemMatch c
|
||||
infix fun KProperty<*>.alike(sample: Example<*>) = asWhere() alike sample
|
||||
infix fun KProperty<*>.andDocumentStructureMatches(schema: MongoJsonSchema) =
|
||||
asWhere() andDocumentStructureMatches schema
|
||||
infix fun KProperty<*>.all(where: Any?) = asWhere() all where
|
||||
infix fun KProperty<*>.all(where: Collection<Any?>) = asWhere() all where
|
||||
infix fun KProperty<*>.size(s: Int) = asWhere() size s
|
||||
infix fun KProperty<*>.exists(b: Boolean) = asWhere() exists b
|
||||
infix fun KProperty<*>.type(t: Int) = asWhere() type t
|
||||
operator fun KProperty<*>.not() = asWhere().not()
|
||||
infix fun KProperty<*>.regex(re: String) = asWhere() regex re
|
||||
infix fun KProperty<*>.regex(pattern: Pattern) = asWhere() regex pattern
|
||||
infix fun KProperty<*>.regex(pattern: Regex) = asWhere() regex pattern.toPattern()
|
||||
infix fun KProperty<*>.regex(regex: BsonRegularExpression) = asWhere() regex regex
|
||||
infix fun KProperty<*>.withinSphere(circle: Circle) = asWhere() withinSphere circle
|
||||
infix fun KProperty<*>.within(shape: Shape) = asWhere() within shape
|
||||
infix fun KProperty<*>.near(point: Point) = asWhere() near point
|
||||
infix fun KProperty<*>.nearSphere(point: Point) = asWhere() nearSphere point
|
||||
infix fun KProperty<*>.intersects(point: GeoJson<*>) = asWhere() intersects point
|
||||
infix fun KProperty<*>.maxDistance(maxDistance: Double) = asWhere() maxDistance maxDistance
|
||||
infix fun KProperty<*>.minDistance(maxDistance: Double) = asWhere() minDistance maxDistance
|
||||
infix fun KProperty<*>.elemMatch(c: Criteria) = asWhere() elemMatch c
|
||||
infix fun KProperty<*>.alike(sample: Example<*>) = asWhere() alike sample
|
||||
infix fun KProperty<*>.andDocumentStructureMatches(schema: MongoJsonSchema) =
|
||||
asWhere() andDocumentStructureMatches schema
|
||||
|
||||
infix fun KProperty<*>.eq(where: Any?) = asWhere() equal where
|
||||
infix fun KProperty<*>.equal(where: Any?) = asWhere() equal where
|
||||
infix fun KProperty<*>.eq(where: Any?) = asWhere() equal where
|
||||
infix fun KProperty<*>.equal(where: Any?) = asWhere() equal where
|
||||
|
||||
infix fun String.gt(where: Any) = asWhere() gt where // >
|
||||
infix fun String.gte(where: Any) = asWhere() gte where // >=
|
||||
fun String.`in`(vararg where: Any?) = asWhere() `in` where.asList() // contains
|
||||
infix fun String.`in`(where: Collection<Any?>) = asWhere() `in` where // contains
|
||||
infix fun String.`is`(where: Any?) = asWhere() `is` where // ==
|
||||
infix fun String.ne(where: Any?) = asWhere() ne where // !=
|
||||
infix fun String.lt(where: Any) = asWhere() lt where // <
|
||||
infix fun String.lte(where: Any) = asWhere() lte where // <=
|
||||
fun String.nin(vararg where: Any?) = asWhere() nin where.asList() // not contains
|
||||
infix fun String.nin(where: Collection<Any?>) = asWhere() nin where // not contains
|
||||
infix fun String.gt(where: Any) = asWhere() gt where // >
|
||||
infix fun String.gte(where: Any) = asWhere() gte where // >=
|
||||
fun String.`in`(vararg where: Any?) = asWhere() `in` where.asList() // contains
|
||||
infix fun String.`in`(where: Collection<Any?>) = asWhere() `in` where // contains
|
||||
infix fun String.`is`(where: Any?) = asWhere() `is` where // ==
|
||||
infix fun String.ne(where: Any?) = asWhere() ne where // !=
|
||||
infix fun String.lt(where: Any) = asWhere() lt where // <
|
||||
infix fun String.lte(where: Any) = asWhere() lte where // <=
|
||||
fun String.nin(vararg where: Any?) = asWhere() nin where.asList() // not contains
|
||||
infix fun String.nin(where: Collection<Any?>) = asWhere() nin where // not contains
|
||||
|
||||
infix fun String.all(where: Any?) = asWhere() all where
|
||||
infix fun String.all(where: Collection<Any?>) = asWhere() all where
|
||||
infix fun String.size(s: Int) = asWhere() size s
|
||||
infix fun String.exists(b: Boolean) = asWhere() exists b
|
||||
infix fun String.type(t: Int) = asWhere() type t
|
||||
operator fun String.not() = asWhere().not()
|
||||
infix fun String.regex(re: String) = asWhere() regex re
|
||||
infix fun String.regex(pattern: Pattern) = asWhere() regex pattern
|
||||
infix fun String.regex(pattern: Regex) = asWhere() regex pattern.toPattern()
|
||||
infix fun String.regex(regex: BsonRegularExpression) = asWhere() regex regex
|
||||
infix fun String.withinSphere(circle: Circle) = asWhere() withinSphere circle
|
||||
infix fun String.within(shape: Shape) = asWhere() within shape
|
||||
infix fun String.near(point: Point) = asWhere() near point
|
||||
infix fun String.nearSphere(point: Point) = asWhere() nearSphere point
|
||||
infix fun String.intersects(point: GeoJson<*>) = asWhere() intersects point
|
||||
infix fun String.maxDistance(maxDistance: Double) = asWhere() maxDistance maxDistance
|
||||
infix fun String.minDistance(maxDistance: Double) = asWhere() minDistance maxDistance
|
||||
infix fun String.elemMatch(c: Criteria) = asWhere() elemMatch c
|
||||
infix fun String.alike(sample: Example<*>) = asWhere() alike sample
|
||||
infix fun String.andDocumentStructureMatches(schema: MongoJsonSchema) = asWhere() andDocumentStructureMatches schema
|
||||
infix fun String.all(where: Any?) = asWhere() all where
|
||||
infix fun String.all(where: Collection<Any?>) = asWhere() all where
|
||||
infix fun String.size(s: Int) = asWhere() size s
|
||||
infix fun String.exists(b: Boolean) = asWhere() exists b
|
||||
infix fun String.type(t: Int) = asWhere() type t
|
||||
operator fun String.not() = asWhere().not()
|
||||
infix fun String.regex(re: String) = asWhere() regex re
|
||||
infix fun String.regex(pattern: Pattern) = asWhere() regex pattern
|
||||
infix fun String.regex(pattern: Regex) = asWhere() regex pattern.toPattern()
|
||||
infix fun String.regex(regex: BsonRegularExpression) = asWhere() regex regex
|
||||
infix fun String.withinSphere(circle: Circle) = asWhere() withinSphere circle
|
||||
infix fun String.within(shape: Shape) = asWhere() within shape
|
||||
infix fun String.near(point: Point) = asWhere() near point
|
||||
infix fun String.nearSphere(point: Point) = asWhere() nearSphere point
|
||||
infix fun String.intersects(point: GeoJson<*>) = asWhere() intersects point
|
||||
infix fun String.maxDistance(maxDistance: Double) = asWhere() maxDistance maxDistance
|
||||
infix fun String.minDistance(maxDistance: Double) = asWhere() minDistance maxDistance
|
||||
infix fun String.elemMatch(c: Criteria) = asWhere() elemMatch c
|
||||
infix fun String.alike(sample: Example<*>) = asWhere() alike sample
|
||||
infix fun String.andDocumentStructureMatches(schema: MongoJsonSchema) = asWhere() andDocumentStructureMatches schema
|
||||
|
||||
infix fun String.eq(where: Any?) = asWhere() equal where
|
||||
infix fun String.equal(where: Any?) = asWhere() equal where
|
||||
infix fun String.eq(where: Any?) = asWhere() equal where
|
||||
infix fun String.equal(where: Any?) = asWhere() equal where
|
||||
|
||||
inline infix operator fun invoke(operator: CriteriaBuilder.() -> Criteria): Criteria = this.operator()
|
||||
inline infix fun query(operator: CriteriaBuilder.() -> Criteria): Query = Query(this.operator())
|
||||
inline infix fun queryObject(operator: CriteriaBuilder.() -> Criteria): Document =
|
||||
Query(this.operator()).queryObject
|
||||
inline infix operator fun invoke(operator: CriteriaBuilder.() -> Criteria): Criteria = this.operator()
|
||||
inline infix fun query(operator: CriteriaBuilder.() -> Criteria): Query = Query(this.operator())
|
||||
inline infix fun queryObject(operator: CriteriaBuilder.() -> Criteria): Document =
|
||||
Query(this.operator()).queryObject
|
||||
|
||||
inline infix fun fieldsObject(operator: CriteriaBuilder.() -> Criteria): Document =
|
||||
Query(this.operator()).fieldsObject
|
||||
inline infix fun fieldsObject(operator: CriteriaBuilder.() -> Criteria): Document =
|
||||
Query(this.operator()).fieldsObject
|
||||
|
||||
inline infix fun sortObject(operator: CriteriaBuilder.() -> Criteria): Document = Query(this.operator()).sortObject
|
||||
inline infix fun sortObject(operator: CriteriaBuilder.() -> Criteria): Document = Query(this.operator()).sortObject
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,8 @@ fun AsyncChannel.enhance(): EnhanceChannel<ByteBuffer, ByteBuffer> = EnhanceChan
|
||||
|
||||
fun ChannelReader<ByteBuffer>.lengthField(): ChannelReader<ByteBuffer> = LengthFieldBasedFrameReader(this)
|
||||
fun ChannelWriter<ByteBuffer>.lengthField(): ChannelWriter<ByteBuffer> = LengthFieldPrependWriter(this)
|
||||
fun EnhanceChannel<ByteBuffer, ByteBuffer>.lengthField(): EnhanceChannel<ByteBuffer, ByteBuffer> = LengthFieldChannel(this)
|
||||
fun EnhanceChannel<ByteBuffer, ByteBuffer>.lengthField(): EnhanceChannel<ByteBuffer, ByteBuffer> =
|
||||
LengthFieldChannel(this)
|
||||
|
||||
fun ChannelReader<ByteBuffer>.string() = StringReader(this)
|
||||
fun ChannelWriter<ByteBuffer>.string() = StringWriter(this)
|
||||
|
@ -12,6 +12,8 @@ class ByteArrayWriter(
|
||||
}
|
||||
|
||||
override suspend fun flush(timeout: Long): Long = prevWriter.flush(timeout)
|
||||
override suspend fun writeAndFlush(value: ByteArray, timeout: Long): Long = prevWriter.writeAndFlush(HeapByteBuffer(value), timeout)
|
||||
override suspend fun writeAndFlush(value: ByteArray, timeout: Long): Long =
|
||||
prevWriter.writeAndFlush(HeapByteBuffer(value), timeout)
|
||||
|
||||
override fun close() = prevWriter.close()
|
||||
}
|
@ -8,6 +8,8 @@ class StringObjectWriter(
|
||||
) : ChannelWriter<Any> {
|
||||
override suspend fun write(value: Any) = prevWriter.write(toString(value))
|
||||
override suspend fun flush(timeout: Long) = prevWriter.flush(timeout)
|
||||
override suspend fun writeAndFlush(value: Any, timeout: Long): Long = prevWriter.writeAndFlush(toString(value), timeout)
|
||||
override suspend fun writeAndFlush(value: Any, timeout: Long): Long =
|
||||
prevWriter.writeAndFlush(toString(value), timeout)
|
||||
|
||||
override fun close() = prevWriter.close()
|
||||
}
|
@ -3,20 +3,20 @@ package cn.tursom.niothread
|
||||
import java.nio.channels.SelectionKey
|
||||
|
||||
interface NioProtocol {
|
||||
@Throws(Throwable::class)
|
||||
fun handleConnect(key: SelectionKey, nioThread: NioThread) {
|
||||
}
|
||||
@Throws(Throwable::class)
|
||||
fun handleConnect(key: SelectionKey, nioThread: NioThread) {
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
fun handleRead(key: SelectionKey, nioThread: NioThread)
|
||||
@Throws(Throwable::class)
|
||||
fun handleRead(key: SelectionKey, nioThread: NioThread)
|
||||
|
||||
@Throws(Throwable::class)
|
||||
fun handleWrite(key: SelectionKey, nioThread: NioThread)
|
||||
@Throws(Throwable::class)
|
||||
fun handleWrite(key: SelectionKey, nioThread: NioThread)
|
||||
|
||||
@Throws(Throwable::class)
|
||||
fun exceptionCause(key: SelectionKey, nioThread: NioThread, e: Throwable) {
|
||||
e.printStackTrace()
|
||||
key.cancel()
|
||||
key.channel().close()
|
||||
}
|
||||
@Throws(Throwable::class)
|
||||
fun exceptionCause(key: SelectionKey, nioThread: NioThread, e: Throwable) {
|
||||
e.printStackTrace()
|
||||
key.cancel()
|
||||
key.channel().close()
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package cn.tursom.niothread
|
||||
|
||||
interface NioThreadTaskFuture<T> {
|
||||
fun get(): T
|
||||
fun get(): T
|
||||
}
|
@ -26,10 +26,12 @@ class NioLoopServer(
|
||||
) : SocketServer {
|
||||
private val listenChannel = ServerSocketChannel.open()
|
||||
private val workerNioThread = nioThreadFactory("nio-worker", WorkerLoopHandler(protocol))
|
||||
private val bossNioThread = nioThreadFactory("nio-boss", BossLoopHandler(
|
||||
protocol,
|
||||
workerNioThread
|
||||
))
|
||||
private val bossNioThread = nioThreadFactory(
|
||||
"nio-boss", BossLoopHandler(
|
||||
protocol,
|
||||
workerNioThread
|
||||
)
|
||||
)
|
||||
private val started = AtomicBoolean(false)
|
||||
|
||||
override fun run() {
|
||||
|
@ -19,47 +19,6 @@ import java.nio.channels.SocketChannel;
|
||||
* AsyncSocket 的 NioThread 在 Java 下实现 Echo 服务器
|
||||
*/
|
||||
public class EchoServer implements Closeable, Runnable {
|
||||
public static void main(String[] args) {
|
||||
EchoServer server = new EchoServer(12345);
|
||||
server.run();
|
||||
}
|
||||
|
||||
private final int port;
|
||||
private final ServerSocketChannel serverSocketChannel = getServerSocketChannel();
|
||||
private final NioThread nioThread = new WorkerLoopNioThread("nioLoopThread", getSelector(), false, 3000, loopHandler);
|
||||
private SelectionKey key;
|
||||
|
||||
public EchoServer(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (key != null) {
|
||||
key.cancel();
|
||||
}
|
||||
serverSocketChannel.close();
|
||||
nioThread.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
serverSocketChannel.socket().bind(new InetSocketAddress(port));
|
||||
serverSocketChannel.configureBlocking(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
nioThread.register(serverSocketChannel, SelectionKey.OP_ACCEPT, key -> {
|
||||
this.key = key;
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
private static final NioProtocol nioProtocol = new NioProtocol() {
|
||||
@Override
|
||||
public void exceptionCause(@NotNull SelectionKey key, @NotNull NioThread nioThread, @NotNull Throwable e) throws Throwable {
|
||||
@ -90,8 +49,20 @@ public class EchoServer implements Closeable, Runnable {
|
||||
key.interestOps(SelectionKey.OP_READ);
|
||||
}
|
||||
};
|
||||
|
||||
private static final BossLoopHandler loopHandler = new BossLoopHandler(nioProtocol, null);
|
||||
private final int port;
|
||||
private final ServerSocketChannel serverSocketChannel = getServerSocketChannel();
|
||||
private final NioThread nioThread = new WorkerLoopNioThread("nioLoopThread", getSelector(), false, 3000, loopHandler);
|
||||
private SelectionKey key;
|
||||
|
||||
public EchoServer(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
EchoServer server = new EchoServer(12345);
|
||||
server.run();
|
||||
}
|
||||
|
||||
private static Selector getSelector() {
|
||||
try {
|
||||
@ -108,4 +79,31 @@ public class EchoServer implements Closeable, Runnable {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (key != null) {
|
||||
key.cancel();
|
||||
}
|
||||
serverSocketChannel.close();
|
||||
nioThread.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
serverSocketChannel.socket().bind(new InetSocketAddress(port));
|
||||
serverSocketChannel.configureBlocking(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
nioThread.register(serverSocketChannel, SelectionKey.OP_ACCEPT, key -> {
|
||||
this.key = key;
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,11 @@ public class NioLoopServerTest implements Runnable, Closeable {
|
||||
});
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
NioLoopServerTest server = new NioLoopServerTest(12345);
|
||||
server.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
server.close();
|
||||
@ -72,9 +77,4 @@ public class NioLoopServerTest implements Runnable, Closeable {
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
NioLoopServerTest server = new NioLoopServerTest(12345);
|
||||
server.run();
|
||||
}
|
||||
}
|
||||
|
@ -3,5 +3,5 @@ package cn.tursom.web
|
||||
import java.io.Closeable
|
||||
|
||||
interface HttpServer : Runnable, Closeable {
|
||||
val port: Int
|
||||
val port: Int
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package cn.tursom.web
|
||||
|
||||
interface MutableHttpContent : HttpContent {
|
||||
fun addParam(key: String, value: String)
|
||||
fun addParam(key: String, value: String)
|
||||
}
|
@ -19,10 +19,10 @@ interface ResponseHeaderAdapter {
|
||||
mustRevalidate: Boolean = false
|
||||
) = setResponseHeader(
|
||||
"Cache-Control", "$cacheControl${
|
||||
if (maxAge != null && maxAge > 0) ", max-age=$maxAge" else ""
|
||||
}${
|
||||
if (mustRevalidate) ", must-revalidate" else ""
|
||||
}"
|
||||
if (maxAge != null && maxAge > 0) ", max-age=$maxAge" else ""
|
||||
}${
|
||||
if (mustRevalidate) ", must-revalidate" else ""
|
||||
}"
|
||||
)
|
||||
|
||||
fun addCookie(cookie: Cookie) = addResponseHeader("Set-Cookie", cookie)
|
||||
|
@ -2,7 +2,7 @@ package cn.tursom.web
|
||||
|
||||
import cn.tursom.core.buffer.ByteBuffer
|
||||
|
||||
interface WebSocketHandler<in T : WebSocketContent> {
|
||||
interface WebSocketHandler<in T : WebSocketContent> {
|
||||
fun connected(context: T)
|
||||
|
||||
fun recvText(str: String, context: T)
|
||||
|
@ -1,14 +1,14 @@
|
||||
package cn.tursom.web.router
|
||||
|
||||
interface Router<T> {
|
||||
fun addSubRoute(route: String, value: T?, onDestroy: ((oldValue: T) -> Unit)? = null)
|
||||
fun delRoute(route: String)
|
||||
fun addSubRoute(route: String, value: T?, onDestroy: ((oldValue: T) -> Unit)? = null)
|
||||
fun delRoute(route: String)
|
||||
|
||||
operator fun set(
|
||||
route: String,
|
||||
onDestroy: ((oldValue: T) -> Unit)? = null,
|
||||
value: T?
|
||||
) = addSubRoute(route, value, onDestroy)
|
||||
operator fun set(
|
||||
route: String,
|
||||
onDestroy: ((oldValue: T) -> Unit)? = null,
|
||||
value: T?
|
||||
) = addSubRoute(route, value, onDestroy)
|
||||
|
||||
operator fun get(route: String): Pair<T?, List<Pair<String, String>>>
|
||||
operator fun get(route: String): Pair<T?, List<Pair<String, String>>>
|
||||
}
|
@ -16,98 +16,98 @@ import cn.tursom.web.router.impl.colonnode.PlaceholderColonNode
|
||||
*/
|
||||
@Suppress("unused", "unused", "MemberVisibilityCanBePrivate", "UNUSED_PARAMETER")
|
||||
class ColonRouter<T> : Router<T> {
|
||||
private val rootNode = ColonNode<T>(listOf(""), 0)
|
||||
val root: IColonNode<T> = rootNode
|
||||
private val rootNode = ColonNode<T>(listOf(""), 0)
|
||||
val root: IColonNode<T> = rootNode
|
||||
|
||||
override fun addSubRoute(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
|
||||
override fun addSubRoute(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 = AnyColonNode<T>(routeList, index)
|
||||
routeNode.wildSubRouter = node
|
||||
index = routeList.size - 1
|
||||
node
|
||||
}
|
||||
r == "*" -> routeNode.wildSubRouter ?: run {
|
||||
val node = AnyColonNode<T>(routeList, index)
|
||||
routeNode.wildSubRouter = node
|
||||
index = routeList.size - 1
|
||||
node
|
||||
}
|
||||
|
||||
r[0] == ':' -> run {
|
||||
val node = synchronized(routeNode.placeholderRouterList!!) {
|
||||
val matchLength = PlaceholderColonNode.matchLength(routeList, index)
|
||||
routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength } ?: run {
|
||||
routeNode.addNode(routeList, index, null)
|
||||
routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength }!!
|
||||
}
|
||||
}
|
||||
index += node.size - 1
|
||||
node
|
||||
}
|
||||
r[0] == ':' -> run {
|
||||
val node = synchronized(routeNode.placeholderRouterList!!) {
|
||||
val matchLength = PlaceholderColonNode.matchLength(routeList, index)
|
||||
routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength } ?: run {
|
||||
routeNode.addNode(routeList, index, null)
|
||||
routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength }!!
|
||||
}
|
||||
}
|
||||
index += node.size - 1
|
||||
node
|
||||
}
|
||||
|
||||
else -> synchronized(routeNode.subRouterMap) {
|
||||
routeNode.subRouterMap[r] ?: run {
|
||||
val node = ColonNode<T>(routeList, index)
|
||||
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
|
||||
}
|
||||
else -> synchronized(routeNode.subRouterMap) {
|
||||
routeNode.subRouterMap[r] ?: run {
|
||||
val node = ColonNode<T>(routeList, index)
|
||||
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
|
||||
}
|
||||
|
||||
override fun delRoute(route: String) {
|
||||
this[route] = null
|
||||
}
|
||||
override fun delRoute(route: String) {
|
||||
this[route] = null
|
||||
}
|
||||
|
||||
override operator fun get(route: String): Pair<T?, List<Pair<String, String>>> {
|
||||
val list = ArrayList<Pair<String, String>>()
|
||||
return rootNode[route.split('?')[0].split('/').filter { it.isNotEmpty() }, list]?.value to list
|
||||
}
|
||||
override operator fun get(route: String): Pair<T?, List<Pair<String, String>>> {
|
||||
val list = ArrayList<Pair<String, String>>()
|
||||
return rootNode[route.split('?')[0].split('/').filter { it.isNotEmpty() }, list]?.value to list
|
||||
}
|
||||
|
||||
private fun toString(node: ColonNode<T>, stringBuilder: StringBuilder, indentation: String) {
|
||||
if (
|
||||
node.value == null &&
|
||||
node.subRouterMap.isEmpty() &&
|
||||
node.placeholderRouterList?.isEmpty() != false &&
|
||||
node.wildSubRouter == null
|
||||
) {
|
||||
return
|
||||
}
|
||||
private fun toString(node: ColonNode<T>, stringBuilder: StringBuilder, indentation: String) {
|
||||
if (
|
||||
node.value == null &&
|
||||
node.subRouterMap.isEmpty() &&
|
||||
node.placeholderRouterList?.isEmpty() != false &&
|
||||
node.wildSubRouter == null
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
if (indentation.isNotEmpty()) {
|
||||
stringBuilder.append(indentation)
|
||||
stringBuilder.append("- ")
|
||||
}
|
||||
stringBuilder.append("${node.singleRoute}${if (node.value != null) " ${node.value}" else ""}\n")
|
||||
if (indentation.isNotEmpty()) {
|
||||
stringBuilder.append(indentation)
|
||||
stringBuilder.append("- ")
|
||||
}
|
||||
stringBuilder.append("${node.singleRoute}${if (node.value != null) " ${node.value}" else ""}\n")
|
||||
|
||||
if (node is AnyColonNode) return
|
||||
if (node is AnyColonNode) return
|
||||
|
||||
val subIndentation = if (indentation.isEmpty()) "|" else "$indentation |"
|
||||
val subIndentation = if (indentation.isEmpty()) "|" else "$indentation |"
|
||||
|
||||
node.subRouterMap.forEach { (_, u) ->
|
||||
toString(u, stringBuilder, subIndentation)
|
||||
}
|
||||
node.placeholderRouterList?.forEach {
|
||||
toString(it, stringBuilder, subIndentation)
|
||||
}
|
||||
toString(node.wildSubRouter ?: return, stringBuilder, subIndentation)
|
||||
return
|
||||
}
|
||||
node.subRouterMap.forEach { (_, u) ->
|
||||
toString(u, stringBuilder, subIndentation)
|
||||
}
|
||||
node.placeholderRouterList?.forEach {
|
||||
toString(it, stringBuilder, subIndentation)
|
||||
}
|
||||
toString(node.wildSubRouter ?: return, stringBuilder, subIndentation)
|
||||
return
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val stringBuilder = StringBuilder()
|
||||
toString(rootNode, stringBuilder, "")
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
override fun toString(): String {
|
||||
val stringBuilder = StringBuilder()
|
||||
toString(rootNode, stringBuilder, "")
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,7 @@ class NodeContext(val nodeList: List<String>, val location: Int = 0) {
|
||||
|
||||
interface ICurlyBracesNode {
|
||||
val deep: Int
|
||||
|
||||
/**
|
||||
* 用来对路径进行匹配与获得参数
|
||||
*/
|
||||
|
@ -11,19 +11,19 @@ import kotlin.concurrent.write
|
||||
* 不支持参数解析,仅支持解析固定路径
|
||||
*/
|
||||
class SimpleRouter<T> : Router<T> {
|
||||
private val router = StringRadixTree<T?>()
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
private val router = StringRadixTree<T?>()
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
|
||||
override fun addSubRoute(route: String, value: T?, onDestroy: ((oldValue: T) -> Unit)?) = lock.write {
|
||||
val old = router.set(route, value)
|
||||
if (old != null) onDestroy?.invoke(old)
|
||||
}
|
||||
override fun addSubRoute(route: String, value: T?, onDestroy: ((oldValue: T) -> Unit)?) = lock.write {
|
||||
val old = router.set(route, value)
|
||||
if (old != null) onDestroy?.invoke(old)
|
||||
}
|
||||
|
||||
override fun delRoute(route: String) = lock.write {
|
||||
router[route] = null
|
||||
}
|
||||
override fun delRoute(route: String) = lock.write {
|
||||
router[route] = null
|
||||
}
|
||||
|
||||
override fun get(route: String): Pair<T?, List<Pair<String, String>>> = lock.read { router[route] } to listOf()
|
||||
override fun get(route: String): Pair<T?, List<Pair<String, String>>> = lock.read { router[route] } to listOf()
|
||||
|
||||
override fun toString(): String = router.toString()
|
||||
override fun toString(): String = router.toString()
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package cn.tursom.web.router.impl.colonnode
|
||||
|
||||
class AnyColonNode<T>(
|
||||
route: List<String>,
|
||||
index: Int,
|
||||
value: T? = null
|
||||
route: List<String>,
|
||||
index: Int,
|
||||
value: T? = null
|
||||
) : ColonNode<T>(route, index, value) {
|
||||
override fun match(route: List<String>, startIndex: Int) = true to 1
|
||||
override fun match(route: List<String>, startIndex: Int) = true to 1
|
||||
}
|
@ -4,181 +4,181 @@ import cn.tursom.core.binarySearch
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
open class ColonNode<T>(
|
||||
var routeList: List<String>,
|
||||
var index: Int,
|
||||
override var value: T? = null
|
||||
var routeList: List<String>,
|
||||
var index: Int,
|
||||
override var value: T? = null
|
||||
) : IColonNode<T> {
|
||||
val route: String = routeList[index]
|
||||
var wildSubRouter: AnyColonNode<T>? = null
|
||||
open val placeholderRouterList: ArrayList<PlaceholderColonNode<T>>? = ArrayList(0)
|
||||
val subRouterMap = HashMap<String, ColonNode<T>>(0)
|
||||
|
||||
open val singleRoute
|
||||
get() = "/$route"
|
||||
|
||||
override fun forEach(action: (node: IColonNode<T>) -> Unit) {
|
||||
placeholderRouterList?.forEach(action)
|
||||
subRouterMap.forEach { (_, u) -> action(u) }
|
||||
wildSubRouter?.let(action)
|
||||
}
|
||||
|
||||
open fun match(
|
||||
route: List<String>,
|
||||
startIndex: Int
|
||||
): Pair<Boolean, Int> = (route.size > startIndex && route[startIndex] == this.route) to 1
|
||||
|
||||
fun addNode(route: List<String>, startIndex: Int, value: T? = null): Int {
|
||||
val r = route[startIndex]
|
||||
return when {
|
||||
r.isEmpty() -> return addNode(route, startIndex + 1)
|
||||
r == "*" -> {
|
||||
wildSubRouter = AnyColonNode(route, startIndex)
|
||||
1
|
||||
}
|
||||
r[0] == ':' -> {
|
||||
val node: PlaceholderColonNode<T> = PlaceholderColonNode(route, startIndex, value = value)
|
||||
// 必须保证 placeholderRouterList 存在,而且还不能有这个长度的节点
|
||||
if (synchronized(placeholderRouterList!!) {
|
||||
placeholderRouterList!!.binarySearch { it.size - node.size }
|
||||
} != null) {
|
||||
throw Exception()
|
||||
}
|
||||
synchronized(placeholderRouterList!!) {
|
||||
placeholderRouterList?.add(node)
|
||||
placeholderRouterList?.sortBy { it.size }
|
||||
}
|
||||
node.size
|
||||
}
|
||||
else -> synchronized(subRouterMap) {
|
||||
subRouterMap[r] = ColonNode(route, startIndex, value)
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun get(route: List<String>, startIndex: Int = 0): Pair<ColonNode<T>?, Int> {
|
||||
val r = route[startIndex]
|
||||
if (r.isEmpty()) return this to 1
|
||||
|
||||
val value = synchronized(subRouterMap) { subRouterMap[r] }
|
||||
if (value != null) return value to 1
|
||||
|
||||
val matchLength = route.size - startIndex
|
||||
val exactRoute = placeholderRouterList?.let { list ->
|
||||
synchronized(list) { list.binarySearch { matchLength - it.size } }
|
||||
}
|
||||
if (exactRoute != null) return exactRoute to matchLength
|
||||
|
||||
placeholderRouterList?.let { list ->
|
||||
synchronized(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<String>, startIndex: Int = 0): ColonNode<T>? {
|
||||
var index = startIndex
|
||||
var routeNode = this
|
||||
while (index < route.size) {
|
||||
val (node, size) = routeNode[route, index]
|
||||
routeNode = node ?: return null
|
||||
index += size
|
||||
}
|
||||
return routeNode
|
||||
}
|
||||
|
||||
operator fun get(
|
||||
route: List<String>,
|
||||
startIndex: Int = 0,
|
||||
routeList: java.util.AbstractList<Pair<String, String>>
|
||||
): Pair<ColonNode<T>?, Int> {
|
||||
val r = route[startIndex]
|
||||
if (r.isEmpty()) {
|
||||
return this to 1
|
||||
}
|
||||
|
||||
val value = synchronized(subRouterMap) { subRouterMap[r] }
|
||||
if (value != null) return value to 1
|
||||
|
||||
val matchLength = route.size - startIndex
|
||||
val exactRoute = placeholderRouterList?.let { list ->
|
||||
synchronized(list) { list.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
|
||||
}
|
||||
|
||||
val list = ArrayList<Pair<String, String>>()
|
||||
placeholderRouterList?.let { routerList ->
|
||||
synchronized(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 subRoute to route.size - startIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i in startIndex until route.size)
|
||||
routeList.add("*" to route[i])
|
||||
return wildSubRouter to 1
|
||||
}
|
||||
|
||||
operator fun get(
|
||||
route: List<String>,
|
||||
routeList: java.util.AbstractList<Pair<String, String>>
|
||||
) = getRoute(route, 0, routeList)
|
||||
|
||||
fun getRoute(
|
||||
route: List<String>,
|
||||
startIndex: Int = 0,
|
||||
routeList: java.util.AbstractList<Pair<String, String>>
|
||||
): ColonNode<T>? {
|
||||
var index = startIndex
|
||||
var routeNode = this
|
||||
while (routeNode !is AnyColonNode && index < route.size) {
|
||||
val (node, size) = routeNode[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()
|
||||
}
|
||||
val route: String = routeList[index]
|
||||
var wildSubRouter: AnyColonNode<T>? = null
|
||||
open val placeholderRouterList: ArrayList<PlaceholderColonNode<T>>? = ArrayList(0)
|
||||
val subRouterMap = HashMap<String, ColonNode<T>>(0)
|
||||
|
||||
open val singleRoute
|
||||
get() = "/$route"
|
||||
|
||||
override fun forEach(action: (node: IColonNode<T>) -> Unit) {
|
||||
placeholderRouterList?.forEach(action)
|
||||
subRouterMap.forEach { (_, u) -> action(u) }
|
||||
wildSubRouter?.let(action)
|
||||
}
|
||||
|
||||
open fun match(
|
||||
route: List<String>,
|
||||
startIndex: Int
|
||||
): Pair<Boolean, Int> = (route.size > startIndex && route[startIndex] == this.route) to 1
|
||||
|
||||
fun addNode(route: List<String>, startIndex: Int, value: T? = null): Int {
|
||||
val r = route[startIndex]
|
||||
return when {
|
||||
r.isEmpty() -> return addNode(route, startIndex + 1)
|
||||
r == "*" -> {
|
||||
wildSubRouter = AnyColonNode(route, startIndex)
|
||||
1
|
||||
}
|
||||
r[0] == ':' -> {
|
||||
val node: PlaceholderColonNode<T> = PlaceholderColonNode(route, startIndex, value = value)
|
||||
// 必须保证 placeholderRouterList 存在,而且还不能有这个长度的节点
|
||||
if (synchronized(placeholderRouterList!!) {
|
||||
placeholderRouterList!!.binarySearch { it.size - node.size }
|
||||
} != null) {
|
||||
throw Exception()
|
||||
}
|
||||
synchronized(placeholderRouterList!!) {
|
||||
placeholderRouterList?.add(node)
|
||||
placeholderRouterList?.sortBy { it.size }
|
||||
}
|
||||
node.size
|
||||
}
|
||||
else -> synchronized(subRouterMap) {
|
||||
subRouterMap[r] = ColonNode(route, startIndex, value)
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun get(route: List<String>, startIndex: Int = 0): Pair<ColonNode<T>?, Int> {
|
||||
val r = route[startIndex]
|
||||
if (r.isEmpty()) return this to 1
|
||||
|
||||
val value = synchronized(subRouterMap) { subRouterMap[r] }
|
||||
if (value != null) return value to 1
|
||||
|
||||
val matchLength = route.size - startIndex
|
||||
val exactRoute = placeholderRouterList?.let { list ->
|
||||
synchronized(list) { list.binarySearch { matchLength - it.size } }
|
||||
}
|
||||
if (exactRoute != null) return exactRoute to matchLength
|
||||
|
||||
placeholderRouterList?.let { list ->
|
||||
synchronized(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<String>, startIndex: Int = 0): ColonNode<T>? {
|
||||
var index = startIndex
|
||||
var routeNode = this
|
||||
while (index < route.size) {
|
||||
val (node, size) = routeNode[route, index]
|
||||
routeNode = node ?: return null
|
||||
index += size
|
||||
}
|
||||
return routeNode
|
||||
}
|
||||
|
||||
operator fun get(
|
||||
route: List<String>,
|
||||
startIndex: Int = 0,
|
||||
routeList: java.util.AbstractList<Pair<String, String>>
|
||||
): Pair<ColonNode<T>?, Int> {
|
||||
val r = route[startIndex]
|
||||
if (r.isEmpty()) {
|
||||
return this to 1
|
||||
}
|
||||
|
||||
val value = synchronized(subRouterMap) { subRouterMap[r] }
|
||||
if (value != null) return value to 1
|
||||
|
||||
val matchLength = route.size - startIndex
|
||||
val exactRoute = placeholderRouterList?.let { list ->
|
||||
synchronized(list) { list.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
|
||||
}
|
||||
|
||||
val list = ArrayList<Pair<String, String>>()
|
||||
placeholderRouterList?.let { routerList ->
|
||||
synchronized(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 subRoute to route.size - startIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i in startIndex until route.size)
|
||||
routeList.add("*" to route[i])
|
||||
return wildSubRouter to 1
|
||||
}
|
||||
|
||||
operator fun get(
|
||||
route: List<String>,
|
||||
routeList: java.util.AbstractList<Pair<String, String>>
|
||||
) = getRoute(route, 0, routeList)
|
||||
|
||||
fun getRoute(
|
||||
route: List<String>,
|
||||
startIndex: Int = 0,
|
||||
routeList: java.util.AbstractList<Pair<String, String>>
|
||||
): ColonNode<T>? {
|
||||
var index = startIndex
|
||||
var routeNode = this
|
||||
while (routeNode !is AnyColonNode && index < route.size) {
|
||||
val (node, size) = routeNode[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()
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.web.router.impl.colonnode
|
||||
|
||||
interface IColonNode<T> {
|
||||
val value: T?
|
||||
|
||||
fun forEach(action: (node: IColonNode<T>) -> Unit)
|
||||
val value: T?
|
||||
|
||||
fun forEach(action: (node: IColonNode<T>) -> Unit)
|
||||
}
|
@ -1,53 +1,53 @@
|
||||
package cn.tursom.web.router.impl.colonnode
|
||||
|
||||
class PlaceholderColonNode<T>(
|
||||
route: List<String>,
|
||||
private val startIndex: Int = 0,
|
||||
endIndex: Int = startIndex + route.matchLength(startIndex),
|
||||
value: T? = null
|
||||
route: List<String>,
|
||||
private val startIndex: Int = 0,
|
||||
endIndex: Int = startIndex + route.matchLength(startIndex),
|
||||
value: T? = null
|
||||
) : ColonNode<T>(route, endIndex - 1, value) {
|
||||
override val placeholderRouterList: ArrayList<PlaceholderColonNode<T>>?
|
||||
get() = null
|
||||
|
||||
val size: Int = route.matchLength(startIndex, endIndex)
|
||||
|
||||
override val singleRoute: String
|
||||
get() {
|
||||
val sb = StringBuilder()
|
||||
for (i in startIndex..index) {
|
||||
sb.append("/")
|
||||
sb.append(routeList[i])
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
override fun match(
|
||||
route: List<String>,
|
||||
startIndex: Int
|
||||
): Pair<Boolean, Int> =
|
||||
(size == route.matchLength(startIndex)) to size
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private fun List<String>.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<String>, 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
|
||||
}
|
||||
}
|
||||
override val placeholderRouterList: ArrayList<PlaceholderColonNode<T>>?
|
||||
get() = null
|
||||
|
||||
val size: Int = route.matchLength(startIndex, endIndex)
|
||||
|
||||
override val singleRoute: String
|
||||
get() {
|
||||
val sb = StringBuilder()
|
||||
for (i in startIndex..index) {
|
||||
sb.append("/")
|
||||
sb.append(routeList[i])
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
override fun match(
|
||||
route: List<String>,
|
||||
startIndex: Int
|
||||
): Pair<Boolean, Int> =
|
||||
(size == route.matchLength(startIndex)) to size
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private fun List<String>.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<String>, 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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package cn.tursom.web.utils
|
||||
|
||||
enum class CacheControl(val str: String) {
|
||||
Public("public"), Private("private"), NoStore("no-store"), NoCache("no-cache");
|
||||
override fun toString(): String = str
|
||||
Public("public"), Private("private"), NoStore("no-store"), NoCache("no-cache");
|
||||
|
||||
override fun toString(): String = str
|
||||
}
|
@ -3,28 +3,28 @@ package cn.tursom.web.utils
|
||||
import cn.tursom.core.buffer.ByteBuffer
|
||||
|
||||
interface Chunked {
|
||||
/**
|
||||
* Returns current transfer progress.
|
||||
*/
|
||||
val progress: Long
|
||||
/**
|
||||
* Returns current transfer progress.
|
||||
*/
|
||||
val progress: Long
|
||||
|
||||
/**
|
||||
* Returns the length of the input.
|
||||
* @return the length of the input if the length of the input is known.
|
||||
* a negative value if the length of the input is unknown.
|
||||
*/
|
||||
val length: Long
|
||||
/**
|
||||
* Returns the length of the input.
|
||||
* @return the length of the input if the length of the input is known.
|
||||
* a negative value if the length of the input is unknown.
|
||||
*/
|
||||
val length: Long
|
||||
|
||||
/**
|
||||
* Return {@code true} if and only if there is no data left in the stream
|
||||
* and the stream has reached at its end.
|
||||
*/
|
||||
val endOfInput: Boolean
|
||||
/**
|
||||
* Return {@code true} if and only if there is no data left in the stream
|
||||
* and the stream has reached at its end.
|
||||
*/
|
||||
val endOfInput: Boolean
|
||||
|
||||
fun readChunk(): ByteBuffer
|
||||
fun readChunk(): ByteBuffer
|
||||
|
||||
/**
|
||||
* Releases the resources associated with the input.
|
||||
*/
|
||||
fun close()
|
||||
/**
|
||||
* Releases the resources associated with the input.
|
||||
*/
|
||||
fun close()
|
||||
}
|
@ -1,19 +1,22 @@
|
||||
package cn.tursom.web.utils
|
||||
|
||||
class Cookie(
|
||||
var name: String,
|
||||
var value: String,
|
||||
var domain: String? = null,
|
||||
var path: String? = null,
|
||||
var maxAge: Long = 0,
|
||||
var sameSite: SameSite? = null
|
||||
var name: String,
|
||||
var value: String,
|
||||
var domain: String? = null,
|
||||
var path: String? = null,
|
||||
var maxAge: Long = 0,
|
||||
var sameSite: SameSite? = null
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "$name=$value${
|
||||
if (maxAge > 0) "; Max-Age=$maxAge" else ""}${
|
||||
if (domain != null) "; Domain=$domain" else ""}${
|
||||
if (path != null) "; Path=$path" else ""}${
|
||||
if (sameSite != null) ": SameSite=$sameSite" else ""
|
||||
}"
|
||||
}
|
||||
override fun toString(): String {
|
||||
return "$name=$value${
|
||||
if (maxAge > 0) "; Max-Age=$maxAge" else ""
|
||||
}${
|
||||
if (domain != null) "; Domain=$domain" else ""
|
||||
}${
|
||||
if (path != null) "; Path=$path" else ""
|
||||
}${
|
||||
if (sameSite != null) ": SameSite=$sameSite" else ""
|
||||
}"
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.web.utils
|
||||
|
||||
enum class SameSite(val str: String) {
|
||||
Strict("Strict"), Lax("Lax");
|
||||
Strict("Strict"), Lax("Lax");
|
||||
|
||||
override fun toString() = str
|
||||
override fun toString() = str
|
||||
}
|
@ -7,7 +7,9 @@ import io.netty.handler.codec.http.cookie.ServerCookieDecoder
|
||||
import java.util.*
|
||||
|
||||
|
||||
fun parseHttpDate(date: CharSequence, start: Int = 0, end: Int = date.length): Date = DateFormatter.parseHttpDate(date, start, end)
|
||||
fun parseHttpDate(date: CharSequence, start: Int = 0, end: Int = date.length): Date =
|
||||
DateFormatter.parseHttpDate(date, start, end)
|
||||
|
||||
fun format(date: Date): String = DateFormatter.format(date)
|
||||
fun append(date: Date, sb: StringBuilder): StringBuilder = DateFormatter.append(date, sb)
|
||||
fun decodeCookie(cookie: String): Map<String, String> {
|
||||
|
Loading…
Reference in New Issue
Block a user