Merge branch 'master' of github.com:tursom/TursomServer

This commit is contained in:
tursom 2020-07-20 08:43:02 +08:00
commit c6f57a88cd
24 changed files with 1517 additions and 256 deletions

View File

@ -377,4 +377,32 @@ inline fun <reified T : Any?> Any.assert(action: T.() -> Unit): Boolean {
} else {
false
}
}
val Class<*>.allFields: List<Field>
get() {
var clazz = this
val list = ArrayList<Field>()
while (clazz != Any::class.java) {
list.addAll(clazz.declaredFields)
clazz = clazz.superclass
}
list.addAll(clazz.declaredFields)
return list
}
fun Class<*>.forAllFields(action: (Field) -> Unit) {
var clazz = this
while (clazz != Any::class.java) {
clazz.declaredFields.forEach(action)
clazz = clazz.superclass
}
clazz.declaredFields.forEach(action)
}
fun <T, R> Iterable<T>.firstNotNull(selector: (T) -> R): R? {
forEach {
return selector(it) ?: return@forEach
}
return null
}

View File

@ -1,271 +1,284 @@
package cn.tursom.core.datastruct
import cn.tursom.core.cast
@Suppress("MemberVisibilityCanBePrivate")
class ArrayMap<K : Comparable<K>, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
@Volatile
private var arr: Array<Node<K, V>?> = Array(initialCapacity) { null }
@Volatile
private var end = 0
open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
@Volatile
protected var arr: Array<Node<K, V>?> = Array(initialCapacity) { null }
override val size: Int get() = end
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
override val keys: MutableSet<K> = KeySet(this)
override val values: MutableCollection<V> = ValueCollection(this)
@Volatile
protected var end = 0
/**
* @param key 查找的键
* @return 键所在的下标
* @return < 0 如果键不存在, -${return} - 1 为如果插入应插入的下标
*/
fun search(key: K): Int {
if (end == 0) return -1
return arr.binarySearch(key, 0, end)
override val size: Int get() = end
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
override val keys: MutableSet<K> = KeySet(this)
override val values: MutableCollection<V> = ValueCollection(this)
/**
* @param key 查找的键
* @return 键所在的下标
* @return < 0 如果键不存在, -${return} - 1 为如果插入应插入的下标
*/
open fun search(key: K): Int {
if (end == 0) return -1
for (index in 0 until end) {
if ((arr[index] ?: continue).key == key) {
return index
}
}
return -1
}
infix fun getFromIndex(index: Int): V? {
return if (index < 0) null
else arr[index]?.value
}
override fun first(): V? = getFromIndex(0)
override fun clear() {
end = 0
}
override operator fun set(key: K, value: V) {
setAndGet(key, value)
}
override fun setAndGet(key: K, value: V): V? {
@Suppress("SENSELESS_COMPARISON")
if (key == null) return null
// 首先查找得到目标所在的下标
val index = search(key)
var prev: V? = null
if (index < 0) {
// 下标小于零表示不存在,直接插入数据
insert(key, value, -index - 1)
} else {
val node = arr[index]
if (node != null) {
prev = node.value
node.value = value
} else arr[index] = Node(key, value)
}
return prev
}
override infix fun putAll(from: Map<out K, V>) {
from.forEach { (key, value) ->
val index = search(key)
if (index < 0) arr[end++] = Node(key, value)
else {
val node = arr[index]
if (node != null) node.value = value
else arr[index] = Node(key, value)
}
}
}
override infix fun delete(key: K): V? {
val index = search(key)
return delete(index)
}
override infix fun containsKey(key: K): Boolean = search(key) >= 0
override infix fun containsValue(value: V): Boolean {
arr.forEach {
if (it?.value == value) return true
}
return false
}
override infix operator fun get(key: K): V? = getNode(key)?.value
override fun isEmpty(): Boolean = end == 0
fun copy(): ArrayMap<K, V> {
val clone = ArrayMap<K, V>(0)
clone.arr = Array(end) { arr[it]?.let { Node(it.key, it.value) } }
clone.end = end
return clone
}
override fun toString(): String {
if (end == 0) return "{}"
val sb = StringBuilder("{${arr[0]}")
for (i in 1 until end) {
sb.append(", ")
sb.append(arr[i])
}
sb.append("}")
return sb.toString()
}
private fun getNode(key: K): Node<K, V>? {
@Suppress("SENSELESS_COMPARISON")
if (key == null) return null
val index = search(key)
return if (index < 0) null
else arr[index]
}
private fun resize(newSize: Int = if (arr.isNotEmpty()) arr.size * 2 else 1) {
arr = arr.copyOf(newSize)
}
private fun insert(key: K, value: V, index: Int): V? {
if (end == arr.size) resize()
System.arraycopy(arr, index, arr, index + 1, end - index)
arr[index] = Node(key, value)
end++
return value
}
private infix fun delete(index: Int): V? {
if (index in 0 until end) {
val oldNode = arr[index]
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
end--
return oldNode?.value
}
return null
}
class Node<K, V>(
override val key: K,
@Volatile override var value: V
) : MutableMap.MutableEntry<K, V>, Comparable<K> {
override fun toString(): String = "$key=$value"
override fun setValue(newValue: V): V = value.also { value = newValue }
override fun compareTo(other: K): Int {
return if (key is Comparable<*>) {
key.cast<Comparable<K>>().compareTo(other)
} else {
-1
}
}
}
class EntrySet<K, V>(private val map: ArrayMap<K, V>) : MutableSet<MutableMap.MutableEntry<K, V>> {
override val size: Int get() = map.size
override fun contains(element: MutableMap.MutableEntry<K, V>): Boolean = map[element.key] == element.value
override fun isEmpty(): Boolean = map.isEmpty()
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = MapIterator(map)
override fun clear() = map.clear()
override fun containsAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
elements.forEach {
if (!contains(it)) return false
}
return true
}
infix fun getFromIndex(index: Int): V? {
return if (index < 0) null
else arr[index]?.value
override fun add(element: MutableMap.MutableEntry<K, V>): Boolean {
map[element.key] = element.value
return true
}
override fun first(): V? = getFromIndex(0)
override fun clear() {
end = 0
override fun addAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
elements.forEach { add(it) }
return true
}
override operator fun set(key: K, value: V) {
setAndGet(key, value)
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
val index = map.search(element.key)
val value = map.getFromIndex(index)
return if (value == element.value) {
map.delete(index)
true
} else {
false
}
}
override fun setAndGet(key: K, value: V): V? {
@Suppress("SENSELESS_COMPARISON")
if (key == null) return null
// 首先查找得到目标所在的下标
val index = search(key)
var prev: V? = null
if (index < 0) {
// 下标小于零表示不存在,直接插入数据
insert(key, value, -index - 1)
} else {
val node = arr[index]
if (node != null) {
prev = node.value
node.value = value
} else arr[index] = Node(key, value)
}
return prev
override fun removeAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
elements.forEach { remove(it) }
return true
}
override infix fun putAll(from: Map<out K, V>) {
from.forEach { (key, value) ->
val index = search(key)
if (index < 0) arr[end++] = Node(key, value)
else {
val node = arr[index]
if (node != null) node.value = value
else arr[index] = Node(key, value)
}
}
arr.sort()
override fun retainAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
val contains = elements.filter { map[it.key] == it.value }
map.clear()
map.resize(contains.size)
addAll(contains)
return true
}
}
class MapIterator<K, V>(private val map: ArrayMap<K, V>) : MutableIterator<MutableMap.MutableEntry<K, V>> {
private var index = 0
override fun hasNext(): Boolean {
@Suppress("ControlFlowWithEmptyBody")
while (++index < map.arr.size && index < map.end && map.arr[index] == null);
index--
return index < map.end
}
override infix fun delete(key: K): V? {
val index = search(key)
return delete(index)
override fun next(): MutableMap.MutableEntry<K, V> = map.arr[index++]!!
override fun remove() {
map.delete(index)
index--
}
}
class KeySet<K>(private val map: ArrayMap<K, *>) : MutableSet<K> {
override val size: Int get() = map.size
override fun contains(element: K): Boolean = map.containsKey(element)
override fun isEmpty(): Boolean = size == 0
override fun iterator(): MutableIterator<K> = KeyIterator(map)
override fun containsAll(elements: Collection<K>): Boolean {
elements.forEach {
if (!map.containsKey(it)) return false
}
return true
}
override infix fun containsKey(key: K): Boolean = search(key) >= 0
override infix fun containsValue(value: V): Boolean {
arr.forEach {
if (it?.value == value) return true
}
return false
override fun add(element: K): Boolean = false
override fun addAll(elements: Collection<K>): Boolean = false
override fun clear() = map.clear()
override fun retainAll(elements: Collection<K>): Boolean = map.entries.retainAll(elements.map { map.getNode(it) }.filterNotNull())
override fun remove(element: K): Boolean = map.remove(element) != null
override fun removeAll(elements: Collection<K>): Boolean {
elements.forEach { remove(it) }
return true
}
}
override infix operator fun get(key: K): V? = getNode(key)?.value
override fun isEmpty(): Boolean = end == 0
class KeyIterator<K>(map: ArrayMap<K, *>) : MutableIterator<K> {
private val iterator = map.iterator()
override fun hasNext(): Boolean = iterator.hasNext()
override fun next(): K = iterator.next().key
override fun remove() = iterator.remove()
}
fun copy(): ArrayMap<K, V> {
val clone = ArrayMap<K, V>(0)
clone.arr = Array(end) { arr[it]?.let { Node(it.key, it.value) } }
clone.end = end
return clone
class ValueCollection<V>(private val map: ArrayMap<*, V>) : MutableCollection<V> {
override val size: Int get() = map.size
override fun contains(element: V): Boolean = map.containsValue(element)
override fun isEmpty(): Boolean = size == 0
override fun iterator(): MutableIterator<V> = ValueIterator(map)
override fun add(element: V): Boolean = false
override fun addAll(elements: Collection<V>): Boolean = false
override fun clear() = map.clear()
override fun remove(element: V): Boolean = false
override fun removeAll(elements: Collection<V>): Boolean = false
override fun retainAll(elements: Collection<V>): Boolean = false
override fun containsAll(elements: Collection<V>): Boolean {
elements.forEach {
if (!map.containsValue(it)) return false
}
return true
}
}
override fun toString(): String {
if (end == 0) return "{}"
val sb = StringBuilder("{${arr[0]}")
for (i in 1 until end) {
sb.append(", ")
sb.append(arr[i])
}
sb.append("}")
return sb.toString()
}
private fun getNode(key: K): Node<K, V>? {
@Suppress("SENSELESS_COMPARISON")
if (key == null) return null
val index = search(key)
return if (index < 0) null
else arr[index]
}
private fun resize(newSize: Int = if (arr.isNotEmpty()) arr.size * 2 else 1) {
arr = arr.copyOf(newSize)
}
private fun insert(key: K, value: V, index: Int): V? {
if (end == arr.size) resize()
System.arraycopy(arr, index, arr, index + 1, end - index)
arr[index] = Node(key, value)
end++
return value
}
private infix fun delete(index: Int): V? {
if (index in 0 until end) {
val oldNode = arr[index]
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
end--
return oldNode?.value
}
return null
}
class Node<K : Comparable<K>, V>(
override val key: K,
@Volatile override var value: V
) : Comparable<K>, MutableMap.MutableEntry<K, V> {
override fun compareTo(other: K): Int = key.compareTo(other)
override fun toString(): String = "$key=$value"
override fun setValue(newValue: V): V = value.also { value = newValue }
}
class EntrySet<K : Comparable<K>, V>(private val map: ArrayMap<K, V>) : MutableSet<MutableMap.MutableEntry<K, V>> {
override val size: Int get() = map.size
override fun contains(element: MutableMap.MutableEntry<K, V>): Boolean = map[element.key] == element.value
override fun isEmpty(): Boolean = map.isEmpty()
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = MapIterator(map)
override fun clear() = map.clear()
override fun containsAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
elements.forEach {
if (!contains(it)) return false
}
return true
}
override fun add(element: MutableMap.MutableEntry<K, V>): Boolean {
map[element.key] = element.value
return true
}
override fun addAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
elements.forEach { add(it) }
return true
}
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
val index = map.search(element.key)
val value = map.getFromIndex(index)
return if (value == element.value) {
map.delete(index)
true
} else {
false
}
}
override fun removeAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
elements.forEach { remove(it) }
return true
}
override fun retainAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
val contains = elements.filter { map[it.key] == it.value }
map.clear()
map.resize(contains.size)
addAll(contains)
return true
}
}
class MapIterator<K : Comparable<K>, V>(private val map: ArrayMap<K, V>) : MutableIterator<MutableMap.MutableEntry<K, V>> {
private var index = 0
override fun hasNext(): Boolean {
@Suppress("ControlFlowWithEmptyBody")
while (++index < map.arr.size && index < map.end && map.arr[index] == null);
index--
return index < map.end
}
override fun next(): MutableMap.MutableEntry<K, V> = map.arr[index++]!!
override fun remove() {
map.delete(index)
index--
}
}
class KeySet<K : Comparable<K>>(private val map: ArrayMap<K, *>) : MutableSet<K> {
override val size: Int get() = map.size
override fun contains(element: K): Boolean = map.containsKey(element)
override fun isEmpty(): Boolean = size == 0
override fun iterator(): MutableIterator<K> = KeyIterator(map)
override fun containsAll(elements: Collection<K>): Boolean {
elements.forEach {
if (!map.containsKey(it)) return false
}
return true
}
override fun add(element: K): Boolean = false
override fun addAll(elements: Collection<K>): Boolean = false
override fun clear() = map.clear()
override fun retainAll(elements: Collection<K>): Boolean = map.entries.retainAll(elements.map { map.getNode(it) }.filterNotNull())
override fun remove(element: K): Boolean = map.remove(element) != null
override fun removeAll(elements: Collection<K>): Boolean {
elements.forEach { remove(it) }
return true
}
}
class KeyIterator<K : Comparable<K>>(map: ArrayMap<K, *>) : MutableIterator<K> {
private val iterator = map.iterator()
override fun hasNext(): Boolean = iterator.hasNext()
override fun next(): K = iterator.next().key
override fun remove() = iterator.remove()
}
class ValueCollection<V>(private val map: ArrayMap<*, V>) : MutableCollection<V> {
override val size: Int get() = map.size
override fun contains(element: V): Boolean = map.containsValue(element)
override fun isEmpty(): Boolean = size == 0
override fun iterator(): MutableIterator<V> = ValueIterator(map)
override fun add(element: V): Boolean = false
override fun addAll(elements: Collection<V>): Boolean = false
override fun clear() = map.clear()
override fun remove(element: V): Boolean = false
override fun removeAll(elements: Collection<V>): Boolean = false
override fun retainAll(elements: Collection<V>): Boolean = false
override fun containsAll(elements: Collection<V>): Boolean {
elements.forEach {
if (!map.containsValue(it)) return false
}
return true
}
}
class ValueIterator<V>(map: ArrayMap<*, V>) : MutableIterator<V> {
private val iterator = map.iterator()
override fun hasNext(): Boolean = iterator.hasNext()
override fun next(): V = iterator.next().value
override fun remove() = iterator.remove()
}
class ValueIterator<V>(map: ArrayMap<*, V>) : MutableIterator<V> {
private val iterator = map.iterator()
override fun hasNext(): Boolean = iterator.hasNext()
override fun next(): V = iterator.next().value
override fun remove() = iterator.remove()
}
}

View File

@ -0,0 +1,27 @@
package cn.tursom.core.datastruct
@Suppress("MemberVisibilityCanBePrivate")
class ComparableArrayMap<K : Comparable<K>, V>(initialCapacity: Int = 16) : ArrayMap<K, V>(initialCapacity) {
/**
* @param key 查找的键
* @return 键所在的下标
* @return < 0 如果键不存在, -${return} - 1 为如果插入应插入的下标
*/
override fun search(key: K): Int {
if (end == 0) return -1
return arr.binarySearch(key, 0, end)
}
override infix fun putAll(from: Map<out K, V>) {
from.forEach { (key, value) ->
val index = search(key)
if (index < 0) arr[end++] = Node(key, value)
else {
val node = arr[index]
if (node != null) node.value = value
else arr[index] = Node(key, value)
}
}
arr.sort()
}
}

View File

@ -0,0 +1,203 @@
package cn.tursom.core.datastruct
import cn.tursom.core.cast
@Suppress("MemberVisibilityCanBePrivate")
open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
@Volatile
protected var arr: Array<Any?> = Array(initialCapacity) { null }
@Volatile
protected var arrValue: Array<Any?> = Array(initialCapacity) { null }
@Volatile
protected var end = 0
override val size: Int get() = end
@Suppress("LeakingThis")
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().cast()
override val values: MutableCollection<V> get() = arrValue.asList().cast<MutableList<V>>().subList(0, end)
/**
* @param key 查找的键
* @return 键所在的下标
* @return < 0 如果键不存在, -${return} - 1 为如果插入应插入的下标
*/
open fun search(key: K): Int {
if (end == 0) return -1
for (index in 0 until end) {
if ((arr[index] ?: continue) == key) {
return index
}
}
return -1
}
private fun resize(newSize: Int = if (arr.isNotEmpty()) arr.size * 2 else 1) {
arr = arr.copyOf(newSize)
arrValue = arrValue.copyOf(newSize)
}
override fun setAndGet(key: K, value: V): V? {
var index = search(key)
if (index < 0 || index >= end) {
if (end == arr.size) {
resize()
}
index = end++
arr[index] = key
}
return setByIndex(index, value)
}
override fun set(key: K, value: V) {
setAndGet(key, value)
}
fun setByIndex(index: Int, value: V): V? {
val oldValue = arrValue[end]
arrValue[index] = value
return oldValue.cast()
}
override fun delete(key: K): V? {
return deleteByIndex(search(key))
}
fun deleteByIndex(index: Int): V? {
if (index < 0 || index >= end) return null
val oldValue = arrValue[index]
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
System.arraycopy(arrValue, index + 1, arrValue, index, end - index - 1)
end--
return oldValue.cast()
}
override fun clear() {
end = 0
}
override fun first(): V? {
return if (end <= 0) {
null
} else {
arrValue[0].cast()
}
}
override fun containsKey(key: K): Boolean {
return search(key) >= 0
}
override fun containsValue(value: V): Boolean {
if (end == 0) return false
for (index in 0 until end) {
if ((arrValue[index] ?: continue) == value) {
return true
}
}
return false
}
override fun get(key: K): V? {
return getByIndex(search(key))
}
fun getKeyByIndex(index: Int): K? {
return if (index < 0 || index >= end) {
null
} else {
arr[index].cast()
}
}
fun getByIndex(index: Int): V? {
return if (index < 0 || index >= end) {
null
} else {
arrValue[index].cast()
}
}
override fun isEmpty(): Boolean = end <= 0
class EntrySet<K, V>(private val map: ParallelArrayMap<K, V>) : MutableSet<MutableMap.MutableEntry<K, V>> {
override val size: Int get() = map.size
override fun contains(element: MutableMap.MutableEntry<K, V>): Boolean = map[element.key] == element.value
override fun isEmpty(): Boolean = map.isEmpty()
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = MapIterator(map)
override fun clear() = map.clear()
override fun containsAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
elements.forEach {
if (!contains(it)) return false
}
return true
}
override fun add(element: MutableMap.MutableEntry<K, V>): Boolean {
map[element.key] = element.value
return true
}
override fun addAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
elements.forEach { add(it) }
return true
}
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
val index = map.search(element.key)
val value = map.getByIndex(index)
return if (value == element.value) {
map.deleteByIndex(index)
true
} else {
false
}
}
override fun removeAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
elements.forEach { remove(it) }
return true
}
override fun retainAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
val contains = elements.filter { map[it.key] == it.value }
map.clear()
map.resize(contains.size)
addAll(contains)
return true
}
}
class MapIterator<K, V>(private val map: ParallelArrayMap<K, V>) : MutableIterator<MutableMap.MutableEntry<K, V>> {
private var index = 0
override fun hasNext(): Boolean {
@Suppress("ControlFlowWithEmptyBody")
while (++index < map.arr.size && index < map.end && map.arr[index] == null);
index--
return index < map.end
}
override fun next(): MutableMap.MutableEntry<K, V> = ParallelArrayMapEntry(map, index++)
override fun remove() {
map.deleteByIndex(index)
index--
}
}
class ParallelArrayMapEntry<K, V>(
val map: ParallelArrayMap<K, V>,
val index: Int
) : MutableMap.MutableEntry<K, V> {
override val key: K get() = map.getKeyByIndex(index).cast()
override val value: V get() = map.getByIndex(index).cast()
override fun setValue(newValue: V): V {
return map.setByIndex(index, newValue).cast()
}
}
}

View File

@ -0,0 +1,15 @@
package cn.tursom.core.stream.impl
import java.io.InputStream
class JavaInputStreamProxy(
val inputStream: cn.tursom.core.stream.InputStream
) : InputStream() {
override fun read(): Int = inputStream.read()
override fun read(b: ByteArray, off: Int, len: Int): Int = inputStream.read(b, off, len)
override fun skip(n: Long): Long {
inputStream.skip(n)
return n
}
}

View File

@ -1,6 +1,20 @@
dependencies {
implementation project(":")
implementation project(":utils")
api project(":utils:xml")
// kotlin
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
//implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
// kotlin
//implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
// OkHttp
implementation("com.squareup.okhttp3:okhttp:3.14.1")
//implementation("com.squareup.okhttp3:okhttp:3.14.1")
//implementation group: 'cglib', name: 'cglib', version: '3.3.0'
// https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson
api group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.9.0'
// https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit
compile group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.9.0'
// https://mvnrepository.com/artifact/org.jsoup/jsoup
api group: 'org.jsoup', name: 'jsoup', version: '1.13.1'
}

View File

@ -0,0 +1,23 @@
package cn.tursom.http
import retrofit2.Call
import retrofit2.CallAdapter
import retrofit2.Retrofit
import java.lang.reflect.Type
import java.util.concurrent.CompletableFuture
object BlockingCallAdapterFactory : CallAdapter.Factory() {
override fun get(
returnType: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): CallAdapter<out Any?, out Any?>? {
if (getRawType(returnType) == Call::class.java) return null
if (getRawType(returnType) == CompletableFuture::class.java) return null
if (annotations.any { it is retrofit2.SkipCallbackExecutor }) return null
return object : CallAdapter<Any?, Any?> {
override fun responseType(): Type = returnType
override fun adapt(call: Call<Any?>): Any? = call.execute().body()
}
}
}

