add coroutine ticker

This commit is contained in:
tursom 2021-07-10 12:04:11 +08:00
parent d86018ea4d
commit 4ea5450819
74 changed files with 4255 additions and 4123 deletions

View File

@ -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
}
}
}

View File

@ -1,6 +1,6 @@
package cn.tursom.aop.advice
interface Advice {
operator fun invoke(content: AdviceContent): Any?
operator fun invoke(content: AdviceContent): Any?
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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()
}
}

View File

@ -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
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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) {
}
}
}
}

View File

@ -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))
}
}

View File

@ -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
)
}
}

View File

@ -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
)
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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()
}
}

View File

@ -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) {
}
}
}
}

View File

@ -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
}
}

View File

@ -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()
}
}

View File

@ -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
}
}
}

View File

@ -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()
}
}

View File

@ -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) {
}
}
}
}

View File

@ -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>>>()
}
}

View File

@ -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) {
}
}
}
}

View File

@ -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>
}

View File

@ -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>
}

View File

@ -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
)
}

View File

@ -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) {
}
}
}
}

View File

@ -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) {
}
}
}
}

View File

@ -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 {

View File

@ -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++
}
}

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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
}
}
}

View File

@ -1,7 +1,7 @@
package cn.tursom.core.xml
enum class ElementTarget {
Attribute, ElementText, SubElement
Attribute, ElementText, SubElement
}
@Target(AnnotationTarget.CLASS)

View File

@ -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)
}

View File

@ -1,5 +1,5 @@
package cn.tursom.core.xml.interfaces
interface ElementContainerXmlElement : XmlElement {
val subElement: List<XmlElement>
val subElement: List<XmlElement>
}

View File

@ -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)
}

View File

@ -1,5 +1,5 @@
package cn.tursom.core.xml.interfaces
interface TextPotableXmlElement : TextXmlElement, PotableXmlElement {
override var text: String
override var text: String
}

View File

@ -1,5 +1,5 @@
package cn.tursom.core.xml.interfaces
interface TextXmlElement : XmlElement {
val text: String
val text: String
}

View File

@ -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("&", "&amp;")
if (value.contains('"')) value = value.replace("\"", "&quot;")
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("&", "&amp;")
if (value.contains('"')) value = value.replace("\"", "&quot;")
sb.append(" $t=\"$value\"")
}
return sb.toString()
}
}

View File

@ -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) {
}
}
}
}

View File

@ -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") {

View File

@ -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
}

View File

@ -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)

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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()
}
}

View File

@ -1,5 +1,5 @@
package cn.tursom.niothread
interface NioThreadTaskFuture<T> {
fun get(): T
fun get(): T
}

View File

@ -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() {

View File

@ -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;
});
}
}

View File

@ -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();
}
}

View File

@ -3,5 +3,5 @@ package cn.tursom.web
import java.io.Closeable
interface HttpServer : Runnable, Closeable {
val port: Int
val port: Int
}

View File

@ -1,5 +1,5 @@
package cn.tursom.web
interface MutableHttpContent : HttpContent {
fun addParam(key: String, value: String)
fun addParam(key: String, value: String)
}

View File

@ -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)

View File

@ -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)

View File

@ -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>>>
}

View File

@ -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()
}
}

View File

@ -67,6 +67,7 @@ class NodeContext(val nodeList: List<String>, val location: Int = 0) {
interface ICurlyBracesNode {
val deep: Int
/**
* 用来对路径进行匹配与获得参数
*/

View File

@ -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()
}

View File

@ -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
}

View File

@ -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()
}
}

View File

@ -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)
}

View File

@ -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
}
}
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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 ""
}"
}
}

View File

@ -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
}

View File

@ -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> {