Cronet共用okhttp的线程池
This commit is contained in:
@@ -2,7 +2,7 @@ package io.legado.app.help.http.cronet
|
|||||||
|
|
||||||
import io.legado.app.help.http.okHttpClient
|
import io.legado.app.help.http.okHttpClient
|
||||||
import io.legado.app.utils.DebugLog
|
import io.legado.app.utils.DebugLog
|
||||||
import io.legado.app.utils.rethrowAsIOException
|
import io.legado.app.utils.asIOException
|
||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
import okhttp3.EventListener
|
import okhttp3.EventListener
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
@@ -27,12 +27,24 @@ abstract class AbsCallBack(
|
|||||||
|
|
||||||
var mResponse: Response
|
var mResponse: Response
|
||||||
|
|
||||||
var mException: IOException? = null
|
|
||||||
private var followCount = 0
|
private var followCount = 0
|
||||||
|
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
abstract fun waitForDone(urlRequest: UrlRequest): Response
|
abstract fun waitForDone(urlRequest: UrlRequest): Response
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当发生错误时,通知子类终止阻塞抛出错误
|
||||||
|
* @param error
|
||||||
|
*/
|
||||||
|
abstract fun onError(error: IOException)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求成功后,通知子类结束阻塞,返回response
|
||||||
|
* @param response
|
||||||
|
*/
|
||||||
|
abstract fun onSuccess(response: Response)
|
||||||
|
|
||||||
|
|
||||||
override fun onRedirectReceived(
|
override fun onRedirectReceived(
|
||||||
request: UrlRequest,
|
request: UrlRequest,
|
||||||
@@ -41,10 +53,13 @@ abstract class AbsCallBack(
|
|||||||
) {
|
) {
|
||||||
if (followCount > MAX_FOLLOW_COUNT) {
|
if (followCount > MAX_FOLLOW_COUNT) {
|
||||||
request.cancel()
|
request.cancel()
|
||||||
mException = IOException("Too many redirect")
|
onError(IOException("Too many redirect"))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (mCall.isCanceled()) {
|
if (mCall.isCanceled()) {
|
||||||
mException = IOException("Request Canceled")
|
onError(IOException("Request Canceled"))
|
||||||
|
request.cancel()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
followCount += 1
|
followCount += 1
|
||||||
val client = okHttpClient
|
val client = okHttpClient
|
||||||
@@ -55,7 +70,7 @@ abstract class AbsCallBack(
|
|||||||
} else if (okHttpClient.followRedirects) {
|
} else if (okHttpClient.followRedirects) {
|
||||||
request.followRedirect()
|
request.followRedirect()
|
||||||
} else {
|
} else {
|
||||||
mException = IOException("Too many redirect")
|
onError(IOException("Too many redirect"))
|
||||||
request.cancel()
|
request.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +88,7 @@ abstract class AbsCallBack(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(IOException::class)
|
||||||
override fun onReadCompleted(
|
override fun onReadCompleted(
|
||||||
request: UrlRequest,
|
request: UrlRequest,
|
||||||
info: UrlResponseInfo,
|
info: UrlResponseInfo,
|
||||||
@@ -83,7 +98,7 @@ abstract class AbsCallBack(
|
|||||||
|
|
||||||
if (mCall.isCanceled()) {
|
if (mCall.isCanceled()) {
|
||||||
request.cancel()
|
request.cancel()
|
||||||
mException = IOException("Request Canceled")
|
onError(IOException("Request Canceled"))
|
||||||
}
|
}
|
||||||
|
|
||||||
byteBuffer.flip()
|
byteBuffer.flip()
|
||||||
@@ -91,9 +106,9 @@ abstract class AbsCallBack(
|
|||||||
try {
|
try {
|
||||||
buffer.write(byteBuffer)
|
buffer.write(byteBuffer)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
DebugLog.i(javaClass.name, "IOException during ByteBuffer read. Details: ", e)
|
DebugLog.e(javaClass.name, "IOException during ByteBuffer read. Details: ", e)
|
||||||
mException = IOException("IOException during ByteBuffer read. Details:", e)
|
onError(IOException("IOException during ByteBuffer read. Details:", e))
|
||||||
throw e
|
return
|
||||||
}
|
}
|
||||||
byteBuffer.clear()
|
byteBuffer.clear()
|
||||||
request.read(byteBuffer)
|
request.read(byteBuffer)
|
||||||
@@ -108,7 +123,8 @@ abstract class AbsCallBack(
|
|||||||
buffer.asResponseBody(contentType)
|
buffer.asResponseBody(contentType)
|
||||||
val newRequest = originalRequest.newBuilder().url(info.url).build()
|
val newRequest = originalRequest.newBuilder().url(info.url).build()
|
||||||
this.mResponse = this.mResponse.newBuilder().body(responseBody).request(newRequest).build()
|
this.mResponse = this.mResponse.newBuilder().body(responseBody).request(newRequest).build()
|
||||||
DebugLog.i(javaClass.simpleName, "end[${info.negotiatedProtocol}]${info.url}")
|
onSuccess(this.mResponse)
|
||||||
|
//DebugLog.i(javaClass.simpleName, "end[${info.negotiatedProtocol}]${info.url}")
|
||||||
|
|
||||||
eventListener?.callEnd(mCall)
|
eventListener?.callEnd(mCall)
|
||||||
if (responseCallback != null) {
|
if (responseCallback != null) {
|
||||||
@@ -123,8 +139,8 @@ abstract class AbsCallBack(
|
|||||||
|
|
||||||
//UrlResponseInfo可能为null
|
//UrlResponseInfo可能为null
|
||||||
override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) {
|
override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) {
|
||||||
DebugLog.i(javaClass.name, error.message.toString())
|
DebugLog.e(javaClass.name, error.message.toString())
|
||||||
mException = error.rethrowAsIOException()
|
onError(error.asIOException())
|
||||||
this.eventListener?.callFailed(mCall, error)
|
this.eventListener?.callFailed(mCall, error)
|
||||||
responseCallback?.onFailure(mCall, error)
|
responseCallback?.onFailure(mCall, error)
|
||||||
}
|
}
|
||||||
@@ -132,7 +148,7 @@ abstract class AbsCallBack(
|
|||||||
override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
|
override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
|
||||||
super.onCanceled(request, info)
|
super.onCanceled(request, info)
|
||||||
this.eventListener?.callEnd(mCall)
|
this.eventListener?.callEnd(mCall)
|
||||||
mException = IOException("Cronet Request Canceled")
|
onError(IOException("Cronet Request Canceled"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.legado.app.help.http.cronet
|
|||||||
|
|
||||||
import io.legado.app.constant.AppLog
|
import io.legado.app.constant.AppLog
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
|
import io.legado.app.help.http.okHttpClient
|
||||||
import io.legado.app.utils.DebugLog
|
import io.legado.app.utils.DebugLog
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.MediaType
|
import okhttp3.MediaType
|
||||||
@@ -13,11 +14,8 @@ import org.chromium.net.UploadDataProviders
|
|||||||
import org.chromium.net.UrlRequest
|
import org.chromium.net.UrlRequest
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService
|
|
||||||
import java.util.concurrent.Executors
|
|
||||||
|
|
||||||
|
//val executor: ExecutorService by lazy { Executors.newCachedThreadPool() }
|
||||||
val executor: ExecutorService by lazy { Executors.newCachedThreadPool() }
|
|
||||||
|
|
||||||
val cronetEngine: ExperimentalCronetEngine? by lazy {
|
val cronetEngine: ExperimentalCronetEngine? by lazy {
|
||||||
if (!AppConfig.isGooglePlay) {
|
if (!AppConfig.isGooglePlay) {
|
||||||
@@ -48,7 +46,11 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest? {
|
|||||||
val url = request.url.toString()
|
val url = request.url.toString()
|
||||||
val headers: Headers = request.headers
|
val headers: Headers = request.headers
|
||||||
val requestBody = request.body
|
val requestBody = request.body
|
||||||
return cronetEngine?.newUrlRequestBuilder(url, callback, executor)?.apply {
|
return cronetEngine?.newUrlRequestBuilder(
|
||||||
|
url,
|
||||||
|
callback,
|
||||||
|
okHttpClient.dispatcher.executorService
|
||||||
|
)?.apply {
|
||||||
setHttpMethod(request.method)//设置
|
setHttpMethod(request.method)//设置
|
||||||
allowDirectExecutor()
|
allowDirectExecutor()
|
||||||
headers.forEachIndexed { index, _ ->
|
headers.forEachIndexed { index, _ ->
|
||||||
@@ -65,7 +67,7 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest? {
|
|||||||
requestBody.writeTo(buffer)
|
requestBody.writeTo(buffer)
|
||||||
setUploadDataProvider(
|
setUploadDataProvider(
|
||||||
UploadDataProviders.create(buffer.readByteArray()),
|
UploadDataProviders.create(buffer.readByteArray()),
|
||||||
executor
|
okHttpClient.dispatcher.executorService
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor {
|
|||||||
OldCallback(request, call)
|
OldCallback(request, call)
|
||||||
}
|
}
|
||||||
buildRequest(request, callBack)?.let {
|
buildRequest(request, callBack)?.let {
|
||||||
it.start()
|
|
||||||
return callBack.waitForDone(it)
|
return callBack.waitForDone(it)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -268,7 +268,8 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
download = true
|
download = true
|
||||||
executor.execute {
|
|
||||||
|
Coroutine.async {
|
||||||
val result = downloadFileIfNotExist(url, downloadTempFile)
|
val result = downloadFileIfNotExist(url, downloadTempFile)
|
||||||
DebugLog.d(javaClass.simpleName, "download result:$result")
|
DebugLog.d(javaClass.simpleName, "download result:$result")
|
||||||
//文件md5再次校验
|
//文件md5再次校验
|
||||||
@@ -279,7 +280,7 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
|
|||||||
downloadTempFile.deleteOnExit()
|
downloadTempFile.deleteOnExit()
|
||||||
}
|
}
|
||||||
download = false
|
download = false
|
||||||
return@execute
|
return@async
|
||||||
}
|
}
|
||||||
DebugLog.d(javaClass.simpleName, "download success, copy to $destSuccessFile")
|
DebugLog.d(javaClass.simpleName, "download success, copy to $destSuccessFile")
|
||||||
//下载成功拷贝文件
|
//下载成功拷贝文件
|
||||||
@@ -289,6 +290,9 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
|
|||||||
@Suppress("SameParameterValue")
|
@Suppress("SameParameterValue")
|
||||||
deleteHistoryFile(parentFile!!, null)
|
deleteHistoryFile(parentFile!!, null)
|
||||||
}
|
}
|
||||||
|
// executor.execute {
|
||||||
|
//
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,11 +6,8 @@ import androidx.annotation.RequiresApi
|
|||||||
import okhttp3.Call
|
import okhttp3.Call
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.chromium.net.CronetException
|
|
||||||
import org.chromium.net.UrlRequest
|
import org.chromium.net.UrlRequest
|
||||||
import org.chromium.net.UrlResponseInfo
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.ByteBuffer
|
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@@ -21,45 +18,29 @@ class NewCallBack(originalRequest: Request, mCall: Call) : AbsCallBack(originalR
|
|||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun waitForDone(urlRequest: UrlRequest): Response {
|
override fun waitForDone(urlRequest: UrlRequest): Response {
|
||||||
return responseFuture.get(mCall.timeout().timeoutNanos(), TimeUnit.NANOSECONDS)
|
urlRequest.start()
|
||||||
}
|
return if (mCall.timeout().timeoutNanos() > 0) {
|
||||||
|
responseFuture.get(mCall.timeout().timeoutNanos(), TimeUnit.NANOSECONDS)
|
||||||
override fun onRedirectReceived(
|
} else {
|
||||||
request: UrlRequest,
|
return responseFuture.get()
|
||||||
info: UrlResponseInfo,
|
|
||||||
newLocationUrl: String
|
|
||||||
) {
|
|
||||||
super.onRedirectReceived(request, info, newLocationUrl)
|
|
||||||
if (mException != null) {
|
|
||||||
responseFuture.completeExceptionally(mException)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
override fun onReadCompleted(
|
* 当发生错误时,通知子类终止阻塞抛出错误
|
||||||
request: UrlRequest,
|
* @param error
|
||||||
info: UrlResponseInfo,
|
*/
|
||||||
byteBuffer: ByteBuffer
|
override fun onError(error: IOException) {
|
||||||
) {
|
responseFuture.completeExceptionally(error)
|
||||||
super.onReadCompleted(request, info, byteBuffer)
|
|
||||||
if (mException != null) {
|
|
||||||
responseFuture.completeExceptionally(mException)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {
|
/**
|
||||||
super.onSucceeded(request, info)
|
* 请求成功后,通知子类结束阻塞,返回response
|
||||||
responseFuture.complete(mResponse)
|
* @param response
|
||||||
}
|
*/
|
||||||
|
override fun onSuccess(response: Response) {
|
||||||
override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) {
|
responseFuture.complete(response)
|
||||||
super.onFailed(request, info, error)
|
|
||||||
responseFuture.completeExceptionally(mException)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
|
|
||||||
super.onCanceled(request, info)
|
|
||||||
responseFuture.completeExceptionally(mException)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,20 +4,19 @@ import android.os.ConditionVariable
|
|||||||
import okhttp3.Call
|
import okhttp3.Call
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.chromium.net.CronetException
|
|
||||||
import org.chromium.net.UrlRequest
|
import org.chromium.net.UrlRequest
|
||||||
import org.chromium.net.UrlResponseInfo
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
class OldCallback(originalRequest: Request, mCall: Call) : AbsCallBack(originalRequest, mCall) {
|
class OldCallback(originalRequest: Request, mCall: Call) : AbsCallBack(originalRequest, mCall) {
|
||||||
|
|
||||||
private val mResponseCondition = ConditionVariable()
|
private val mResponseCondition = ConditionVariable()
|
||||||
|
private var mException: IOException? = null
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun waitForDone(urlRequest: UrlRequest): Response {
|
override fun waitForDone(urlRequest: UrlRequest): Response {
|
||||||
//获取okhttp call的完整请求的超时时间
|
//获取okhttp call的完整请求的超时时间
|
||||||
val timeOutMs: Long = mCall.timeout().timeoutNanos() / 1000000
|
val timeOutMs: Long = mCall.timeout().timeoutNanos() / 1000000
|
||||||
|
urlRequest.start()
|
||||||
if (timeOutMs > 0) {
|
if (timeOutMs > 0) {
|
||||||
mResponseCondition.block(timeOutMs)
|
mResponseCondition.block(timeOutMs)
|
||||||
} else {
|
} else {
|
||||||
@@ -32,35 +31,25 @@ class OldCallback(originalRequest: Request, mCall: Call) : AbsCallBack(originalR
|
|||||||
if (mException != null) {
|
if (mException != null) {
|
||||||
throw mException as IOException
|
throw mException as IOException
|
||||||
}
|
}
|
||||||
return this.mResponse
|
return mResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
override fun onReadCompleted(
|
* 当发生错误时,通知子类终止阻塞抛出错误
|
||||||
request: UrlRequest,
|
* @param error
|
||||||
info: UrlResponseInfo,
|
*/
|
||||||
byteBuffer: ByteBuffer
|
override fun onError(error: IOException) {
|
||||||
) {
|
mException = error
|
||||||
super.onReadCompleted(request, info, byteBuffer)
|
|
||||||
if (mException != null) {
|
|
||||||
mResponseCondition.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {
|
|
||||||
super.onSucceeded(request, info)
|
|
||||||
mResponseCondition.open()
|
mResponseCondition.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) {
|
/**
|
||||||
super.onFailed(request, info, error)
|
* 请求成功后,通知子类结束阻塞,返回response
|
||||||
|
* @param response
|
||||||
|
*/
|
||||||
|
override fun onSuccess(response: Response) {
|
||||||
mResponseCondition.open()
|
mResponseCondition.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
|
|
||||||
super.onCanceled(request, info)
|
|
||||||
mResponseCondition.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -12,8 +12,8 @@ val Throwable.msg: String
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Throwable.rethrowAsIOException(): IOException {
|
fun Throwable.asIOException(): IOException {
|
||||||
val newException = IOException(this.message)
|
val newException = IOException(this.message)
|
||||||
newException.initCause(this)
|
newException.initCause(this)
|
||||||
throw newException
|
return newException
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user