View File

@ -0,0 +1,53 @@
package cn.tursom.http
import cn.tursom.core.isInheritanceFrom
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Node
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type
object HtmlConverterFactory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, out Node>? {
return if (type is Class<*> && Document::class.java.isInheritanceFrom(type)) {
DocumentResponseBodyConverter(retrofit.baseUrl().uri().toString())
} else {
null
}
}
override fun requestBodyConverter(
type: Type,
parameterAnnotations: Array<Annotation>,
methodAnnotations: Array<Annotation>,
retrofit: Retrofit
): Converter<in Node, RequestBody>? {
return if (type is Class<*> && type::class.java.isInheritanceFrom(Node::class.java)) {
NodeRequestBodyConverter
} else {
null
}
}
class DocumentResponseBodyConverter(
private val baseUri: String
) : Converter<ResponseBody, Document> {
override fun convert(value: ResponseBody): Document {
return Jsoup.parse(value.string(), baseUri)
}
}
object NodeRequestBodyConverter : Converter<Node, RequestBody> {
override fun convert(value: Node): RequestBody {
return RequestBody.create(MediaType.parse("text/html; charset=utf-8"), value.outerHtml())
}
}
}

View File

@ -0,0 +1,47 @@
package cn.tursom.http
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type
object StringConverterFactory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *>? {
return if (type == String::class.java) {
StringResponseBodyConverter
} else {
null
}
}
override fun requestBodyConverter(
type: Type,
parameterAnnotations: Array<Annotation>,
methodAnnotations: Array<Annotation>,
retrofit: Retrofit
): Converter<*, RequestBody>? {
return if (type == String::class.java) {
StringRequestBodyConverter
} else {
null
}
}
object StringResponseBodyConverter : Converter<ResponseBody, String> {
override fun convert(value: ResponseBody): String? {
return value.string()
}
}
object StringRequestBodyConverter : Converter<String, RequestBody> {
override fun convert(value: String): RequestBody {
return RequestBody.create(MediaType.parse("text/plain; charset=utf-8"), value)
}
}
}

View File

@ -0,0 +1,51 @@
package cn.tursom.http
import cn.tursom.core.isInheritanceFrom
import cn.tursom.utils.xml.Xml
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.dom4j.Document
import org.dom4j.Node
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type
object XmlConverterFactory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, out Node>? {
return if (type is Class<*> && Document::class.java.isInheritanceFrom(type)) {
DocumentResponseBodyConverter
} else {
null
}
}
override fun requestBodyConverter(
type: Type,
parameterAnnotations: Array<Annotation>,
methodAnnotations: Array<Annotation>,
retrofit: Retrofit
): Converter<in Node, RequestBody>? {
return if (type is Class<*> && type.isInheritanceFrom(Node::class.java)) {
NodeRequestBodyConverter
} else {
null
}
}
object DocumentResponseBodyConverter : Converter<ResponseBody, Document> {
override fun convert(value: ResponseBody): Document {
return Xml.saxReader.read(value.string().reader())
}
}
object NodeRequestBodyConverter : Converter<Node, RequestBody> {
override fun convert(value: Node): RequestBody {
return RequestBody.create(MediaType.parse("text/xml; charset=utf-8"), value.asXML())
}
}
}

View File

@ -14,15 +14,13 @@ 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)
fun proxyClient(
host: String = "127.0.0.1",
port: Int = 1080,
@ -31,13 +29,13 @@ object AsyncHttpRequest {
.proxy(Proxy(type, InetSocketAddress(host, port) as SocketAddress))
.retryOnConnectionFailure(true)
.build()
private suspend fun sendRequest(call: Call): Response = suspendCoroutine {
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)
}

View File

@ -0,0 +1,196 @@
package cn.tursom.http
import cn.tursom.utils.coroutine.MainDispatcher
import cn.tursom.utils.gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.jsoup.nodes.Document
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
interface CoroutineLocalTest {
@GET("/")
suspend fun test(): Document
@GET("/status")
suspend fun status(): List<RoomStatus>
@GET("status/{db}")
suspend fun status(@Path("db") db: String): RoomStatus
@GET("room/v1/Room/get_info")
suspend fun getRoomInfo(@Query("id") roomId: Int, @Query("from") from: String = "room"): String
}
suspend fun main() {
MainDispatcher.init()
val retrofit = Retrofit.Builder()
//.baseUrl("http://tursom.cn:15015")
//.baseUrl("https://www.baidu.com")
.baseUrl("https://api.live.bilibili.com")
.addCallAdapterFactory(BlockingCallAdapterFactory)
.addConverterFactory(StringConverterFactory)
.addConverterFactory(HtmlConverterFactory)
.addConverterFactory(XmlConverterFactory)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
GlobalScope.launch(Dispatchers.Main) {
launch {
println(Thread.currentThread().name)
}
val coroutineLocalTest: CoroutineLocalTest = retrofit.create()
//println(coroutineLocalTest.status())
println(coroutineLocalTest.getRoomInfo(801580))
}.join()
}
data class RoomStatus(
val connected: Boolean,
val db: String,
val liveUser: LiveUser,
val living: Boolean,
val recvCount: Int,
val roomId: Int,
val roomInfo: RoomInfo,
val totalCount: Int
)
data class LiveUser(
val info: Info,
val level: Level,
val san: Int
)
data class RoomInfo(
val allow_change_area_time: Int,
val allow_upload_cover_time: Int,
val area_id: Int,
val area_name: String,
val area_pendants: String,
val attention: Int,
val background: String,
val battle_id: Int,
val description: String,
val hot_words: List<String>,
val hot_words_status: Int,
val is_anchor: Int,
val is_portrait: Boolean,
val is_strict_room: Boolean,
val keyframe: String,
val live_status: Int,
val live_time: String,
val new_pendants: NewPendants,
val old_area_id: Int,
val online: Int,
val parent_area_id: Int,
val parent_area_name: String,
val pendants: String,
val pk_id: Int,
val pk_status: Int,
val room_id: Int,
val room_silent_level: Int,
val room_silent_second: Int,
val room_silent_type: String,
val short_id: Int,
val studio_info: StudioInfo,
val tags: String,
val title: String,
val uid: Int,
val up_session: String,
val user_cover: String,
val verify: String
)
data class Info(
val face: String,
val gender: Int,
val identification: Int,
val mobile_verify: Int,
val official_verify: OfficialVerify,
val platform_user_level: Int,
val rank: String,
val uid: Int,
val uname: String,
val vip_type: Int
)
data class Level(
val anchor_score: Int,
val color: Int,
val cost: Int,
val master_level: MasterLevel,
val rcost: Long,
val svip: Int,
val svip_time: String,
val uid: Int,
val update_time: String,
val user_level: Int,
val user_score: String,
val vip: Int,
val vip_time: String
)
data class OfficialVerify(
val desc: String,
val role: Int,
val type: Int
)
data class MasterLevel(
val anchor_score: Int,
val color: Int,
val current: List<Int>,
val level: Int,
val master_level_color: Int,
val next: List<Int>,
val sort: String,
val upgrade_score: Int
)
data class NewPendants(
val badge: Badge,
val frame: Frame,
val mobile_frame: MobileFrame
)
data class StudioInfo(
val master_list: List<Any>,
val status: Int
)
data class Badge(
val desc: String,
val name: String,
val position: Double,
val value: String
)
data class Frame(
val area: Int,
val area_old: Int,
val bg_color: String,
val bg_pic: String,
val desc: String,
val name: String,
val position: Int,
val use_old_area: Boolean,
val value: String
)
data class MobileFrame(
val area: Int,
val area_old: Int,
val bg_color: String,
val bg_pic: String,
val desc: String,
val name: String,
val position: Int,
val use_old_area: Boolean,
val value: String
)

View File

@ -0,0 +1,11 @@
package cn.tursom.utils.coroutine
import kotlinx.coroutines.CoroutineScope
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
class CoroutineContextScope(override val coroutineContext: CoroutineContext) : CoroutineScope {
companion object {
suspend fun get() = CoroutineContextScope(coroutineContext)
}
}

View File

@ -0,0 +1,53 @@
package cn.tursom.utils.coroutine
import cn.tursom.core.cast
import cn.tursom.core.toHexString
import kotlinx.coroutines.Job
import java.util.concurrent.ConcurrentHashMap
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
open class CoroutineLocal<T> {
open suspend fun get(): T? {
var attach: MutableMap<CoroutineLocal<*>, Any?>? = coroutineContext[CoroutineLocalContext]
if (attach == null) {
if (injectCoroutineLocalContext()) {
attach = coroutineContext[CoroutineLocalContext]
}
if (attach == null) {
val job = coroutineContext[Job] ?: return null
attach = attachMap[job]
}
}
return attach?.get(this)?.cast()
}
open suspend infix fun set(value: T): Boolean {
var attach: MutableMap<CoroutineLocal<*>, Any?>? = coroutineContext[CoroutineLocalContext]
if (attach == null) {
if (injectCoroutineLocalContext()) {
attach = coroutineContext[CoroutineLocalContext]
}
if (attach == null) {
val job = coroutineContext[Job] ?: return false
attach = attachMap[job]
if (attach == null) {
attach = HashMap()
attachMap[job] = attach
job.invokeOnCompletion {
attachMap.remove(job)
}
}
}
}
attach[this] = value
return true
}
override fun toString(): String = "CoroutineLocal@${hashCode().toHexString(false)}"
companion object {
private val attachMap = ConcurrentHashMap<CoroutineContext, MutableMap<CoroutineLocal<*>, Any?>>()
override fun toString(): String = attachMap.toString()
}
}

View File

@ -0,0 +1,45 @@
package cn.tursom.utils.coroutine
import cn.tursom.core.cast
import kotlinx.coroutines.ThreadContextElement
import kotlin.coroutines.CoroutineContext
open class CoroutineLocalContext(
private val mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) }
) : CoroutineContext.Element, ThreadContextElement<MutableMap<CoroutineLocal<*>, Any?>>, MutableMap<CoroutineLocal<*>, Any?> {
override val key: CoroutineContext.Key<*> get() = Key
private var map: MutableMap<CoroutineLocal<*>, Any?> = mapBuilder()
override fun toString(): String {
return "CoroutineLocalContext$map"
}
companion object Key : CoroutineContext.Key<CoroutineLocalContext>
override fun restoreThreadContext(context: CoroutineContext, oldState: MutableMap<CoroutineLocal<*>, Any?>) {
map = oldState
}
override fun updateThreadContext(context: CoroutineContext): MutableMap<CoroutineLocal<*>, Any?> {
val oldState = map
map = mapBuilder()
return oldState
}
@JvmName("getTyped")
operator fun <T> get(key: CoroutineLocal<T>): T? = map[key].cast()
operator fun <T> set(key: CoroutineLocal<T>, value: T?): T? = map.put(key, value).cast()
override val size: Int get() = map.size
override fun containsKey(key: CoroutineLocal<*>): Boolean = map.containsKey(key)
override fun containsValue(value: Any?): Boolean = map.containsValue(value)
override fun get(key: CoroutineLocal<*>): Any? = map[key]
override fun isEmpty(): Boolean = map.isEmpty()
override val entries: MutableSet<MutableMap.MutableEntry<CoroutineLocal<*>, Any?>> get() = map.entries
override val keys: MutableSet<CoroutineLocal<*>> get() = map.keys
override val values: MutableCollection<Any?> get() = map.values
override fun clear() = map.clear()
override fun put(key: CoroutineLocal<*>, value: Any?): Any? = map.put(key, value)
override fun putAll(from: Map<out CoroutineLocal<*>, Any?>) = map.putAll(from)
override fun remove(key: CoroutineLocal<*>): Any? = map.remove(key)
}

