httpserver

This commit is contained in:
lushunming 2025-07-21 15:24:56 +08:00
parent 7e65d5eae0
commit b5a1f6ef04
5 changed files with 73 additions and 62 deletions

View File

@ -86,10 +86,10 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1"
// https://mvnrepository.com/artifact/com.sun.net.httpserver/http // https://mvnrepository.com/artifact/com.sun.net.httpserver/http
implementation(files("libs/sun-common-server.jar"))
// implementation("com.sun.net.httpserver:http:20070405") implementation("com.sun.net.httpserver:http:20070405")
// implementation("com.hibegin:simplewebserver:0.1.15") // implementation("com.hibegin:simplewebserver:0.1.15")
implementation("com.github.codeborne.klite:klite-server:1.7.0") //implementation("com.github.codeborne.klite:klite-server:1.7.0")
//implementation 'wang.harlon.quickjs:wrapper-java:1.0.0' //implementation 'wang.harlon.quickjs:wrapper-java:1.0.0'

View File

@ -1,10 +1,17 @@
package com.github.catvod.utils package com.github.catvod.utils
import com.github.catvod.crawler.SpiderDebug import com.github.catvod.crawler.SpiderDebug
import com.github.catvod.net.OkHttp import com.github.catvod.net.OkHttp
import com.google.gson.Gson 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.net.InetSocketAddress
import java.nio.charset.Charset import java.nio.charset.Charset
@ -13,59 +20,75 @@ object ProxyServer {
private val THREAD_NUM = Runtime.getRuntime().availableProcessors() * 2 private val THREAD_NUM = Runtime.getRuntime().availableProcessors() * 2
private const val partSize = 1024 * 1024 * 1 private const val partSize = 1024 * 1024 * 1
private var port = 12345 private var port = 12345
private var server: Server? = null private var httpServer: HttpServer? = null
private val infos = mutableMapOf<String, MutableMap<String, MutableList<String>>>(); private val infos = mutableMapOf<String, MutableMap<String, MutableList<String>>>();
fun stop() { fun stop() {
server?.stop(1000) httpServer?.stop(1_000)
} }
fun start() { fun start() {
try { try {
server = Server(InetSocketAddress(port)).apply { httpServer = HttpServer.create(InetSocketAddress(port), 100);
context("/api") { httpServer?.createContext("/") { httpExchange ->
get("/hello") { "Hello, world!" } 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<String, String> = Gson().fromJson<Map<String, String>>(
Util.base64Decode(params?.get("headers")), MutableMap::class.java
)
CoroutineScope(Dispatchers.IO).launch {
proxyAsync(
url, header, httpExchange
)
}
}
}
httpServer?.executor = null;
httpServer?.start();
} catch (e: Exception) { } catch (e: Exception) {
SpiderDebug.log("start server e:" + e.message) SpiderDebug.log("start server e:" + e.message)
e.printStackTrace() 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<String, String> = Gson().fromJson<Map<String, String>>(
Util.base64Decode(getRequest().getParaToStr("headers")), MutableMap::class.java
)
CoroutineScope(Dispatchers.IO).launch {
proxyAsync(
url, header, getRequest(), getResponse()
)
}
}
}
private suspend fun proxyAsync( private suspend fun proxyAsync(
url: String, headers: Map<String, String>, request: HttpRequest, response: HttpResponse url: String, headers: Map<String, String>, httpExchange: HttpExchange
) { ) {
val channels = List(THREAD_NUM) { Channel<ByteArray>() } val channels = List(THREAD_NUM) { Channel<ByteArray>() }
var outputStream = ByteArrayOutputStream() val outputStream = httpExchange.responseBody
val bufferedOutputStream = BufferedOutputStream(outputStream)
try { try {
SpiderDebug.log("--proxyMultiThread: THREAD_NUM: $THREAD_NUM") SpiderDebug.log("--proxyMultiThread: THREAD_NUM: $THREAD_NUM")
var rangeHeader = request.getHeader("Range") var rangeHeader = httpExchange.requestHeaders.getFirst("Range")
//没有range头 //没有range头
if (rangeHeader.isNullOrEmpty()) { if (rangeHeader.isNullOrEmpty()) {
// 处理初始请求 // 处理初始请求
@ -92,22 +115,15 @@ object ProxyServer {
SpiderDebug.log("contentLength: $contentLength") SpiderDebug.log("contentLength: $contentLength")
val finalEndPoint = if (endPoint == -1L) contentLength - 1 else endPoint val finalEndPoint = if (endPoint == -1L) contentLength - 1 else endPoint
httpExchange.responseHeaders.apply {
response.addHeader("Connection", "keep-alive") set("Connection", "keep-alive")
response.addHeader("Content-Length", (finalEndPoint - startPoint + 1).toString()) set("Content-Length", (finalEndPoint - startPoint + 1).toString())
response.addHeader("Content-Range", "bytes $startPoint-$finalEndPoint/$contentLength") set("Content-Range", "bytes $startPoint-$finalEndPoint/$contentLength")
response.addHeader("Content-Type", info["Content-Type"]?.get(0)) set("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")
} }
sb.append("\r\n") httpExchange.sendResponseHeaders(206, 0)
outputStream.write(sb.toString().toByteArray(Charset.defaultCharset()))
outputStream.flush() // 使用流式响应
response.send(outputStream, false)
var currentStart = startPoint var currentStart = startPoint
@ -122,9 +138,7 @@ object ProxyServer {
for (i in 0 until THREAD_NUM) { for (i in 0 until THREAD_NUM) {
if (currentStart > finalEndPoint) { if (currentStart > finalEndPoint) break
break
}
val chunkStart = currentStart val chunkStart = currentStart
val chunkEnd = minOf(currentStart + partSize - 1, finalEndPoint) val chunkEnd = minOf(currentStart + partSize - 1, finalEndPoint)
producerJob += CoroutineScope(Dispatchers.IO).launch { producerJob += CoroutineScope(Dispatchers.IO).launch {
@ -139,30 +153,27 @@ object ProxyServer {
val data = channels[index].receive() val data = channels[index].receive()
SpiderDebug.log("Received chunk: ${data.size} bytes") 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) { } catch (e: Exception) {
SpiderDebug.log("error: ${e.message}") SpiderDebug.log("error: ${e.message}")
e.printStackTrace() outputStream.write("error: ${e.message}".toByteArray())
} finally { } finally {
channels.forEach { it.close() } channels.forEach { it.close() }
bufferedOutputStream.close()
outputStream.close()
httpExchange.close()
} }
} }
*/
private fun queryToMap(query: String?): Map<String, String>? { private fun queryToMap(query: String?): Map<String, String>? {
if (query == null) { if (query == null) {
return null return null

Binary file not shown.

View File

@ -1 +1 @@
46a0bc151a572484c98dc163e9b944dd 822127bc7ad6da1d93a4ef9f8b9f15a1

View File

@ -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": [ "lives": [
{ {
"name": "电视直播", "name": "电视直播",