diff --git a/app/build.gradle b/app/build.gradle index 42e27c25..f12c2ba5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,7 +87,8 @@ 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.sun.net.httpserver:http:20070405") + implementation("com.hibegin:simplewebserver:0.3.175") //implementation 'wang.harlon.quickjs:wrapper-java:1.0.0' // implementation(ext: 'aar', name: 'quickjs', group: 'fongmi', version: 'release') 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 2cad67ee..8ccc1b71 100644 --- a/app/src/main/java/com/github/catvod/utils/ProxyServer.kt +++ b/app/src/main/java/com/github/catvod/utils/ProxyServer.kt @@ -1,97 +1,85 @@ package com.github.catvod.utils + import com.github.catvod.crawler.SpiderDebug import com.github.catvod.net.OkHttp import com.google.gson.Gson -import com.sun.net.httpserver.HttpExchange -import com.sun.net.httpserver.HttpServer +import com.hibegin.http.server.SimpleWebServer +import com.hibegin.http.server.WebServerBuilder +import com.hibegin.http.server.api.HttpRequest +import com.hibegin.http.server.api.HttpResponse +import com.hibegin.http.server.config.ServerConfig +import com.hibegin.http.server.util.StatusCodeUtil +import com.hibegin.http.server.web.Controller import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import okhttp3.Headers -import java.io.BufferedOutputStream import java.io.ByteArrayOutputStream -import java.io.OutputStreamWriter -import java.net.InetSocketAddress import java.nio.charset.Charset object ProxyServer { private val THREAD_NUM = Runtime.getRuntime().availableProcessors() * 2 private const val partSize = 1024 * 1024 * 1 - private var port = 0 - private var httpServer: HttpServer? = null + private var port = 12345 + private var httpServer: SimpleWebServer? = null private val infos = mutableMapOf>>(); fun stop() { - httpServer?.stop(1_000) + httpServer?.destroy() } fun start() { try { - httpServer = HttpServer.create(InetSocketAddress(port), 100); - httpServer?.createContext("/") { httpExchange -> - run { - httpExchange.sendResponseHeaders(200, "server running ".length.toLong()); + val serverConfig = ServerConfig() + serverConfig.port = port + serverConfig.router.addMapper("/proxy", ProxyController::class.java) + val builder = WebServerBuilder.Builder().serverConfig(serverConfig).build() - val os = httpExchange.responseBody - val writer = OutputStreamWriter(os, Charset.defaultCharset()) - writer.write("server running ") - writer.close() - os.close() - httpExchange.close() - } - } - 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(); + builder.startWithThread() + httpServer = builder.webServer } catch (e: Exception) { SpiderDebug.log("start server e:" + e.message) e.printStackTrace() - httpServer?.stop(1000) + httpServer?.destroy() } - port = httpServer?.address?.port!! - SpiderDebug.log("ktorServer start on " + port) + SpiderDebug.log("Server 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, httpExchange: HttpExchange + url: String, headers: Map, request: HttpRequest, response: HttpResponse ) { val channels = List(THREAD_NUM) { Channel() } - val outputStream = httpExchange.responseBody - - val bufferedOutputStream = BufferedOutputStream(outputStream) + var outputStream = ByteArrayOutputStream() try { SpiderDebug.log("--proxyMultiThread: THREAD_NUM: $THREAD_NUM") - var rangeHeader = httpExchange.requestHeaders.getFirst("Range") + var rangeHeader = request.getHeader("Range") //没有range头 if (rangeHeader.isNullOrEmpty()) { // 处理初始请求 @@ -118,15 +106,22 @@ object ProxyServer { SpiderDebug.log("contentLength: $contentLength") val finalEndPoint = if (endPoint == -1L) contentLength - 1 else endPoint - 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)) - } - httpExchange.sendResponseHeaders(206, 0) - // 使用流式响应 + 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(request.httpVersion.value).append(" ").append(statusCode).append(" ") + .append(StatusCodeUtil.getStatusCodeDesc(statusCode)).append("\r\n") + for ((key, value) in response.header) { + sb.append(key).append(": ").append(value).append("\r\n") + } + sb.append("\r\n") + outputStream.write(sb.toString().toByteArray(Charset.defaultCharset())) + outputStream.flush() + response.send(outputStream, false) var currentStart = startPoint @@ -141,7 +136,9 @@ 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 { @@ -156,24 +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}") - outputStream.write("error: ${e.message}".toByteArray()) + e.printStackTrace() } finally { channels.forEach { it.close() } - bufferedOutputStream.close() - outputStream.close() - httpExchange.close() } } diff --git a/jar/custom_spider.jar b/jar/custom_spider.jar index 7ee15743..ab4b9b1a 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 03d6f15a..8633b115 100644 --- a/jar/custom_spider.jar.md5 +++ b/jar/custom_spider.jar.md5 @@ -1 +1 @@ -2b55efe5a17ba216363ab2bef3b69d05 +ba2f976b1ed8413cb45d6798af4b5b55 diff --git a/json/test.json b/json/test.json index 7f12c99a..b83f45cd 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;2b55efe5a17ba216363ab2bef3b69d05", + "spider": "https://gh.llkk.cc/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/multiThreadNew/jar/custom_spider.jar;md5;ba2f976b1ed8413cb45d6798af4b5b55", "lives": [ { "name": "电视直播",