View File

@ -0,0 +1,16 @@
package cn.tursom.utils.coroutine
import cn.tursom.core.cast
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
class CoroutineLocalContinuation(
private val completion: Continuation<*>
) : Continuation<Any?> by completion.cast() {
override val context: CoroutineContext = completion.context + if (completion.context[CoroutineLocalContext] == null) {
CoroutineLocalContext()
} else {
EmptyCoroutineContext
}
}

View File

@ -0,0 +1,37 @@
package cn.tursom.utils.coroutine
import cn.tursom.core.cast
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
class CoroutineScopeContext(
var coroutineScope: CoroutineScope = GlobalScope
) : CoroutineContext.Element {
override val key: CoroutineContext.Key<*> get() = Companion
override fun toString(): String = "CoroutineScopeContext(coroutineScope=$coroutineScope)"
companion object : CoroutineContext.Key<CoroutineScopeContext>, CoroutineLocal<CoroutineScope>() {
override suspend fun get(): CoroutineScope = coroutineContext[this]?.coroutineScope ?: super.get()
?: coroutineContext[Job]?.let {
if (it is CoroutineScope) {
it.cast<CoroutineScope>()
} else {
null
}
} ?: CoroutineContextScope(coroutineContext)
override suspend infix fun set(value: CoroutineScope): Boolean {
val coroutineScopeContext = coroutineContext[this]
return if (coroutineScopeContext != null) {
coroutineScopeContext.coroutineScope = value
true
} else {
super.set(value)
}
}
}
}

View File

