0
0
mirror of https://github.com/tursom/TursomServer.git synced 2025-04-15 05:50:46 +08:00
This commit is contained in:
tursom 2021-09-03 17:34:02 +08:00
parent 5209651184
commit f67c39ac88
10 changed files with 39 additions and 369 deletions

View File

@ -10,9 +10,9 @@ dependencies {
api(project(":ts-core:ts-buffer"))
implementation(project(":ts-core:ts-xml"))
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1")
api(group = "com.squareup.retrofit2", name = "converter-gson", version = "2.9.0")
// https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit
api(group = "com.squareup.retrofit2", name = "retrofit", version = "2.9.0")
compileOnly("com.squareup.okhttp3:okhttp:4.9.1")
//api(group = "com.squareup.retrofit2", name = "converter-gson", version = "2.9.0")
//api(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.14.2")

View File

@ -1,23 +0,0 @@
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

@ -1,53 +0,0 @@
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

@ -1,175 +0,0 @@
package cn.tursom.http
import cn.tursom.core.buffer.ByteBuffer
import cn.tursom.core.buffer.impl.HeapByteBuffer
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLConnection
import java.net.URLEncoder
import java.nio.charset.Charset
import java.util.zip.GZIPInputStream
@Suppress("unused", "MemberVisibilityCanBePrivate")
object HttpRequest {
val defaultHeader = mapOf(
"accept" to "*/*",
"connection" to "Keep-Alive",
"user-agent" to "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)",
"Accept-Encoding" to "gzip, deflate, sdch, br"
)
fun URLConnection.getCharset(): Charset {
val contentType = getHeaderField("content-type")
return if (contentType == null) {
Charsets.UTF_8
} else {
val startIndex = contentType.indexOf("charset=", ignoreCase = true) + 8
if (startIndex < 8) {
Charsets.UTF_8
} else {
var endIndex = contentType.indexOf(";", startIndex = startIndex, ignoreCase = true)
if (endIndex < 0) endIndex = contentType.length
if (startIndex == endIndex) {
Charsets.UTF_8
} else {
Charset.forName(contentType.substring(startIndex, endIndex))
}
}
}
}
fun URLConnection.getRealInputStream(): InputStream {
return if (getHeaderField("content-encoding")?.contains("gzip", true) == true) {
GZIPInputStream(inputStream)
} else {
inputStream
}
}
fun send(
method: String = "GET",
url: String,
headers: Map<String, String> = defaultHeader,
data: ByteBuffer? = null
): HttpURLConnection {
val realUrl = URL(url)
val conn = realUrl.openConnection() as HttpURLConnection
headers.forEach { (key, value) ->
conn.setRequestProperty(key, value)
}
if (data != null) conn.doOutput = true
conn.doInput = true
conn.requestMethod = method
data?.let {
conn.outputStream.use { out ->
data.writeTo(out)
out.flush()
}
}
return conn
}
fun send(
method: String = "GET",
url: String,
headers: Map<String, String> = defaultHeader,
data: ByteArray?
) = send(method, url, headers, data?.let { HeapByteBuffer(data) })
fun getContextStream(
method: String = "GET",
url: String,
headers: Map<String, String> = defaultHeader,
data: ByteBuffer? = null
): InputStream = send(method, url, headers, data).inputStream
fun getContext(
method: String = "GET",
url: String,
headers: Map<String, String> = defaultHeader,
data: ByteBuffer? = null
) = send(method, url, headers, data).getRealInputStream().readBytes()
fun getContextStr(
method: String = "GET",
url: String,
headers: Map<String, String> = defaultHeader,
data: ByteBuffer? = null
): String {
val conn = send(method, url, headers, data)
return conn.getRealInputStream().readBytes().toString(conn.getCharset())
}
fun doGet(
url: String,
param: String? = null,
headers: Map<String, String> = defaultHeader
): String = getContextStr(
"GET", if (param != null) {
"$url?$param"
} else {
url
}, headers
)
infix operator fun get(url: String): String = doGet(url, null)
fun doGet(
url: String,
param: Map<String, String>,
headers: Map<String, String> = defaultHeader
): String {
val paramSB = StringBuilder()
return doGet(url, run {
param.forEach {
paramSB.append("${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}&")
}
if (paramSB.isNotEmpty()) paramSB.deleteCharAt(paramSB.lastIndex)
paramSB.toString()
}, headers)
}
fun doPost(
url: String,
data: ByteArray,
headers: Map<String, String> = defaultHeader
): String = getContextStr("POST", url, headers, HeapByteBuffer(data))
fun doPost(
url: String,
param: Map<String, String>,
headers: Map<String, String> = defaultHeader
): String {
val sb = StringBuilder()
param.forEach { (key, value) ->
sb.append("${URLEncoder.encode(key, "utf-8")}=${URLEncoder.encode(value, "utf-8")}&")
}
if (sb.isNotEmpty()) sb.deleteCharAt(sb.lastIndex)
return doPost(url, sb.toString().toByteArray(), headers)
}
fun doHead(
url: String,
param: String,
headers: Map<String, String> = defaultHeader
): Map<String, List<String>> = send("HEAD", "$url?$param", headers).headerFields
fun doHead(
url: String,
param: Map<String, String>,
headers: Map<String, String> = defaultHeader
): Map<String, List<String>> {
val paramSB = StringBuilder()
return doHead(url, run {
param.forEach {
paramSB.append("${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}&")
}
if (paramSB.isNotEmpty()) paramSB.deleteCharAt(paramSB.lastIndex)
paramSB.toString()
}, headers)
}
}

View File

@ -1,47 +0,0 @@
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

@ -1,51 +0,0 @@
package cn.tursom.http
import cn.tursom.core.isInheritanceFrom
import cn.tursom.core.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

@ -1,6 +1,7 @@
package cn.tursom.utils
package cn.tursom.http.client
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import java.io.File
import java.io.IOException
import java.net.InetSocketAddress
@ -11,7 +12,6 @@ import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
@Suppress("unused", "MemberVisibilityCanBePrivate")
object AsyncHttpRequest {
val defaultClient: OkHttpClient = OkHttpClient().newBuilder()
@ -106,7 +106,7 @@ object AsyncHttpRequest {
client: OkHttpClient = defaultClient
) = post(
url,
RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), body),
RequestBody.create("text/plain;charset=utf-8".toMediaTypeOrNull(), body),
headers,
client
)
@ -118,7 +118,7 @@ object AsyncHttpRequest {
client: OkHttpClient = defaultClient
) = post(
url,
RequestBody.create(MediaType.parse("application/octet-stream"), body),
RequestBody.create("application/octet-stream".toMediaTypeOrNull(), body),
headers,
client
)
@ -130,7 +130,7 @@ object AsyncHttpRequest {
client: OkHttpClient = defaultClient
) = post(
url,
RequestBody.create(MediaType.parse("application/octet-stream"), body),
RequestBody.create("application/octet-stream".toMediaTypeOrNull(), body),
headers,
client
)
@ -151,7 +151,7 @@ object AsyncHttpRequest {
client: OkHttpClient
): String {
val response = get(url, param, headers, client)
return response.body()!!.string()
return response.body!!.string()
}
@Suppress("BlockingMethodInNonBlockingContext")
@ -160,7 +160,7 @@ object AsyncHttpRequest {
body: RequestBody,
headers: Map<String, String>? = null,
client: OkHttpClient
): String = post(url, body, headers, client).body()!!.string()
): String = post(url, body, headers, client).body!!.string()
suspend fun postStr(
url: String,
@ -196,7 +196,7 @@ object AsyncHttpRequest {
client: OkHttpClient
): String = postStr(
url,
RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), body),
RequestBody.create("text/plain;charset=utf-8".toMediaTypeOrNull(), body),
headers,
client
)
@ -215,7 +215,7 @@ object AsyncHttpRequest {
client: OkHttpClient
): String = postStr(
url,
RequestBody.create(MediaType.parse("application/octet-stream"), body),
RequestBody.create("application/octet-stream".toMediaTypeOrNull(), body),
headers,
client
)
@ -237,7 +237,7 @@ object AsyncHttpRequest {
param: Map<String, String>? = null,
headers: Map<String, String>? = null,
client: OkHttpClient
): ByteArray = get(url, param, headers, client).body()!!.bytes()
): ByteArray = get(url, param, headers, client).body!!.bytes()
@Suppress("BlockingMethodInNonBlockingContext")
@ -246,7 +246,7 @@ object AsyncHttpRequest {
body: RequestBody,
headers: Map<String, String>? = null,
client: OkHttpClient
): ByteArray = post(url, body, headers, client).body()!!.bytes()
): ByteArray = post(url, body, headers, client).body!!.bytes()
suspend fun postByteArray(
@ -291,7 +291,7 @@ object AsyncHttpRequest {
client: OkHttpClient
): ByteArray = postByteArray(
url,
RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), body),
RequestBody.create("text/plain;charset=utf-8".toMediaTypeOrNull(), body),
headers,
client
)
@ -314,8 +314,8 @@ object AsyncHttpRequest {
client: OkHttpClient
): ByteArray = postByteArray(
url,
RequestBody.create(MediaType.parse("application/octet-stream"), body),
RequestBody.create("application/octet-stream".toMediaTypeOrNull(), body),
headers,
client
)
}
}

