pull/737/head
Robot 4 years ago
commit 15fd808d68
  1. 20
      app/src/main/java/io/legado/app/help/http/HttpHelper.kt
  2. 2
      app/src/main/java/io/legado/app/help/http/parser/ByteParser.kt
  3. 14
      app/src/main/java/io/legado/app/help/http/parser/InputStreamParser.kt
  4. 2
      app/src/main/java/io/legado/app/help/http/parser/TextParser.kt
  5. 2
      app/src/main/java/io/legado/app/help/storage/Backup.kt
  6. 26
      app/src/main/java/io/legado/app/help/storage/BookWebDav.kt
  7. 73
      app/src/main/java/io/legado/app/lib/webdav/WebDav.kt
  8. 7
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt
  9. 6
      app/src/main/java/io/legado/app/utils/ZipUtils.kt

@ -3,10 +3,12 @@ package io.legado.app.help.http
import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.*
import retrofit2.Retrofit
import java.io.IOException
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.concurrent.TimeUnit
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
@Suppress("unused")
object HttpHelper {
@ -35,6 +37,24 @@ object HttpHelper {
builder.build()
}
suspend fun awaitResponse(request: Request): Response = suspendCancellableCoroutine { block ->
val call = client.newCall(request)
block.invokeOnCancellation {
call.cancel()
}
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
block.resumeWithException(e)
}
override fun onResponse(call: Call, response: Response) {
block.resume(response)
}
})
}
inline fun <reified T> getApiService(
baseUrl: String,
encode: String? = null,

@ -1,4 +1,4 @@
package io.legado.app.help.http
package io.legado.app.help.http.parser
import okhttp3.Response
import rxhttp.wrapper.annotation.Parser

@ -0,0 +1,14 @@
package io.legado.app.help.http.parser
import okhttp3.Response
import rxhttp.wrapper.annotation.Parser
import java.io.InputStream
@Parser(name = "InputStream")
class InputStreamParser : rxhttp.wrapper.parse.Parser<InputStream> {
override fun onParse(response: Response): InputStream {
return response.body()!!.byteStream()
}
}

@ -1,4 +1,4 @@
package io.legado.app.help.http
package io.legado.app.help.http.parser
import io.legado.app.utils.EncodingDetect
import io.legado.app.utils.UTF8BOMFighter

@ -56,7 +56,6 @@ object Backup {
suspend fun backup(context: Context, path: String, isAuto: Boolean = false) {
context.putPrefLong(PreferKey.lastBackup, System.currentTimeMillis())
withContext(IO) {
synchronized(this@Backup) {
FileUtils.deleteFile(backupPath)
writeListToJson(App.db.bookDao.all, "bookshelf.json", backupPath)
writeListToJson(App.db.bookmarkDao.all, "bookmark.json", backupPath)
@ -107,7 +106,6 @@ object Backup {
}
}
}
}
private fun writeListToJson(list: List<Any>, fileName: String, path: String) {
if (list.isNotEmpty()) {

@ -39,7 +39,7 @@ object BookWebDav {
return url
}
fun initWebDav(): Boolean {
suspend fun initWebDav(): Boolean {
val account = App.INSTANCE.getPrefString(PreferKey.webDavAccount)
val password = App.INSTANCE.getPrefString(PreferKey.webDavPassword)
if (!account.isNullOrBlank() && !password.isNullOrBlank()) {
@ -52,7 +52,7 @@ object BookWebDav {
}
@Throws(Exception::class)
private fun getWebDavFileNames(): ArrayList<String> {
private suspend fun getWebDavFileNames(): ArrayList<String> {
val url = rootWebDavUrl
val names = arrayListOf<String>()
if (initWebDav()) {
@ -77,7 +77,11 @@ object BookWebDav {
items = names
) { _, index ->
if (index in 0 until names.size) {
Coroutine.async {
restoreWebDav(names[index])
}.onError {
App.INSTANCE.toast("WebDavError:${it.localizedMessage}")
}
}
}
}
@ -86,8 +90,7 @@ object BookWebDav {
}
}
private fun restoreWebDav(name: String) {
Coroutine.async {
private suspend fun restoreWebDav(name: String) {
rootWebDavUrl.let {
val webDav = WebDav(it + name)
webDav.downloadTo(zipFilePath, true)
@ -96,12 +99,9 @@ object BookWebDav {
Restore.restoreDatabase()
Restore.restoreConfig()
}
}.onError {
App.INSTANCE.toast("WebDavError:${it.localizedMessage}")
}
}
fun backUpWebDav(path: String) {
suspend fun backUpWebDav(path: String) {
try {
if (initWebDav()) {
val paths = arrayListOf(*Backup.backupFileNames)
@ -123,7 +123,7 @@ object BookWebDav {
}
}
fun exportWebDav(path: String, fileName: String) {
suspend fun exportWebDav(path: String, fileName: String) {
try {
if (initWebDav()) {
// 默认导出到legado文件夹下exports目录
@ -155,16 +155,16 @@ object BookWebDav {
durChapterTitle = book.durChapterTitle
)
val json = GSON.toJson(bookProgress)
val url = geProtresstUrl(book)
val url = getProgressUrl(book)
if (initWebDav()) {
WebDav(url).upload(json.toByteArray())
}
}
}
fun getBookProgress(book: Book): BookProgress? {
suspend fun getBookProgress(book: Book): BookProgress? {
if (initWebDav()) {
val url = geProtresstUrl(book)
val url = getProgressUrl(book)
WebDav(url).download()?.let { byteArray ->
val json = String(byteArray)
GSON.fromJsonObject<BookProgress>(json)?.let {
@ -175,7 +175,7 @@ object BookWebDav {
return null
}
private fun geProtresstUrl(book: Book): String {
private fun getProgressUrl(book: Book): String {
return bookProgressUrl + book.name + "_" + book.author + ".json"
}
}

@ -3,6 +3,8 @@ package io.legado.app.lib.webdav
import io.legado.app.help.http.HttpHelper
import okhttp3.*
import org.jsoup.Jsoup
import rxhttp.wrapper.param.RxHttp
import rxhttp.wrapper.param.toInputStream
import java.io.File
import java.io.IOException
import java.io.InputStream
@ -54,17 +56,16 @@ class WebDav(urlStr: String) {
/**
* 填充文件信息实例化WebDAVFile对象时并没有将远程文件的信息填充到实例中需要手动填充
*
* @return 远程文件是否存在
*/
@Throws(IOException::class)
fun indexFileInfo(): Boolean {
suspend fun indexFileInfo(): Boolean {
propFindResponse(ArrayList())?.let { response ->
if (!response.isSuccessful) {
this.exists = false
return false
}
response.body()?.let {
@Suppress("BlockingMethodInNonBlockingContext")
if (it.string().isNotEmpty()) {
return true
}
@ -79,12 +80,11 @@ class WebDav(urlStr: String) {
* @param propsList 指定列出文件的哪些属性
* @return 文件列表
*/
@Throws(IOException::class)
@JvmOverloads
fun listFiles(propsList: ArrayList<String> = ArrayList()): List<WebDav> {
suspend fun listFiles(propsList: ArrayList<String> = ArrayList()): List<WebDav> {
propFindResponse(propsList)?.let { response ->
if (response.isSuccessful) {
response.body()?.let { body ->
@Suppress("BlockingMethodInNonBlockingContext")
return parseDir(body.string())
}
}
@ -93,7 +93,7 @@ class WebDav(urlStr: String) {
}
@Throws(IOException::class)
private fun propFindResponse(propsList: ArrayList<String>, depth: Int = 1): Response? {
private suspend fun propFindResponse(propsList: ArrayList<String>, depth: Int = 1): Response? {
val requestProps = StringBuilder()
for (p in propsList) {
requestProps.append("<a:").append(p).append("/>\n")
@ -105,23 +105,18 @@ class WebDav(urlStr: String) {
String.format(DIR, requestProps.toString() + "\n")
}
httpUrl?.let { url ->
val request = Request.Builder()
.url(url)
// 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性
// 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。
.method(
"PROPFIND",
RequestBody.create(MediaType.parse("text/plain"), requestPropsStr)
)
val requestBody = RequestBody.create(MediaType.parse("text/plain"), requestPropsStr)
val request = Request.Builder()
.url(url)
.method("PROPFIND", requestBody)
HttpAuth.auth?.let {
request.header(
"Authorization",
Credentials.basic(it.user, it.pass)
)
request.header("Authorization", Credentials.basic(it.user, it.pass))
}
request.header("Depth", if (depth < 0) "infinity" else depth.toString())
return HttpHelper.client.newCall(request.build()).execute()
return HttpHelper.awaitResponse(request.build())
}
return null
}
@ -165,8 +160,7 @@ class WebDav(urlStr: String) {
*
* @return 是否创建成功
*/
@Throws(IOException::class)
fun makeAsDir(): Boolean {
suspend fun makeAsDir(): Boolean {
httpUrl?.let { url ->
val request = Request.Builder()
.url(url)
@ -183,7 +177,7 @@ class WebDav(urlStr: String) {
* @param replaceExisting 是否替换本地的同名文件
* @return 下载是否成功
*/
fun downloadTo(savedPath: String, replaceExisting: Boolean): Boolean {
suspend fun downloadTo(savedPath: String, replaceExisting: Boolean): Boolean {
if (File(savedPath).exists()) {
if (!replaceExisting) return false
}
@ -192,7 +186,7 @@ class WebDav(urlStr: String) {
return true
}
fun download(): ByteArray? {
suspend fun download(): ByteArray? {
val inputS = getInputStream() ?: return null
return inputS.readBytes()
}
@ -200,8 +194,7 @@ class WebDav(urlStr: String) {
/**
* 上传文件
*/
@Throws(IOException::class)
fun upload(localPath: String, contentType: String? = null): Boolean {
suspend fun upload(localPath: String, contentType: String? = null): Boolean {
val file = File(localPath)
if (!file.exists()) return false
val mediaType = contentType?.let { MediaType.parse(it) }
@ -216,7 +209,7 @@ class WebDav(urlStr: String) {
return false
}
fun upload(byteArray: ByteArray, contentType: String? = null): Boolean {
suspend fun upload(byteArray: ByteArray, contentType: String? = null): Boolean {
val mediaType = contentType?.let { MediaType.parse(it) }
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
val fileBody = RequestBody.create(mediaType, byteArray)
@ -235,30 +228,22 @@ class WebDav(urlStr: String) {
* @return 请求执行的结果
*/
@Throws(IOException::class)
private fun execRequest(requestBuilder: Request.Builder): Boolean {
private suspend fun execRequest(requestBuilder: Request.Builder): Boolean {
HttpAuth.auth?.let {
requestBuilder.header(
"Authorization",
Credentials.basic(it.user, it.pass)
)
requestBuilder.header("Authorization", Credentials.basic(it.user, it.pass))
}
val response = HttpHelper.client.newCall(requestBuilder.build()).execute()
val response = HttpHelper.awaitResponse(requestBuilder.build())
return response.isSuccessful
}
private fun getInputStream(): InputStream? {
httpUrl?.let { url ->
val request = Request.Builder().url(url)
HttpAuth.auth?.let {
request.header("Authorization", Credentials.basic(it.user, it.pass))
}
try {
return HttpHelper.client.newCall(request.build()).execute().body()?.byteStream()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: IllegalArgumentException) {
e.printStackTrace()
}
@Throws(IOException::class)
private suspend fun getInputStream(): InputStream? {
val url = httpUrl
val auth = HttpAuth.auth
if (url != null && auth != null) {
return RxHttp.get(url)
.addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
.toInputStream().await()
}
return null
}

@ -10,6 +10,7 @@ import io.legado.app.help.CacheManager
import io.legado.app.help.JsExtensions
import io.legado.app.help.http.CookieStore
import io.legado.app.utils.*
import kotlinx.coroutines.runBlocking
import org.jsoup.nodes.Entities
import org.mozilla.javascript.NativeObject
import java.net.URL
@ -645,9 +646,9 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions {
override fun ajax(urlStr: String): String? {
return try {
val analyzeUrl = AnalyzeUrl(urlStr, book = book)
val call = analyzeUrl.getResponse(urlStr)
val response = call.execute()
response.body()
runBlocking {
analyzeUrl.getRes(urlStr).body
}
} catch (e: Exception) {
e.localizedMessage
}

@ -18,8 +18,7 @@ object ZipUtils {
* @return `true`: success<br></br>`false`: fail
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun zipFiles(
suspend fun zipFiles(
srcFiles: Collection<String>,
zipFilePath: String
): Boolean {
@ -35,8 +34,7 @@ object ZipUtils {
* @return `true`: success<br></br>`false`: fail
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun zipFiles(
suspend fun zipFiles(
srcFilePaths: Collection<String>?,
zipFilePath: String?,
comment: String?

Loading…
Cancel
Save