@ -0,0 +1,75 @@
package cn.tursom.utils.coroutine
import cn.tursom.core.SimpThreadLocal
import cn.tursom.core.cast
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
object CurrentThreadCoroutineScope {
private val eventLoopThreadLocal: SimpThreadLocal<CoroutineDispatcher> = SimpThreadLocal {
newBlockingEventLoop()
}
private suspend fun getCoroutineScope(): CoroutineScope {
val eventLoop = eventLoopThreadLocal.get()
val coroutineScopeContext = CoroutineScopeContext()
val newBlockingCoroutine = newBlockingCoroutine(
coroutineContext + coroutineScopeContext + Dispatchers.Unconfined,
Thread.currentThread(),
eventLoop
)
coroutineScopeContext.coroutineScope = newBlockingCoroutine
return newBlockingCoroutine
}
suspend fun launch(
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
val coroutineScope = getCoroutineScope()
//coroutineScope.launch(start = start, block = block)
coroutineScope.start(start, block = block)
return coroutineScope as Job
}
private val EventLoop = Class.forName("kotlinx.coroutines.EventLoop")
private val EventLoopShouldBeProcessedFromContext = EventLoop.methods
.first { it.name == "shouldBeProcessedFromContext" }
.apply { isAccessible = true }
private val BlockingEventLoop = Class.forName("kotlinx.coroutines.BlockingEventLoop")
private val BlockingEventLoopConstructor = BlockingEventLoop
.getConstructor(Thread::class.java)
.apply { isAccessible = true }
private fun newBlockingEventLoop(thread: Thread = Thread.currentThread()): CoroutineDispatcher {
return BlockingEventLoopConstructor.newInstance(thread) as CoroutineDispatcher
}
private val BlockingCoroutine = Class.forName("kotlinx.coroutines.BlockingCoroutine")
private val BlockingCoroutineConstructor = BlockingCoroutine.constructors[0].apply { isAccessible = true }
private val BlockingCoroutineStart = BlockingCoroutine.methods.first { it.name == "start" && it.parameters.size == 3 }.apply { isAccessible = true }
private val BlockingCoroutineJoinBlocking = BlockingCoroutine.methods.first { it.name == "joinBlocking" }.apply { isAccessible = true }
//private val BlockingCoroutineOnCompleted = BlockingCoroutine.methods.first { it.name == "onCompleted" }.apply { isAccessible = true }
private fun newBlockingCoroutine(
coroutineContext: CoroutineContext,
thread: Thread = Thread.currentThread(),
eventLoop: CoroutineDispatcher
): CoroutineScope {
return BlockingCoroutineConstructor.newInstance(coroutineContext, thread, eventLoop).cast()
}
private fun <T> CoroutineScope.start(
start: CoroutineStart = CoroutineStart.DEFAULT,
receiver: CoroutineScope = this,
block: suspend CoroutineScope.() -> T
) {
BlockingCoroutineStart.invoke(this, start, receiver, block)
}
private fun <T> CoroutineScope.joinBlocking(): T {
return BlockingCoroutineJoinBlocking.invoke(this).cast()
}
}

View File

@ -0,0 +1,13 @@
package cn.tursom.utils.coroutine
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.MainCoroutineDispatcher
import kotlinx.coroutines.internal.MainDispatcherFactory
@Suppress("unused")
@InternalCoroutinesApi
class MainCoroutineDispatcherFactory : MainDispatcherFactory {
override val loadPriority: Int = 1
override fun createDispatcher(allFactories: List<MainDispatcherFactory>): MainCoroutineDispatcher = MainDispatcher
}

View File

@ -0,0 +1,51 @@
package cn.tursom.utils.coroutine
import cn.tursom.core.cast
import kotlinx.coroutines.ExecutorCoroutineDispatcher
import kotlinx.coroutines.MainCoroutineDispatcher
import kotlinx.coroutines.asCoroutineDispatcher
import java.io.Closeable
import java.lang.reflect.Field
import java.lang.reflect.Modifier
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.concurrent.thread
import kotlin.coroutines.CoroutineContext
object MainDispatcher : MainCoroutineDispatcher(), Closeable {
private val loaded = AtomicBoolean(false)
private val dispatcher: ExecutorCoroutineDispatcher = Executors.newSingleThreadExecutor {
thread(start = false, block = it::run, name = "MainDispatcher", isDaemon = false)
}.asCoroutineDispatcher()
private var oldDispatcher: MainCoroutineDispatcher? = null
private val mainDispatcherLoader: Class<*> = Class.forName("kotlinx.coroutines.internal.MainDispatcherLoader")
private val dispatcherField: Field = mainDispatcherLoader.getDeclaredField("dispatcher").also { dispatcher ->
dispatcher.isAccessible = true
val mf: Field = Field::class.java.getDeclaredField("modifiers")
mf.isAccessible = true
mf.setInt(dispatcher, dispatcher.modifiers and Modifier.FINAL.inv())
}
fun init() {
if (loaded.compareAndSet(false, true)) {
oldDispatcher = dispatcherField.get(null).cast()
dispatcherField.set(null, this)
}
}
fun resume() {
if (loaded.compareAndSet(true, false) && oldDispatcher != null) {
dispatcherField.set(null, oldDispatcher)
}
}
override val immediate: MainCoroutineDispatcher get() = this
override fun dispatch(context: CoroutineContext, block: Runnable) {
dispatcher.dispatch(context, block)
}
override fun close() {
dispatcher.close()
}
}

View File

