parent
e6867c7173
commit
a446db3946
@ -0,0 +1,91 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package com.arialyy.aria.http.download |
||||||
|
|
||||||
|
import com.arialyy.aria.core.inf.IBlockManager |
||||||
|
import com.arialyy.aria.core.inf.ITaskOption |
||||||
|
import com.arialyy.aria.core.manager.ThreadTaskManager |
||||||
|
import com.arialyy.aria.core.task.ITask |
||||||
|
import com.arialyy.aria.core.task.ITaskInterceptor |
||||||
|
import com.arialyy.aria.core.task.TaskChain |
||||||
|
import com.arialyy.aria.core.task.TaskResp |
||||||
|
import timber.log.Timber |
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor |
||||||
|
import java.util.concurrent.TimeUnit.MILLISECONDS |
||||||
|
|
||||||
|
/** |
||||||
|
* @Author laoyuyu |
||||||
|
* @Description |
||||||
|
* @Date 2:27 PM 2023/2/05 |
||||||
|
**/ |
||||||
|
open class TimerInterceptor : ITaskInterceptor { |
||||||
|
private var mTimer: ScheduledThreadPoolExecutor = ScheduledThreadPoolExecutor(1) |
||||||
|
|
||||||
|
@Synchronized private fun closeTimer() { |
||||||
|
if (!mTimer.isShutdown) { |
||||||
|
mTimer.shutdown() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override suspend fun interceptor(chain: TaskChain): TaskResp { |
||||||
|
val b = startTimer(chain) |
||||||
|
if (!b) { |
||||||
|
return TaskResp(TaskResp.CODE_INTERRUPT) |
||||||
|
} |
||||||
|
return chain.proceed(chain.getTask()) |
||||||
|
} |
||||||
|
|
||||||
|
@Synchronized private fun startTimer(chain: TaskChain): Boolean { |
||||||
|
closeTimer() |
||||||
|
try { |
||||||
|
mTimer = ScheduledThreadPoolExecutor(1) |
||||||
|
val blockManager = chain.blockManager |
||||||
|
mTimer.scheduleWithFixedDelay(object : Runnable { |
||||||
|
override fun run() { |
||||||
|
// 线程池中是不抛异常的,没有日志,很难定位问题,需要手动try-catch |
||||||
|
try { |
||||||
|
if (blockManager.isCompleted |
||||||
|
|| blockManager.hasFailedBlock() |
||||||
|
|| !isRunning(chain.getTask()) |
||||||
|
) { |
||||||
|
ThreadTaskManager.getInstance().removeTaskThread(chain.getTask().taskId) |
||||||
|
closeTimer() |
||||||
|
return |
||||||
|
} |
||||||
|
if (chain.getTask().taskState.curProgress >= 0) { |
||||||
|
chain.getTask().getTaskOption(ITaskOption::class.java).taskListener.onProgress( |
||||||
|
blockManager.currentProgress |
||||||
|
) |
||||||
|
return |
||||||
|
} |
||||||
|
Timber.d("未知状态") |
||||||
|
} catch (e: Exception) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
}, 0, 1000, MILLISECONDS) |
||||||
|
} catch (e: Exception) { |
||||||
|
Timber.e(e) |
||||||
|
return false |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
@Synchronized fun isRunning(task: ITask): Boolean { |
||||||
|
return ThreadTaskManager.getInstance().taskIsRunning(task.taskId) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
package com.arialyy.aria.core.task |
||||||
|
|
||||||
|
import android.bluetooth.BluetoothClass |
||||||
|
import com.arialyy.aria.orm.entity.BlockRecord |
||||||
|
import com.arialyy.aria.orm.entity.TaskRecord |
||||||
|
import com.arialyy.aria.util.FileUtil |
||||||
|
import timber.log.Timber |
||||||
|
import java.io.File |
||||||
|
|
||||||
|
/* |
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
object BlockUtil { |
||||||
|
|
||||||
|
/** |
||||||
|
* create block record |
||||||
|
*/ |
||||||
|
fun createBlockRecord(fileSize: Long): List<BlockRecord> { |
||||||
|
val blockNumInfo = getBlockNum(fileSize) |
||||||
|
val lastIndex = blockNumInfo.first - 1 |
||||||
|
val brList = mutableListOf<BlockRecord>() |
||||||
|
for (bi in 0 until blockNumInfo.first) { |
||||||
|
val sl = bi * BlockState.BLOCK_SIZE |
||||||
|
val blockSize = if (bi == lastIndex) blockNumInfo.second else BlockState.BLOCK_SIZE |
||||||
|
val el = sl + blockSize |
||||||
|
val blockRecord = BlockRecord( |
||||||
|
bId = bi, |
||||||
|
startLocation = bi * BlockState.BLOCK_SIZE, |
||||||
|
endLocation = el, |
||||||
|
blockSize = blockSize, |
||||||
|
) |
||||||
|
brList.add(blockRecord) |
||||||
|
} |
||||||
|
return brList |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the number of blocks according to the file length |
||||||
|
* @return pair<blockNum, lastBlockSize> |
||||||
|
*/ |
||||||
|
fun getBlockNum(fileLen: Long): Pair<Int, Long> { |
||||||
|
if (fileLen <= BlockState.BLOCK_SIZE) { |
||||||
|
return Pair(1, 0) |
||||||
|
} |
||||||
|
val blockNum = (fileLen / BlockState.BLOCK_SIZE).toInt() |
||||||
|
val lastBlockSize = fileLen % BlockState.BLOCK_SIZE |
||||||
|
return Pair(if (lastBlockSize != 0L) blockNum + 1 else blockNum, lastBlockSize) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* merge block file,if success,return true else return false |
||||||
|
*/ |
||||||
|
fun mergeFile(record: TaskRecord): Boolean { |
||||||
|
val targetF = File(record.filePath) |
||||||
|
val dir = targetF.parentFile ?: return false |
||||||
|
val fileName = targetF.name |
||||||
|
if (record.blockNum == 1) { |
||||||
|
// if this task not support blocks or fileSize < 5m, just need rename |
||||||
|
return File(BlockState.BLOCK_PATH.format(dir, fileName, 0)).renameTo(targetF) |
||||||
|
} |
||||||
|
val blockList = mutableListOf<File>() |
||||||
|
for (i in 0 until record.blockNum) { |
||||||
|
val subF = File(BlockState.BLOCK_PATH.format(dir, fileName, i)) |
||||||
|
if (!subF.exists()) { |
||||||
|
Timber.e("this block: $i not exists") |
||||||
|
return false |
||||||
|
} |
||||||
|
if (subF.length() != BlockState.BLOCK_SIZE.toLong()) { |
||||||
|
Timber.e("this block: $i size abnormal, size: ${subF.length()}") |
||||||
|
return false |
||||||
|
} |
||||||
|
blockList.add(subF) |
||||||
|
} |
||||||
|
return FileUtil.mergeFile(record.filePath, blockList) |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue