aoi 5 месяцев назад
Родитель
Сommit
43b401c52b

+ 44 - 31
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<String, List<String>> {
-        val map = mutableMapOf<String, List<String>>()
-        this.forEach { s, list -> map[s] = list }
-        return map
-    }
-
     companion object {
         private const val TAG = "KtorServer"
     }

+ 3 - 4
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<Map<String, String>>(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)
                     }

+ 4 - 5
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<Map<String, String>>(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
                     }
                 }
             }

+ 3 - 4
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<Map<String, String>>(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