diff --git a/utils/async-http/build.gradle b/utils/async-http/build.gradle index a5707ae..532426e 100644 --- a/utils/async-http/build.gradle +++ b/utils/async-http/build.gradle @@ -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 + implementation group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.9.0' + // https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit + implementation 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' } diff --git a/utils/async-http/src/main/kotlin/cn/tursom/http/HtmlConverterFactory.kt b/utils/async-http/src/main/kotlin/cn/tursom/http/HtmlConverterFactory.kt new file mode 100644 index 0000000..4711920 --- /dev/null +++ b/utils/async-http/src/main/kotlin/cn/tursom/http/HtmlConverterFactory.kt @@ -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, + retrofit: Retrofit + ): Converter? { + return if (type is Class<*> && Document::class.java.isInheritanceFrom(type)) { + DocumentResponseBodyConverter(retrofit.baseUrl().uri().toString()) + } else { + null + } + } + + override fun requestBodyConverter( + type: Type, + parameterAnnotations: Array, + methodAnnotations: Array, + retrofit: Retrofit + ): Converter? { + return if (type is Class<*> && type::class.java.isInheritanceFrom(Node::class.java)) { + NodeRequestBodyConverter + } else { + null + } + } + + class DocumentResponseBodyConverter( + private val baseUri: String + ) : Converter { + override fun convert(value: ResponseBody): Document { + return Jsoup.parse(value.string(), baseUri) + } + } + + object NodeRequestBodyConverter : Converter { + override fun convert(value: Node): RequestBody { + return RequestBody.create(MediaType.parse("text/html; charset=utf-8"), value.outerHtml()) + } + } +} \ No newline at end of file diff --git a/utils/async-http/src/main/kotlin/cn/tursom/http/StringConverterFactory.kt b/utils/async-http/src/main/kotlin/cn/tursom/http/StringConverterFactory.kt new file mode 100644 index 0000000..2baa5a4 --- /dev/null +++ b/utils/async-http/src/main/kotlin/cn/tursom/http/StringConverterFactory.kt @@ -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, + retrofit: Retrofit + ): Converter? { + return if (type == String::class.java) { + StringResponseBodyConverter + } else { + null + } + } + + override fun requestBodyConverter( + type: Type, + parameterAnnotations: Array, + methodAnnotations: Array, + retrofit: Retrofit + ): Converter<*, RequestBody>? { + return if (type == String::class.java) { + StringRequestBodyConverter + } else { + null + } + } + + object StringResponseBodyConverter : Converter { + override fun convert(value: ResponseBody): String? { + return value.string() + } + } + + object StringRequestBodyConverter : Converter { + override fun convert(value: String): RequestBody { + return RequestBody.create(MediaType.parse("text/plain; charset=utf-8"), value) + } + } +} \ No newline at end of file diff --git a/utils/async-http/src/main/kotlin/cn/tursom/http/XmlConverterFactory.kt b/utils/async-http/src/main/kotlin/cn/tursom/http/XmlConverterFactory.kt new file mode 100644 index 0000000..c1f2ae4 --- /dev/null +++ b/utils/async-http/src/main/kotlin/cn/tursom/http/XmlConverterFactory.kt @@ -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, + retrofit: Retrofit + ): Converter? { + return if (type is Class<*> && Document::class.java.isInheritanceFrom(type)) { + DocumentResponseBodyConverter + } else { + null + } + } + + override fun requestBodyConverter( + type: Type, + parameterAnnotations: Array, + methodAnnotations: Array, + retrofit: Retrofit + ): Converter? { + return if (type is Class<*> && type.isInheritanceFrom(Node::class.java)) { + NodeRequestBodyConverter + } else { + null + } + } + + object DocumentResponseBodyConverter : Converter { + override fun convert(value: ResponseBody): Document { + return Xml.saxReader.read(value.string().reader()) + } + } + + object NodeRequestBodyConverter : Converter { + override fun convert(value: Node): RequestBody { + return RequestBody.create(MediaType.parse("text/xml; charset=utf-8"), value.asXML()) + } + } +} \ No newline at end of file diff --git a/utils/async-http/src/main/kotlin/cn/tursom/utils/AsyncHttpRequest.kt b/utils/async-http/src/main/kotlin/cn/tursom/utils/AsyncHttpRequest.kt index 5d229bb..ecbb6ef 100644 --- a/utils/async-http/src/main/kotlin/cn/tursom/utils/AsyncHttpRequest.kt +++ b/utils/async-http/src/main/kotlin/cn/tursom/utils/AsyncHttpRequest.kt @@ -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) } diff --git a/utils/async-http/src/test/kotlin/cn/tursom/http/test.kt b/utils/async-http/src/test/kotlin/cn/tursom/http/test.kt new file mode 100644 index 0000000..9b2573b --- /dev/null +++ b/utils/async-http/src/test/kotlin/cn/tursom/http/test.kt @@ -0,0 +1,180 @@ +package cn.tursom.http + +import cn.tursom.utils.gson +import org.jsoup.nodes.Document +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.create +import retrofit2.http.GET +import retrofit2.http.Path + +interface CoroutineLocalTest { + @GET("/") + suspend fun test(): Document + + @GET("/status") + suspend fun status(): List + + @GET("status/{db}") + suspend fun status(@Path("db") db: String): RoomStatus +} + +suspend fun main() { + val retrofit = Retrofit.Builder() + //.baseUrl("http://tursom.cn:15015") + .baseUrl("https://www.baidu.com") + .addConverterFactory(StringConverterFactory) + .addConverterFactory(HtmlConverterFactory) + .addConverterFactory(XmlConverterFactory) + .addConverterFactory(GsonConverterFactory.create(gson)) + .build() + val coroutineLocalTest: CoroutineLocalTest = retrofit.create() + println(coroutineLocalTest.test()) + //println(coroutineLocalTest.status()) + //println(coroutineLocalTest.status("wula")) +} + +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, + 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, + val level: Int, + val master_level_color: Int, + val next: List, + 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, + 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 +) \ No newline at end of file diff --git a/utils/src/test/kotlin/cn/tursom/utils/coroutine/CoroutineLocalTest.kt b/utils/src/test/kotlin/cn/tursom/utils/coroutine/CoroutineLocalTest.kt index fe319b3..a91cd80 100644 --- a/utils/src/test/kotlin/cn/tursom/utils/coroutine/CoroutineLocalTest.kt +++ b/utils/src/test/kotlin/cn/tursom/utils/coroutine/CoroutineLocalTest.kt @@ -1,10 +1,6 @@ package cn.tursom.utils.coroutine -import cn.tursom.core.cast -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import java.io.Closeable +import kotlinx.coroutines.* import kotlin.coroutines.coroutineContext val testCoroutineLocal = CoroutineLocal() @@ -19,11 +15,31 @@ suspend fun testInlineCustomContext() { println("===================") } -fun main() { - MainDispatcher.init() - GlobalScope.launch(Dispatchers.Main) { - println(Thread.currentThread().name) - }.invokeOnCompletion { - Dispatchers.Main.cast().close() +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(): Job { + println(this) + println(coroutineContext) + return coroutineScope { + println(this) + println(coroutineContext) + println(Thread.currentThread().name) + delay(1) + return@coroutineScope launch { + println(Thread.currentThread().name) + } + } } +} + +suspend fun main() { + MainDispatcher.init() + Test().test().join() + MainDispatcher.close() } \ No newline at end of file diff --git a/utils/xml/build.gradle b/utils/xml/build.gradle index 9c0fc7f..1734507 100644 --- a/utils/xml/build.gradle +++ b/utils/xml/build.gradle @@ -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' }