add ConverterFactory

This commit is contained in:
tursom 2020-07-19 02:47:10 +08:00
parent 71ce18234b
commit 604f87ff66
8 changed files with 380 additions and 21 deletions

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

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

@ -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<Int>()
@ -19,11 +15,31 @@ suspend fun testInlineCustomContext() {
println("===================")
}
fun main() {
MainDispatcher.init()
GlobalScope.launch(Dispatchers.Main) {
println(Thread.currentThread().name)
}.invokeOnCompletion {
Dispatchers.Main.cast<Closeable>().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()
}

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