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