diff --git a/app/build.gradle b/app/build.gradle index bb19ab3e..d9cbfff9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -86,10 +86,10 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1" // https://mvnrepository.com/artifact/com.sun.net.httpserver/http - - // implementation("com.sun.net.httpserver:http:20070405") - // implementation("com.hibegin:simplewebserver:0.1.15") - implementation("com.github.codeborne.klite:klite-server:1.7.0") + implementation(files("libs/sun-common-server.jar")) + implementation("com.sun.net.httpserver:http:20070405") + // implementation("com.hibegin:simplewebserver:0.1.15") + //implementation("com.github.codeborne.klite:klite-server:1.7.0") //implementation 'wang.harlon.quickjs:wrapper-java:1.0.0' diff --git a/app/src/main/java/com/github/catvod/utils/ProxyServer.kt b/app/src/main/java/com/github/catvod/utils/ProxyServer.kt index 7ff2e0d2..a50dd566 100644 --- a/app/src/main/java/com/github/catvod/utils/ProxyServer.kt +++ b/app/src/main/java/com/github/catvod/utils/ProxyServer.kt @@ -1,10 +1,17 @@ package com.github.catvod.utils - import com.github.catvod.crawler.SpiderDebug import com.github.catvod.net.OkHttp import com.google.gson.Gson -import klite.Server +import com.sun.net.httpserver.HttpExchange +import com.sun.net.httpserver.HttpServer +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.launch +import java.io.BufferedOutputStream +import java.io.OutputStreamWriter import java.net.InetSocketAddress import java.nio.charset.Charset @@ -13,59 +20,75 @@ object ProxyServer { private val THREAD_NUM = Runtime.getRuntime().availableProcessors() * 2 private const val partSize = 1024 * 1024 * 1 private var port = 12345 - private var server: Server? = null + private var httpServer: HttpServer? = null private val infos = mutableMapOf>>(); fun stop() { - server?.stop(1000) + httpServer?.stop(1_000) } fun start() { try { - server = Server(InetSocketAddress(port)).apply { - context("/api") { - get("/hello") { "Hello, world!" } + httpServer = HttpServer.create(InetSocketAddress(port), 100); + httpServer?.createContext("/") { httpExchange -> + run { + httpExchange.sendResponseHeaders(200, "server running ".length.toLong()); + + val os = httpExchange.responseBody + val writer = OutputStreamWriter(os, Charset.defaultCharset()) + writer.write("server running ") + writer.close() + os.close() + httpExchange.close() } - start() } + httpServer?.createContext("/proxy") { httpExchange -> + run { + val params = queryToMap(httpExchange.requestURI.query) + + val url = Util.base64Decode(params?.get("url")) + val header: Map = Gson().fromJson>( + Util.base64Decode(params?.get("headers")), MutableMap::class.java + ) + CoroutineScope(Dispatchers.IO).launch { + proxyAsync( + url, header, httpExchange + ) + } + + } + } + httpServer?.executor = null; + + httpServer?.start(); + + } catch (e: Exception) { SpiderDebug.log("start server e:" + e.message) e.printStackTrace() - stop() + httpServer?.stop(1000) } - SpiderDebug.log("Server start on " + port) + port = httpServer?.address?.port!! + SpiderDebug.log("ktorServer start on " + port) } - /*class ProxyController : Controller() { - fun index() { - - val url = Util.base64Decode(getRequest().getParaToStr("url")) - val header: Map = Gson().fromJson>( - Util.base64Decode(getRequest().getParaToStr("headers")), MutableMap::class.java - ) - CoroutineScope(Dispatchers.IO).launch { - proxyAsync( - url, header, getRequest(), getResponse() - ) - } - } - } - private suspend fun proxyAsync( - url: String, headers: Map, request: HttpRequest, response: HttpResponse + url: String, headers: Map, httpExchange: HttpExchange ) { val channels = List(THREAD_NUM) { Channel() } - var outputStream = ByteArrayOutputStream() + val outputStream = httpExchange.responseBody + + val bufferedOutputStream = BufferedOutputStream(outputStream) try { SpiderDebug.log("--proxyMultiThread: THREAD_NUM: $THREAD_NUM") - var rangeHeader = request.getHeader("Range") + var rangeHeader = httpExchange.requestHeaders.getFirst("Range") //没有range头 if (rangeHeader.isNullOrEmpty()) { // 处理初始请求 @@ -92,22 +115,15 @@ object ProxyServer { SpiderDebug.log("contentLength: $contentLength") val finalEndPoint = if (endPoint == -1L) contentLength - 1 else endPoint - - response.addHeader("Connection", "keep-alive") - response.addHeader("Content-Length", (finalEndPoint - startPoint + 1).toString()) - response.addHeader("Content-Range", "bytes $startPoint-$finalEndPoint/$contentLength") - response.addHeader("Content-Type", info["Content-Type"]?.get(0)) - val statusCode = 206 - val sb = StringBuilder(); - sb.append("HTTP/1.1 ").append(" ").append(statusCode).append(" ") - .append(StatusCodeUtil.getStatusCode(statusCode)).append("\r\n") - for ((key, value) in response.header) { - sb.append(key).append(": ").append(value).append("\r\n") + httpExchange.responseHeaders.apply { + set("Connection", "keep-alive") + set("Content-Length", (finalEndPoint - startPoint + 1).toString()) + set("Content-Range", "bytes $startPoint-$finalEndPoint/$contentLength") + set("Content-Type", info["Content-Type"]?.get(0)) } - sb.append("\r\n") - outputStream.write(sb.toString().toByteArray(Charset.defaultCharset())) - outputStream.flush() - response.send(outputStream, false) + httpExchange.sendResponseHeaders(206, 0) + + // 使用流式响应 var currentStart = startPoint @@ -122,9 +138,7 @@ object ProxyServer { for (i in 0 until THREAD_NUM) { - if (currentStart > finalEndPoint) { - break - } + if (currentStart > finalEndPoint) break val chunkStart = currentStart val chunkEnd = minOf(currentStart + partSize - 1, finalEndPoint) producerJob += CoroutineScope(Dispatchers.IO).launch { @@ -139,30 +153,27 @@ object ProxyServer { val data = channels[index].receive() SpiderDebug.log("Received chunk: ${data.size} bytes") - outputStream = ByteArrayOutputStream(); - outputStream.write(data); - outputStream.flush() - - response.send(outputStream, false) - // bufferedOutputStream.close() + bufferedOutputStream.write(data) + bufferedOutputStream.flush() } } - - response.send(ByteArrayOutputStream(), true) } catch (e: Exception) { SpiderDebug.log("error: ${e.message}") - e.printStackTrace() + outputStream.write("error: ${e.message}".toByteArray()) } finally { channels.forEach { it.close() } + bufferedOutputStream.close() + outputStream.close() + httpExchange.close() } } -*/ + private fun queryToMap(query: String?): Map? { if (query == null) { return null diff --git a/jar/custom_spider.jar b/jar/custom_spider.jar index a8438a37..45a0c6d0 100644 Binary files a/jar/custom_spider.jar and b/jar/custom_spider.jar differ diff --git a/jar/custom_spider.jar.md5 b/jar/custom_spider.jar.md5 index 3ad1fd36..8618881c 100644 --- a/jar/custom_spider.jar.md5 +++ b/jar/custom_spider.jar.md5 @@ -1 +1 @@ -46a0bc151a572484c98dc163e9b944dd +822127bc7ad6da1d93a4ef9f8b9f15a1 diff --git a/json/test.json b/json/test.json index a75ac033..52761e63 100644 --- a/json/test.json +++ b/json/test.json @@ -1,5 +1,5 @@ { - "spider": "https://gh.llkk.cc/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/multiThreadNew/jar/custom_spider.jar;md5;46a0bc151a572484c98dc163e9b944dd", + "spider": "https://gh.llkk.cc/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/multiThreadNew/jar/custom_spider.jar;md5;822127bc7ad6da1d93a4ef9f8b9f15a1", "lives": [ { "name": "电视直播",