@ -0,0 +1,229 @@
@file:Suppress("unused")
package cn.tursom.utils.coroutine
import cn.tursom.core.cast
import cn.tursom.core.forAllFields
import cn.tursom.core.isInheritanceFrom
import kotlinx.coroutines.*
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.coroutineContext
fun CoroutineScope.launchWithCoroutineLocalContext(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> Unit
): Job {
return launch(context + CoroutineLocalContext(mapBuilder), start, block)
}
@Suppress("DeferredIsResult")
fun <T> CoroutineScope.asyncWithCoroutineLocalContext(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> T
): Deferred<T> {
return async(context + CoroutineLocalContext(mapBuilder), start, block)
}
suspend fun <T> withCoroutineLocalContext(
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> T
): T {
return withContext(CoroutineLocalContext(mapBuilder), block)
}
@Throws(InterruptedException::class)
fun <T> runBlockingWithCoroutineLocalContext(
context: CoroutineContext = EmptyCoroutineContext,
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> T
): T {
return runBlocking(context + CoroutineLocalContext(mapBuilder), block)
}
fun CoroutineScope.launchWithCoroutineScopeContext(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
return launch(context + CoroutineScopeContext(this), start, block)
}
@Suppress("DeferredIsResult")
fun <T> CoroutineScope.asyncWithCoroutineScopeContext(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T> {
return async(context + CoroutineScopeContext(this), start, block)
}
fun CoroutineScope.launchWithCoroutineLocalAndCoroutineScopeContext(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> Unit
): Job {
return launch(context + CoroutineLocalContext(mapBuilder) + CoroutineScopeContext(this), start, block)
}
@Suppress("DeferredIsResult")
fun <T> CoroutineScope.asyncWithCoroutineLocalAndCoroutineScopeContext(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> T
): Deferred<T> {
return async(context + CoroutineLocalContext(mapBuilder) + CoroutineScopeContext(this), start, block)
}
@Throws(InterruptedException::class)
fun <T> runBlockingWithCoroutineLocalAndCoroutineScopeContext(
context: CoroutineContext = EmptyCoroutineContext,
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> T
): T {
return runBlocking(context + CoroutineLocalContext(mapBuilder) + CoroutineScopeContext()) {
CoroutineScopeContext set this
block()
}
}
fun CoroutineScope.launchWithEnhanceContext(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> Unit
): Job {
return launch(context + CoroutineLocalContext(mapBuilder), start, block)
}
@Suppress("DeferredIsResult")
fun <T> CoroutineScope.asyncWithEnhanceContext(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> T
): Deferred<T> {
return async(context + CoroutineLocalContext(mapBuilder), start, block)
}
@Throws(InterruptedException::class)
fun <T> runBlockingWithEnhanceContext(
context: CoroutineContext = EmptyCoroutineContext,
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
block: suspend CoroutineScope.() -> T
): T {
return runBlocking(context + CoroutineLocalContext(mapBuilder)) {
block()
}
}
suspend fun <T> runWithCoroutineLocalContext(
block: suspend () -> T
): T {
val continuation: Any? = getContinuation()
val coroutineLocalContinuation = if (continuation is Continuation<*>) {
CoroutineLocalContinuation(continuation.cast())
} else {
return continuation.cast()
}
return (block.cast<(Any?) -> T>()).invoke(coroutineLocalContinuation)
}
suspend fun <T> runWithCoroutineLocal(
block: suspend () -> T
): T {
if (coroutineContext[CoroutineLocalContext] == null) {
return runWithCoroutineLocalContext(block)
}
return block()
}
@Suppress("NOTHING_TO_INLINE")
inline fun getContinuation(continuation: Continuation<*>): Continuation<*> {
return continuation
}
suspend inline fun getContinuation(): Continuation<*> {
val getContinuation: (continuation: Continuation<*>) -> Continuation<*> = ::getContinuation
return (getContinuation.cast<suspend () -> Continuation<*>>()).invoke()
}
suspend fun injectCoroutineContext(
coroutineContext: CoroutineContext,
key: CoroutineContext.Key<out CoroutineContext.Element>? = null
): Boolean {
return if (key == null || coroutineContext[key] == null) {
getContinuation().injectCoroutineContext(coroutineContext, key)
} else {
true
}
}
suspend fun injectCoroutineLocalContext(coroutineLocalContext: CoroutineLocalContext? = null): Boolean {
return if (coroutineContext[CoroutineLocalContext] == null) {
getContinuation().injectCoroutineLocalContext(coroutineLocalContext)
} else {
true
}
}
fun Continuation<*>.injectCoroutineLocalContext(
coroutineLocalContext: CoroutineLocalContext? = null
): Boolean {
return if (context[CoroutineLocalContext] == null) {
injectCoroutineContext(coroutineLocalContext ?: CoroutineLocalContext(), CoroutineLocalContext)
} else {
true
}
}
private val BaseContinuationImpl = Class.forName("kotlin.coroutines.jvm.internal.BaseContinuationImpl")
private val BaseContinuationImplCompletion = BaseContinuationImpl.getDeclaredField("completion").apply { isAccessible = true }
fun Continuation<*>.injectCoroutineContext(
coroutineContext: CoroutineContext,
key: CoroutineContext.Key<out CoroutineContext.Element>? = null
): Boolean {
if (key != null && context[key] != null) return true
if (BaseContinuationImpl.isInstance(this)) {
BaseContinuationImplCompletion.get(this).cast<Continuation<*>>().injectCoroutineContext(coroutineContext, key)
}
combinedContext(context)
if (context[CoroutineLocalContext] != null) return true
javaClass.forAllFields {
if (!it.type.isInheritanceFrom(CoroutineContext::class.java)) {
return@forAllFields
}
it.isAccessible = true
it.set(this, it.get(this).cast<CoroutineContext>() + coroutineContext)
}
return context[CoroutineLocalContext] != null
}
private val combinedContextClass = Class.forName("kotlin.coroutines.CombinedContext")
private val left = combinedContextClass.getDeclaredField("left").apply { isAccessible = true }
fun combinedContext(coroutineContext: CoroutineContext): Boolean {
if (!combinedContextClass.isInstance(coroutineContext)) return false
if (coroutineContext[CoroutineLocalContext] == null) {
val leftObj = left.get(coroutineContext).cast<CoroutineContext>()
left.set(coroutineContext, leftObj + CoroutineLocalContext())
}
return true
}
//fun CoroutineScope.runOnUiThread(action: suspend CoroutineScope.() -> Unit): Job {
// return launch(Dispatchers.Main, block = action)
//}
suspend fun <T> runOnUiThread(coroutineContext: CoroutineContext = EmptyCoroutineContext, action: suspend CoroutineScope.() -> T): T {
return withContext(coroutineContext + Dispatchers.Main, action)
}

View File

@ -0,0 +1 @@
cn.tursom.utils.coroutine.MainDispatcherFactory

View File

@ -0,0 +1,62 @@
package cn.tursom.utils.coroutine
import kotlinx.coroutines.*
import kotlin.coroutines.ContinuationInterceptor
import kotlin.coroutines.coroutineContext
val testCoroutineLocal = CoroutineLocal<Int>()
suspend fun testCustomContext() {
testCoroutineLocal.set(1)
testInlineCustomContext()
}
suspend fun testInlineCustomContext() {
println(coroutineContext)
println("===================")
}
annotation class Request(val url: String, val method: String = "GET")
interface CoroutineLocalTest {
@Request("http://tursom.cn:15015/living")
suspend fun test(): String
}
class Test : CoroutineScope by MainScope() {
suspend fun test() {
testCoroutineLocal.set(1)
println(coroutineContext)
coroutineScope {
println(coroutineContext)
delay(1)
}
}
}
object R : () -> R {
override fun invoke(): R = this
}
val threadLocal = ThreadLocal<String>()
fun main() = runBlocking {
println(coroutineContext[ContinuationInterceptor])
MainDispatcher.init()
runOnUiThread(threadLocal.asContextElement()) {
threadLocal.set("hello")
//Test().test()
//println(testCoroutineLocal.get())
println(threadLocal.get())
println(coroutineContext)
launch(Dispatchers.Main) {
println(threadLocal.get())
println(coroutineContext)
}
//runOnUiThread {
// println(coroutineContext)
// println(testCoroutineLocal.get())
//}
}
MainDispatcher.close()
}

View File

@ -1,4 +1,4 @@
dependencies {
// XML
implementation group: 'dom4j', name: 'dom4j', version: '1.6.1'
// XML https://mvnrepository.com/artifact/org.dom4j/dom4j
compile group: 'org.dom4j', name: 'dom4j', version: '2.1.3'
}