Files
QieKan-3.0/app/src/main/java/io/legato/kazusa/web/HttpServer.kt
T
2025-06-04 13:33:51 +08:00

153 lines
6.8 KiB
Kotlin

package io.legato.kazusa.web
import android.graphics.Bitmap
import fi.iki.elonen.NanoHTTPD
import io.legato.kazusa.api.ReturnData
import io.legato.kazusa.api.controller.BookController
import io.legato.kazusa.api.controller.BookSourceController
import io.legato.kazusa.api.controller.ReplaceRuleController
import io.legato.kazusa.api.controller.RssSourceController
import io.legato.kazusa.help.coroutine.Coroutine
import io.legato.kazusa.service.WebService
import io.legato.kazusa.utils.GSON
import io.legato.kazusa.utils.LogUtils
import io.legato.kazusa.utils.stackTraceStr
import io.legato.kazusa.web.utils.AssetsWeb
import kotlinx.coroutines.runBlocking
import okio.Pipe
import okio.buffer
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
class HttpServer(port: Int) : NanoHTTPD(port) {
private val assetsWeb = AssetsWeb("web")
override fun serve(session: IHTTPSession): Response {
WebService.serve()
var returnData: ReturnData? = null
val ct = ContentType(session.headers["content-type"]).tryUTF8()
session.headers["content-type"] = ct.contentTypeHeader
var uri = session.uri
val startAt = System.currentTimeMillis()
LogUtils.d(TAG) {
"${session.method.name} - $uri - ${session.queryParameterString} - Start($startAt)"
}
try {
when (session.method) {
Method.OPTIONS -> {
val response = newFixedLengthResponse("")
response.addHeader("Access-Control-Allow-Methods", "POST")
response.addHeader("Access-Control-Allow-Headers", "content-type")
response.addHeader("Access-Control-Allow-Origin", session.headers["origin"])
//response.addHeader("Access-Control-Max-Age", "3600");
return response
}
Method.POST -> {
val files = HashMap<String, String>()
session.parseBody(files)
val postData = files["postData"]
returnData = runBlocking {
when (uri) {
"/saveBookSource" -> BookSourceController.saveSource(postData)
"/saveBookSources" -> BookSourceController.saveSources(postData)
"/deleteBookSources" -> BookSourceController.deleteSources(postData)
"/saveBook" -> BookController.saveBook(postData)
"/deleteBook" -> BookController.deleteBook(postData)
"/saveBookProgress" -> BookController.saveBookProgress(postData)
"/addLocalBook" -> BookController.addLocalBook(session.parameters, files)
"/saveReadConfig" -> BookController.saveWebReadConfig(postData)
"/saveRssSource" -> RssSourceController.saveSource(postData)
"/saveRssSources" -> RssSourceController.saveSources(postData)
"/deleteRssSources" -> RssSourceController.deleteSources(postData)
"/saveReplaceRule" -> ReplaceRuleController.saveRule(postData)
"/deleteReplaceRule" -> ReplaceRuleController.delete(postData)
"/testReplaceRule" -> ReplaceRuleController.testRule(postData)
else -> null
}
}
}
Method.GET -> {
val parameters = session.parameters
returnData = when (uri) {
"/getBookSource" -> BookSourceController.getSource(parameters)
"/getBookSources" -> BookSourceController.sources
"/getBookshelf" -> BookController.bookshelf
"/getChapterList" -> BookController.getChapterList(parameters)
"/refreshToc" -> BookController.refreshToc(parameters)
"/getBookContent" -> BookController.getBookContent(parameters)
"/cover" -> BookController.getCover(parameters)
"/image" -> BookController.getImg(parameters)
"/getReadConfig" -> BookController.getWebReadConfig()
"/getRssSource" -> RssSourceController.getSource(parameters)
"/getRssSources" -> RssSourceController.sources
"/getReplaceRules" -> ReplaceRuleController.allRules
else -> null
}
}
else -> Unit
}
if (returnData == null) {
if (uri.endsWith("/"))
uri += "index.html"
return assetsWeb.getResponse(uri)
}
val response = if (returnData.data is Bitmap) {
val outputStream = ByteArrayOutputStream()
(returnData.data as Bitmap).compress(Bitmap.CompressFormat.PNG, 100, outputStream)
val byteArray = outputStream.toByteArray()
outputStream.close()
val inputStream = ByteArrayInputStream(byteArray)
newFixedLengthResponse(
Response.Status.OK,
"image/png",
inputStream,
byteArray.size.toLong()
)
} else {
val data = returnData.data
if (data is List<*> && data.size > 3000) {
val pipe = Pipe(16 * 1024)
Coroutine.async {
pipe.sink.buffer().outputStream().bufferedWriter(Charsets.UTF_8).use {
GSON.toJson(returnData, it)
}
}
newChunkedResponse(
Response.Status.OK,
"application/json",
pipe.source.buffer().inputStream()
)
} else {
newFixedLengthResponse(GSON.toJson(returnData))
}
}
response.addHeader("Access-Control-Allow-Methods", "GET, POST")
response.addHeader("Access-Control-Allow-Origin", session.headers["origin"])
LogUtils.d(TAG) {
"${session.method.name} - $uri - ${session.queryParameterString} - End($startAt)"
}
return response
} catch (e: Exception) {
LogUtils.d(TAG) {
"${session.method.name} - $uri - ${session.queryParameterString} - Error End($startAt)\n$e\n${e.stackTraceStr}"
}
return newFixedLengthResponse(e.message)
}
}
companion object {
private const val TAG = "HttpServer"
}
}