View File

@ -9,7 +9,7 @@ dependencies {
api(project(":ts-core:ts-buffer"))
api(project(":ts-core:ts-log"))
compileOnly(project(":ts-socket"))
api(group = "io.netty", name = "netty-all", version = "4.1.67.Final")
api(group = "io.netty", name = "netty-all", version = nettyVersion)
}

View File

@ -150,8 +150,10 @@ open class NettyHttpContent(
if (log.traceEnabled) {
log?.trace("write {}", message)
}
getResponseBodyBuf().addComponent(Unpooled.wrappedBuffer(message.toByteArray()))
//responseBody.write(message.toByteArray())
val compositeByteBuf = getResponseBodyBuf()
val bytes = message.toByteArray()
compositeByteBuf.addComponent(Unpooled.wrappedBuffer(bytes))
compositeByteBuf.writerIndex(compositeByteBuf.writerIndex() + bytes.size)
}
override fun write(byte: Byte) {

View File

@ -0,0 +1,17 @@
package cn.tursom.web.netty
import io.netty.channel.ChannelHandler
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.timeout.TimeoutException
@ChannelHandler.Sharable
object TimeoutHandler : ChannelHandler {
override fun handlerAdded(ctx: ChannelHandlerContext?) {}
override fun handlerRemoved(ctx: ChannelHandlerContext?) {}
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable?) {
when (cause) {
is TimeoutException -> ctx.close()
else -> ctx.fireExceptionCaught(cause)
}
}
}