diff --git a/app/src/main/java/io/legado/app/web/KtorServer.kt b/app/src/main/java/io/legado/app/web/KtorServer.kt index 94c877aeb..6671eabfc 100644 --- a/app/src/main/java/io/legado/app/web/KtorServer.kt +++ b/app/src/main/java/io/legado/app/web/KtorServer.kt @@ -14,6 +14,7 @@ import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.server.websocket.* import io.ktor.util.pipeline.* +import io.ktor.util.toMap import io.legado.app.api.ReturnData import io.legado.app.api.controller.BookController import io.legado.app.api.controller.BookSourceController @@ -29,7 +30,9 @@ import io.legado.app.web.socket.RssSourceDebugWebSocket import io.legado.app.web.utils.AssetsWeb import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import splitties.init.appCtx import java.io.ByteArrayOutputStream +import java.io.File class KtorServer(private val port: Int) { private var server: ApplicationEngine? = null @@ -62,32 +65,46 @@ class KtorServer(private val port: Int) { WebService.serve() val multipart = call.receiveMultipart() var fileName: String? = null - var fileBytes: ByteArray? = null - multipart.forEachPart { part -> - when (part) { - is PartData.FormItem -> { - if (part.name == "fileName") fileName = part.value + val tempFile = File(appCtx.cacheDir, "upload_${System.currentTimeMillis()}") + try { + multipart.forEachPart { part -> + when (part) { + is PartData.FormItem -> { + if (part.name == "fileName") fileName = part.value + } + is PartData.FileItem -> { + part.streamProvider().use { input -> + tempFile.outputStream().use { output -> + input.copyTo(output) + } + } + if (fileName == null) { + fileName = part.originalFileName + } + } + else -> {} } - is PartData.FileItem -> { - fileBytes = part.streamProvider().readBytes() - } - else -> {} + part.dispose() } - part.dispose() - } - if (fileName != null && fileBytes != null) { - val returnData = withContext(Dispatchers.IO) { - kotlin.runCatching { - val uri = LocalBook.saveBookFile(fileBytes!!.inputStream(), fileName!!) - LocalBook.importFile(uri) - ReturnData().setData(true) - }.getOrElse { - ReturnData().setErrorMsg(it.localizedMessage ?: "Save book error") + if (fileName != null && tempFile.exists()) { + val returnData = withContext(Dispatchers.IO) { + kotlin.runCatching { + tempFile.inputStream().use { + val uri = LocalBook.saveBookFile(it, fileName!!) + LocalBook.importFile(uri) + ReturnData().setData(true) + } + }.getOrElse { + LogUtils.e(TAG, it.stackTraceStr) + ReturnData().setErrorMsg(it.localizedMessage ?: "Save book error") + } } + respondReturnData(returnData) + } else { + call.respond(HttpStatusCode.BadRequest, "Missing fileName or fileData") } - respondReturnData(returnData) - } else { - call.respond(HttpStatusCode.BadRequest, "Missing fileName or fileData") + } finally { + if (tempFile.exists()) tempFile.delete() } } post("/saveReadConfig") { handlePost { BookController.saveWebReadConfig(it) } } @@ -113,12 +130,14 @@ class KtorServer(private val port: Int) { get("{...}") { WebService.serve() - var uri = call.request.uri.substringBefore("?") + var uri = call.request.path() if (uri.endsWith("/")) uri += "index.html" val inputStream = assetsWeb.getInputStream(uri) if (inputStream != null) { - call.respondOutputStream(ContentType.parse(assetsWeb.getMimeType(uri))) { - inputStream.copyTo(this) + inputStream.use { stream -> + call.respondOutputStream(ContentType.parse(assetsWeb.getMimeType(uri))) { + stream.copyTo(this) + } } } else { call.respond(HttpStatusCode.NotFound) @@ -195,12 +214,6 @@ class KtorServer(private val port: Int) { } } - private fun Parameters.toMap(): Map> { - val map = mutableMapOf>() - this.forEach { s, list -> map[s] = list } - return map - } - companion object { private const val TAG = "KtorServer" } diff --git a/app/src/main/java/io/legado/app/web/socket/BookSearchWebSocket.kt b/app/src/main/java/io/legado/app/web/socket/BookSearchWebSocket.kt index 987b41d94..c7228ec92 100644 --- a/app/src/main/java/io/legado/app/web/socket/BookSearchWebSocket.kt +++ b/app/src/main/java/io/legado/app/web/socket/BookSearchWebSocket.kt @@ -13,7 +13,6 @@ import io.legado.app.help.config.AppConfig import io.legado.app.ui.config.otherConfig.OtherConfig import io.legado.app.utils.* import kotlinx.coroutines.* -import kotlinx.coroutines.channels.consumeEach import org.koin.core.context.GlobalContext import splitties.init.appCtx @@ -28,13 +27,13 @@ class BookSearchWebSocket(private val session: DefaultWebSocketServerSession) : suspend fun handle() { try { - session.incoming.consumeEach { frame -> + for (frame in session.incoming) { if (frame is Frame.Text) { val text = frame.readText() if (!text.isJson()) { session.send("数据必须为Json格式") session.close(CloseReason(CloseReason.Codes.NORMAL, SEARCH_FINISH)) - return@consumeEach + break } val searchMap = GSON.fromJsonObject>(text).getOrNull() if (searchMap != null) { @@ -42,7 +41,7 @@ class BookSearchWebSocket(private val session: DefaultWebSocketServerSession) : if (key.isNullOrBlank()) { session.send(appCtx.getString(R.string.cannot_empty)) session.close(CloseReason(CloseReason.Codes.NORMAL, SEARCH_FINISH)) - return@consumeEach + break } startSearch(key) } diff --git a/app/src/main/java/io/legado/app/web/socket/BookSourceDebugWebSocket.kt b/app/src/main/java/io/legado/app/web/socket/BookSourceDebugWebSocket.kt index 197293b16..43b92b7d9 100644 --- a/app/src/main/java/io/legado/app/web/socket/BookSourceDebugWebSocket.kt +++ b/app/src/main/java/io/legado/app/web/socket/BookSourceDebugWebSocket.kt @@ -7,7 +7,6 @@ import io.legado.app.data.appDb import io.legado.app.model.Debug import io.legado.app.utils.* import kotlinx.coroutines.* -import kotlinx.coroutines.channels.consumeEach import splitties.init.appCtx /** @@ -21,13 +20,13 @@ class BookSourceDebugWebSocket(private val session: DefaultWebSocketServerSessio suspend fun handle() { try { - session.incoming.consumeEach { frame -> + for (frame in session.incoming) { if (frame is Frame.Text) { val text = frame.readText() if (!text.isJson()) { session.send("数据必须为Json格式") session.close(CloseReason(CloseReason.Codes.NORMAL, "调试结束")) - return@consumeEach + break } val debugBean = GSON.fromJsonObject>(text).getOrNull() if (debugBean != null) { @@ -36,7 +35,7 @@ class BookSourceDebugWebSocket(private val session: DefaultWebSocketServerSessio if (tag.isNullOrBlank() || key.isNullOrBlank()) { session.send(appCtx.getString(R.string.cannot_empty)) session.close(CloseReason(CloseReason.Codes.NORMAL, "调试结束")) - return@consumeEach + break } appDb.bookSourceDao.getBookSource(tag)?.let { Debug.callback = this@BookSourceDebugWebSocket @@ -45,7 +44,7 @@ class BookSourceDebugWebSocket(private val session: DefaultWebSocketServerSessio } else { session.send("数据必须为Json格式") session.close(CloseReason(CloseReason.Codes.NORMAL, "调试结束")) - return@consumeEach + break } } } diff --git a/app/src/main/java/io/legado/app/web/socket/RssSourceDebugWebSocket.kt b/app/src/main/java/io/legado/app/web/socket/RssSourceDebugWebSocket.kt index 9057aaae0..9e77dc5b9 100644 --- a/app/src/main/java/io/legado/app/web/socket/RssSourceDebugWebSocket.kt +++ b/app/src/main/java/io/legado/app/web/socket/RssSourceDebugWebSocket.kt @@ -7,7 +7,6 @@ import io.legado.app.data.appDb import io.legado.app.model.Debug import io.legado.app.utils.* import kotlinx.coroutines.* -import kotlinx.coroutines.channels.consumeEach import splitties.init.appCtx /** @@ -21,13 +20,13 @@ class RssSourceDebugWebSocket(private val session: DefaultWebSocketServerSession suspend fun handle() { try { - session.incoming.consumeEach { frame -> + for (frame in session.incoming) { if (frame is Frame.Text) { val text = frame.readText() if (!text.isJson()) { session.send("数据必须为Json格式") session.close(CloseReason(CloseReason.Codes.NORMAL, "调试结束")) - return@consumeEach + break } val debugBean = GSON.fromJsonObject>(text).getOrNull() if (debugBean != null) { @@ -35,7 +34,7 @@ class RssSourceDebugWebSocket(private val session: DefaultWebSocketServerSession if (tag.isNullOrBlank()) { session.send(appCtx.getString(R.string.cannot_empty)) session.close(CloseReason(CloseReason.Codes.NORMAL, "调试结束")) - return@consumeEach + break } appDb.rssSourceDao.getByKey(tag)?.let { Debug.callback = this@RssSourceDebugWebSocket