cmd reconstruct

v4
laoyuyu 2 years ago
parent 74c2e032c5
commit c23a774dd8
  1. 4
      Http/build.gradle
  2. 56
      Http/src/main/java/com/arialyy/aria/http/download/HttpDStartController.kt
  3. 2
      PublicComponent/build.gradle
  4. 10
      PublicComponent/src/main/java/com/arialyy/aria/core/AriaConfig.java
  5. 4
      PublicComponent/src/main/java/com/arialyy/aria/core/DuaContext.kt
  6. 63
      PublicComponent/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
  7. 28
      PublicComponent/src/main/java/com/arialyy/aria/core/command/AddCmd.java
  8. 45
      PublicComponent/src/main/java/com/arialyy/aria/core/command/CmdChain.kt
  9. 36
      PublicComponent/src/main/java/com/arialyy/aria/core/command/CmdResp.kt
  10. 82
      PublicComponent/src/main/java/com/arialyy/aria/core/command/CommandManager.java
  11. 2
      PublicComponent/src/main/java/com/arialyy/aria/core/command/ICmd.java
  12. 38
      PublicComponent/src/main/java/com/arialyy/aria/core/command/ICmdInterceptor.kt
  13. 110
      PublicComponent/src/main/java/com/arialyy/aria/core/command/StartCmd.java
  14. 44
      PublicComponent/src/main/java/com/arialyy/aria/core/command/TaskCheckInterceptor.kt
  15. 37
      PublicComponent/src/main/java/com/arialyy/aria/core/inf/BaseEntity.kt
  16. 2
      PublicComponent/src/main/java/com/arialyy/aria/core/inf/IEntity.java
  17. 15
      PublicComponent/src/main/java/com/arialyy/aria/core/inf/IStartController.kt
  18. 5
      PublicComponent/src/main/java/com/arialyy/aria/core/inf/ITaskQueue.java
  19. 78
      PublicComponent/src/main/java/com/arialyy/aria/core/listener/BaseListener.java
  20. 5
      PublicComponent/src/main/java/com/arialyy/aria/core/listener/IEventListener.java
  21. 40
      PublicComponent/src/main/java/com/arialyy/aria/core/service/ServiceManager.kt
  22. 18
      PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsTask.java
  23. 5
      PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadTask.java
  24. 7
      PublicComponent/src/main/java/com/arialyy/aria/core/task/ITask.java
  25. 17
      PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskState.kt
  26. 1
      PublicComponent/src/main/java/com/arialyy/aria/orm/DbUtil.kt
  27. 67
      PublicComponent/src/main/java/com/arialyy/aria/orm/EntityCachePool.kt
  28. 5
      PublicComponent/src/main/java/com/arialyy/aria/orm/dao/DEntityDao.kt
  29. 22
      PublicComponent/src/main/java/com/arialyy/aria/orm/entity/DEntity.kt
  30. 11
      Queue/src/main/java/com/arialyy/aria/queue/AbsTaskQueue.java
  31. 2
      Queue/src/main/java/com/arialyy/aria/queue/DTaskQueue.java
  32. 4
      Schedulers/src/main/java/com/arialyy/aria/schedulers/SchedulerComponent.kt
  33. 21
      libs.versions.toml

@ -1,6 +1,7 @@
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
android {
@ -30,6 +31,9 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(path: ':PublicComponent')
implementation(libs.bundles.room)
implementation(libs.kt.coroutines)
kapt libs.room.compiler
}
//apply from: 'bintray-release.gradle'

@ -17,12 +17,16 @@ package com.arialyy.aria.http.download
import android.net.Uri
import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.core.event.EventMsgUtil
import com.arialyy.aria.core.command.AddCmd
import com.arialyy.aria.core.command.StartCmd
import com.arialyy.aria.core.inf.IStartController
import com.arialyy.aria.core.task.DownloadTask
import com.arialyy.aria.http.HttpBaseController
import com.arialyy.aria.http.HttpOption
import com.arialyy.aria.http.HttpUtil
import com.arialyy.aria.orm.EntityCachePool
import com.arialyy.aria.orm.entity.DEntity
import kotlinx.coroutines.launch
/**
* @Author laoyuyu
@ -60,36 +64,54 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
if (HttpUtil.checkHttpDParams(httpDTaskOption)) {
throw IllegalArgumentException("invalid params")
}
val task = DownloadTask()
val task = DownloadTask(httpDTaskOption)
DuaContext.duaScope.launch {
val dEntity = findDEntityBySavePath(httpDTaskOption)
EntityCachePool.putEntity(task.taskId, dEntity)
}
return task
}
override fun add(): Long {
if (!HttpUtil.checkHttpDParams(httpDTaskOption)) {
return -1
/**
* find DEntity, if that not exist, create and save it
*/
private suspend fun findDEntityBySavePath(option: HttpDTaskOption): DEntity {
val savePath = option.savePathUri?.toString()
if (savePath.isNullOrEmpty()) {
throw IllegalArgumentException("savePath is null")
}
EventMsgUtil.getDefault().post()
TODO("Not yet implemented")
val dao = DuaContext.getServiceManager().getDbService().getDuaDb()?.getDEntityDao()
val de = dao?.getDEntityBySavePath(savePath)
if (de != null) {
return de
}
val newDe = DEntity(
sourceUrl = option.sourUrl!!,
savePath = savePath,
)
dao?.insert(newDe)
return newDe
}
override fun create(): Long {
override fun add(): Int {
if (!HttpUtil.checkHttpDParams(httpDTaskOption)) {
return -1
}
TODO("Not yet implemented")
val task = createTask()
val resp = AddCmd(task).executeCmd()
return if (resp.isInterrupt()) -1 else task.taskId
}
override fun resume(): Long {
override fun start(): Int {
if (!HttpUtil.checkHttpDParams(httpDTaskOption)) {
return -1
}
TODO("Not yet implemented")
val task = createTask()
val resp = StartCmd(task).executeCmd()
return if (resp.isInterrupt()) -1 else task.taskId
}
override fun resume(newStart: Boolean): Long {
if (!HttpUtil.checkHttpDParams(httpDTaskOption)) {
return -1
}
TODO("Not yet implemented")
override fun resume(): Int {
return start()
}
}

@ -33,11 +33,11 @@ dependencies {
api project(path: ':AriaAnnotations')
testImplementation(libs.bundles.android.test)
implementation(libs.appcompat)
implementation(libs.bundles.room)
implementation(libs.startup)
api(libs.timber)
api(libs.annotation)
implementation(libs.gson)
implementation(libs.bundles.room)
kapt libs.room.compiler
}

@ -27,6 +27,7 @@ import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import com.arialyy.aria.core.config.AppConfig;
import com.arialyy.aria.core.config.CommonConfig;
import com.arialyy.aria.core.config.Configuration;
import com.arialyy.aria.core.config.DGroupConfig;
import com.arialyy.aria.core.config.DownloadConfig;
@ -56,6 +57,9 @@ public class AriaConfig {
private UploadConfig mUConfig;
private AppConfig mAConfig;
private DGroupConfig mDGConfig;
private CommonConfig mCConfig;
/**
* 是否已经联网true 已经联网
*/
@ -94,6 +98,10 @@ public class AriaConfig {
regNetCallBack(APP);
}
public CommonConfig getCConfig() {
return mCConfig;
}
public DownloadConfig getDConfig() {
return mDConfig;
}
@ -181,7 +189,6 @@ public class AriaConfig {
return false;
}
public boolean isConnectedNet() {
return isConnectedNet;
}
@ -194,6 +201,7 @@ public class AriaConfig {
mUConfig = Configuration.getInstance().uploadCfg;
mAConfig = Configuration.getInstance().appCfg;
mDGConfig = Configuration.getInstance().dGroupCfg;
mCConfig = Configuration.getInstance().cCommonCfg;
File xmlFile = new File(APP.getFilesDir().getPath() + Configuration.XML_FILE);
File tempDir = new File(APP.getFilesDir().getPath() + "/temp");

@ -20,6 +20,7 @@ import android.content.Context
import com.arialyy.aria.core.service.LifecycleManager
import com.arialyy.aria.core.service.ServiceManager
import kotlinx.coroutines.MainScope
import java.util.logging.Handler
/**
* @Author laoyuyu
@ -31,8 +32,9 @@ object DuaContext {
const val DB_SERVICE = "DB_SERVICE"
const val D_QUEUE = "D_QUEUE"
const val U_QUEUE = "U_QUEUE"
const val SCHEDULER = "SCHEDULER"
private val serviceArray = arrayOf(DB_SERVICE, D_QUEUE, U_QUEUE)
private val serviceArray = arrayOf(DB_SERVICE, D_QUEUE, U_QUEUE, SCHEDULER)
val duaScope = MainScope()
lateinit var context: Context

@ -16,20 +16,65 @@
package com.arialyy.aria.core.command;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.queue.AbsTaskQueue;
import com.arialyy.aria.core.DuaContext;
import com.arialyy.aria.core.inf.ITaskQueue;
import com.arialyy.aria.core.task.ITask;
import java.util.ArrayList;
import java.util.List;
/**
* Created by AriaL on 2017/6/29.
*/
public abstract class AbsCmd<T extends AbsTaskWrapper> implements ICmd {
protected AbsTaskQueue mQueue;
protected T mTaskWrapper;
protected String TAG;
public abstract class AbsCmd implements ICmd {
protected ITask mTask;
protected List<ICmdInterceptor> userInterceptors;
protected List<ICmdInterceptor> coreInterceptors = new ArrayList<>();
protected AbsCmd(ITask task) {
mTask = task;
addCoreInterceptor(new TaskCheckInterceptor());
}
/**
* 是否是下载任务的命令
* {@code true} 下载任务的命令{@code false} 上传任务的命令
* add user interceptor
*/
protected boolean isDownloadCmd = true;
public void setInterceptors(List<ICmdInterceptor> userInterceptors) {
this.userInterceptors.addAll(userInterceptors);
}
protected void addCoreInterceptor(ICmdInterceptor interceptor) {
coreInterceptors.add(interceptor);
}
/**
* if interruption occurred, stop cmd
*/
protected CmdResp interceptor() {
if (userInterceptors == null || userInterceptors.isEmpty()) {
return null;
}
List<ICmdInterceptor> interceptors = new ArrayList<>();
interceptors.addAll(userInterceptors);
interceptors.addAll(coreInterceptors);
ICmdInterceptor.IChain chain = new CmdChain(interceptors, 0, mTask, getTaskQueue());
return chain.proceed(mTask);
}
public ITaskQueue<ITask> getTaskQueue() {
ITaskQueue<?> itq = null;
switch (mTask.getTaskType()) {
case ITask.DOWNLOAD: {
itq = DuaContext.INSTANCE.getServiceManager().getDownloadQueue();
break;
}
case ITask.UPLOAD: {
itq = DuaContext.INSTANCE.getServiceManager().getUploadQueue();
break;
}
}
return (ITaskQueue<ITask>) itq;
}
}

@ -16,30 +16,26 @@
package com.arialyy.aria.core.command;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.core.task.ITask;
import timber.log.Timber;
/**
* Created by lyy on 2016/8/22.
* 添加任务的命令
*/
final class AddCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
public final class AddCmd extends AbsCmd {
AddCmd(T entity, int taskType) {
super(entity, taskType);
public AddCmd(ITask task) {
super(task);
}
@Override public void executeCmd() {
if (!canExeCmd) return;
AbsTask task = getTask();
if (task == null) {
mTaskWrapper.getEntity().setState(IEntity.STATE_WAIT);
createTask();
sendWaitState();
} else {
ALog.w(TAG, "添加命令执行失败,【该任务已经存在】");
@Override public CmdResp executeCmd() {
CmdResp resp = interceptor();
if (resp.isInterrupt()) {
Timber.w("interruption occurred, cancel cmd");
return resp;
}
getTaskQueue().addTask(mTask);
return resp;
}
}

@ -0,0 +1,45 @@
/*
* 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.core.command
import com.arialyy.aria.core.inf.ITaskQueue
import com.arialyy.aria.core.task.ITask
/**
* @Author laoyuyu
* @Description
* @Date 11:06 AM 2023/1/27
**/
internal class CmdChain(
private val interceptors: List<ICmdInterceptor>,
private val index: Int = 0,
private val task: ITask,
private val queue: ITaskQueue<ITask>
) : ICmdInterceptor.IChain {
override fun getQueue(): ITaskQueue<ITask> {
return queue
}
override fun getTask(): ITask {
return task
}
override fun proceed(task: ITask): CmdResp {
val next = CmdChain(interceptors, index, task, queue)
val interceptor = interceptors[index]
return interceptor.interceptor(next)
}
}

@ -0,0 +1,36 @@
/*
* 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.core.command
/**
* @Author laoyuyu
* @Description
* @Date 10:39 AM 2023/1/27
**/
class CmdResp(val code: Int = CODE_DEF) {
companion object {
const val CODE_COMPLETE = 1
const val CODE_INTERRUPT = 999
const val CODE_DEF = 0
}
/**
* Whether to interrupt or not
*/
fun isInterrupt() = code == CODE_INTERRUPT
fun isComplete() = code == CODE_COMPLETE
}

@ -15,10 +15,6 @@
*/
package com.arialyy.aria.core.command;
import com.arialyy.aria.core.event.Event;
import com.arialyy.aria.core.event.EventMsgUtil;
import com.arialyy.aria.util.CommonUtil;
/**
* 命令处理器
*/
@ -27,7 +23,6 @@ public class CommandManager {
private static CommandManager instance;
private CommandManager() {
EventMsgUtil.getDefault().register(this);
}
public static void init() {
@ -40,79 +35,10 @@ public class CommandManager {
}
}
@Event
public void add(AddCmd cmd) {
if (CommonUtil.isFastDoubleClick()) {
return;
}
cmd.executeCmd();
}
@Event
public void start(StartCmd cmd) {
cmd.executeCmd();
}
@Event
public void stop(StopCmd cmd) {
cmd.executeCmd();
}
@Event
public void cancel(CancelCmd cmd) {
cmd.executeCmd();
}
@Event
public void stopAll(StopAllCmd cmd) {
if (CommonUtil.isFastDoubleClick()) {
return;
}
cmd.executeCmd();
}
@Event
public void cancelAll(CancelAllCmd cmd) {
if (CommonUtil.isFastDoubleClick()) {
return;
}
cmd.executeCmd();
}
@Event
public void reStart(ReStartCmd cmd) {
if (CommonUtil.isFastDoubleClick()) {
return;
}
cmd.executeCmd();
}
@Event
public void highestPriority(HighestPriorityCmd cmd) {
if (CommonUtil.isFastDoubleClick()) {
return;
}
cmd.executeCmd();
}
@Event
public void resumeAll(ResumeAllCmd cmd) {
if (CommonUtil.isFastDoubleClick()) {
return;
}
cmd.executeCmd();
}
@Event
public void subStart(DGSubStartCmd cmd) {
if (CommonUtil.isFastDoubleClick()) {
return;
}
cmd.executeCmd();
}
@Event
public void subStop(DGSubStopCmd cmd) {
public void exeCmd(ICmd cmd) {
//if (CommonUtil.isFastDoubleClick()) {
// return;
//}
cmd.executeCmd();
}
}

@ -24,5 +24,5 @@ public interface ICmd {
/**
* 执行命令
*/
void executeCmd();
CmdResp executeCmd();
}

@ -0,0 +1,38 @@
/*
* 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.core.command
import com.arialyy.aria.core.inf.ITaskQueue
import com.arialyy.aria.core.task.ITask
/**
* @Author laoyuyu
* @Description
* @Date 10:37 AM 2023/1/27
**/
interface ICmdInterceptor {
/**
* interceptor task
*/
fun interceptor(chain: IChain): CmdResp
interface IChain {
fun getQueue(): ITaskQueue<ITask>
fun getTask(): ITask
fun proceed(task: ITask): CmdResp
}
}

@ -16,109 +16,25 @@
package com.arialyy.aria.core.command;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.common.QueueMod;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.NetUtils;
import com.arialyy.aria.core.task.ITask;
import timber.log.Timber;
/**
* Created by lyy on 2016/8/22. 开始命令 队列模型{@link QueueMod#NOW}{@link QueueMod#WAIT}
* Created by lyy on 2016/8/22.
*/
final public class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
final public class StartCmd extends AbsCmd {
private boolean nowStart = false;
StartCmd(T entity, int taskType) {
super(entity, taskType);
}
/**
* 立即执行任务
*
* @param nowStart true 立即执行任务无论执行队列是否满了
*/
public void setNowStart(boolean nowStart) {
this.nowStart = nowStart;
public StartCmd(ITask task) {
super(task);
}
@Override public void executeCmd() {
if (!canExeCmd) return;
if (!NetUtils.isConnected(AriaConfig.getInstance().getAPP())) {
ALog.e(TAG, "启动任务失败,网络未连接");
return;
}
String mod;
int maxTaskNum = mQueue.getMaxTaskNum();
AriaConfig config = AriaConfig.getInstance();
if (isDownloadCmd) {
mod = config.getDConfig().getQueueMod();
} else {
mod = config.getUConfig().getQueueMod();
}
AbsTask task = getTask();
if (task == null) {
task = createTask();
// 任务不存在时,根据配置不同,对任务执行操作
if (mod.equals(QueueMod.NOW.getTag())) {
startTask();
} else if (mod.equals(QueueMod.WAIT.getTag())) {
int state = task.getTaskState();
if (mQueue.getCurrentExePoolNum() < maxTaskNum) {
if (state == IEntity.STATE_STOP
|| state == IEntity.STATE_FAIL
|| state == IEntity.STATE_OTHER
|| state == IEntity.STATE_PRE
|| state == IEntity.STATE_POST_PRE
|| state == IEntity.STATE_COMPLETE) {
resumeTask();
} else if (state == IEntity.STATE_RUNNING) {
ALog.w(TAG, String.format("任务【%s】已经在运行", task.getTaskName()));
} else {
ALog.d(TAG, String.format("开始新任务, 任务状态:%s", state));
startTask();
}
} else {
if (nowStart) {
startTask();
} else {
sendWaitState(task);
}
@Override public CmdResp executeCmd() {
CmdResp resp = interceptor();
if (resp.isInterrupt()) {
Timber.w("interruption occurred, cancel cmd");
return resp;
}
}
} else {
//任务没执行并且执行队列中没有该任务,才认为任务没有运行中
if (!mQueue.taskIsRunning(task.getKey())) {
if (mod.equals(QueueMod.NOW.getTag())) {
resumeTask();
} else {
if (mQueue.getCurrentExePoolNum() < maxTaskNum) {
resumeTask();
} else {
if (nowStart) {
resumeTask();
} else {
sendWaitState(task);
}
}
}
} else {
ALog.w(TAG, String.format("任务【%s】已经在运行", task.getTaskName()));
}
}
if (mQueue.getCurrentCachePoolNum() == 0) {
findAllWaitTask();
}
}
/**
* 当缓冲队列为null时查找数据库中所有等待中的任务
*/
private void findAllWaitTask() {
new Thread(
new ResumeThread(isDownloadCmd, String.format("state=%s", IEntity.STATE_WAIT))).start();
getTaskQueue().startTask(mTask);
return resp;
}
}

@ -0,0 +1,44 @@
/*
* 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.core.command
import com.arialyy.aria.core.command.ICmdInterceptor.IChain
import timber.log.Timber
/**
* check task state
* @Author laoyuyu
* @Description
* @Date 4:15 PM 2023/1/27
**/
internal class TaskCheckInterceptor : ICmdInterceptor {
/**
* check task state
* 1if task already in queue, interrupt cmd
* 2if task already complete, interrupt cmd
*/
override fun interceptor(chain: IChain): CmdResp {
if (chain.getQueue().taskExists(chain.getTask().taskId)) {
Timber.d("task already in queue")
return CmdResp(CmdResp.CODE_INTERRUPT)
}
if (chain.getTask().taskState.isCompleted()) {
Timber.d("task already complete")
return CmdResp(CmdResp.CODE_INTERRUPT)
}
return chain.proceed(chain.getTask())
}
}

@ -0,0 +1,37 @@
/*
* 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.core.inf
/**
* @Author laoyuyu
* @Description
* @Date 10:26 PM 2023/1/26
**/
abstract class BaseEntity : IEntity {
val createTime: Long = System.currentTimeMillis()
var updateTime: Long = createTime
/**
* task state, [IEntity.STATE_WAIT]
*/
var state: Int = IEntity.STATE_WAIT
/**
* current progress
*/
var progress: Long = 0L
}

@ -57,4 +57,6 @@ public interface IEntity {
* 删除任务
*/
@Ignore int STATE_CANCEL = 7;
void update();
}

@ -26,27 +26,18 @@ interface IStartController {
*
* @return 正常添加返回任务id否则返回-1
*/
fun add(): Long
fun add(): Int
/**
* 创建并开始任务
*
* @return 正常启动返回任务id否则返回-1
*/
fun create(): Long
fun start(): Int
/**
* 恢复任务
* @return 正常启动返回任务id否则返回-1
*/
fun resume(): Long
/**
* 正常来说当执行队列满时调用恢复任务接口只能将任务放到缓存队列中
* 如果希望调用恢复接口马上进入执行队列需要使用该方法
*
* @param newStart true 立即将任务恢复到执行队列中
* @return 正常启动返回任务id否则返回-1
*/
fun resume(newStart: Boolean): Long
fun resume(): Int
}

@ -24,6 +24,11 @@ import com.arialyy.aria.core.task.ITask;
*/
public interface ITaskQueue<TASK extends ITask> extends IService {
/**
* add task to cache queue
*/
boolean addTask(TASK task);
/**
* @return {@code true} task exists
*/

@ -16,42 +16,36 @@
package com.arialyy.aria.core.listener;
import android.os.Handler;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.DuaContext;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.core.task.TaskState;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.exception.AriaException;
import com.arialyy.aria.orm.EntityCachePool;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ErrorHelp;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import timber.log.Timber;
public abstract class BaseListener implements IEventListener {
protected String TAG = getClass().getSimpleName();
static final int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
protected SoftReference<Handler> outHandler;
protected Handler outHandler;
private long mLastLen; //上一次发送长度
private boolean isFirst = true;
private AbsTask mTask;
private ITask mTask;
long mLastSaveTime;
protected AbsEntity mEntity;
protected AbsTaskWrapper mTaskWrapper;
private boolean isConvertSpeed;
private long mUpdateInterval;
@Override public IEventListener setParams(AbsTask task, Handler outHandler) {
this.outHandler = new SoftReference<>(outHandler);
@Override public IEventListener setParams(ITask task) {
this.outHandler = DuaContext.INSTANCE.getServiceManager().getSchedulerHandler();
mTask = new WeakReference<>(task).get();
mEntity = mTask.getTaskWrapper().getEntity();
mTaskWrapper = mTask.getTaskWrapper();
isConvertSpeed = mTaskWrapper.getConfig().isConvertSpeed();
mUpdateInterval = mTaskWrapper.getConfig().getUpdateInterval();
mLastLen = mEntity.getCurrentProgress();
mUpdateInterval = AriaConfig.getInstance().getCConfig().getUpdateInterval();
mLastLen = task.getTaskState().getCurProgress();
mLastSaveTime = System.currentTimeMillis();
TAG = CommonUtil.getClassName(getClass());
return this;
}
@ -75,7 +69,7 @@ public abstract class BaseListener implements IEventListener {
}
@Override public void onProgress(long currentLocation) {
mEntity.setCurrentProgress(currentLocation);
mTask.getTaskState().setCurProgress(currentLocation);
long speed = currentLocation - mLastLen;
if (isFirst) {
speed = 0;
@ -108,21 +102,23 @@ public abstract class BaseListener implements IEventListener {
saveData(IEntity.STATE_CANCEL, -1);
handleSpeed(0);
if (mTask.getSchedulerType() != TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY) {
ALog.d(TAG, "删除任务完成");
Timber.d("remove task success");
sendInState2Target(ISchedulers.CANCEL);
}
}
@Override public void onFail(boolean needRetry, AriaException e) {
mEntity.setFailNum(mEntity.getFailNum() + 1);
saveData(IEntity.STATE_FAIL, mEntity.getCurrentProgress());
TaskState ts = mTask.getTaskState();
int taskFailNum = ts.getFailNum();
ts.setFailNum(taskFailNum + 1);
ts.setNeedRetry(needRetry);
saveData(IEntity.STATE_FAIL, ts.getCurProgress());
handleSpeed(0);
mTask.setNeedRetry(needRetry);
mTask.putExpand(AbsTask.ERROR_INFO_KEY, e);
sendInState2Target(ISchedulers.FAIL);
if (e != null) {
String error = ALog.getExceptionString(e);
ALog.e(TAG, error);
Timber.e(error);
ErrorHelp.saveError(e.getMessage(), error);
}
}
@ -131,22 +127,13 @@ public abstract class BaseListener implements IEventListener {
if (mUpdateInterval != 1000) {
speed = speed * 1000 / mUpdateInterval;
}
if (isConvertSpeed) {
mEntity.setConvertSpeed(CommonUtil.formatFileSize(speed < 0 ? 0 : speed) + "/s");
}
mEntity.setSpeed(speed < 0 ? 0 : speed);
mTask.getTaskState().setSpeed(speed);
int taskType = mTaskWrapper.getRequestType();
if (taskType != ITaskWrapper.M3U8_VOD && taskType != ITaskWrapper.M3U8_LIVE) {
mEntity.setPercent((int) (mEntity.getFileSize() <= 0 ? 0
: mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()));
}
if (mEntity.getFileSize() != 0) {
if (speed == 0) {
mEntity.setTimeLeft(Integer.MAX_VALUE);
} else {
mEntity.setTimeLeft((int) ((mEntity.getFileSize() - mEntity.getCurrentProgress()) / speed));
}
}
}
/**
@ -171,25 +158,22 @@ public abstract class BaseListener implements IEventListener {
* @param state {@link ISchedulers#START}
*/
protected void sendInState2Target(int state) {
if (outHandler.get() != null) {
outHandler.get().obtainMessage(state, mTask).sendToTarget();
}
outHandler.obtainMessage(state, mTask).sendToTarget();
}
protected void saveData(int state, long location) {
mEntity.setState(state);
TaskState ts = mTask.getTaskState();
ts.setState(state);
ts.setCurProgress(location);
if (state == IEntity.STATE_CANCEL) {
handleCancel();
return;
} else if (state == IEntity.STATE_STOP) {
mEntity.setStopTime(System.currentTimeMillis());
} else if (state == IEntity.STATE_COMPLETE) {
handleComplete();
}
if (location > 0) {
mEntity.setCurrentProgress(location);
if (state == IEntity.STATE_COMPLETE) {
handleComplete();
}
mEntity.update();
EntityCachePool.INSTANCE.updateState(mTask.getTaskId(), state, location);
}
}

@ -15,8 +15,7 @@
*/
package com.arialyy.aria.core.listener;
import android.os.Handler;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.exception.AriaException;
/**
@ -25,7 +24,7 @@ import com.arialyy.aria.exception.AriaException;
*/
public interface IEventListener {
IEventListener setParams(AbsTask task, Handler outHandler);
IEventListener setParams(ITask task);
/**
* 预处理有时有些地址链接比较慢这时可以先在这个地方出来一些界面上的UI如按钮的状态

@ -15,9 +15,11 @@
*/
package com.arialyy.aria.core.service
import android.os.Handler
import android.os.Looper
import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.queue.ITaskQueue
import com.arialyy.aria.core.service.QueueManager.registerQueue
import com.arialyy.aria.core.inf.ITaskQueue
import com.arialyy.aria.core.listener.ISchedulers
import com.arialyy.aria.core.task.DownloadTask
import com.arialyy.aria.core.task.UploadTask
import com.arialyy.aria.exception.AriaException
@ -26,6 +28,8 @@ import timber.log.Timber
object ServiceManager {
private val serviceCache = hashMapOf<String, IService>()
private var schedulerHandler: Handler? = null
/**
* register a service
* @param serviceName [DuaContext.DB_SERVICE]
@ -65,21 +69,31 @@ object ServiceManager {
}
/**
* get queue service, if already [registerQueue] custom queue, return custom queue
* get downloadQueue service, if already [registerService] custom queue, return custom queue
*/
fun getDownloadQueue(): com.arialyy.aria.queue.ITaskQueue<DownloadTask> {
if (!DuaContext.isService(DuaContext.D_QUEUE)) {
throw AriaException("${DuaContext.D_QUEUE} not a queue.")
}
fun getDownloadQueue(): ITaskQueue<DownloadTask> {
return (serviceCache[DuaContext.D_QUEUE]
?: throw AriaException("queue not found: ${DuaContext.D_QUEUE}")) as com.arialyy.aria.queue.ITaskQueue<DownloadTask>
?: throw AriaException("queue not found: ${DuaContext.D_QUEUE}")) as ITaskQueue<DownloadTask>
}
fun getUploadQueue(): com.arialyy.aria.queue.ITaskQueue<UploadTask> {
if (!DuaContext.isService(DuaContext.U_QUEUE)) {
throw AriaException("${DuaContext.U_QUEUE} not a queue.")
}
/**
* get uploadQueue service, if already [registerService] custom queue, return custom queue
*/
fun getUploadQueue(): ITaskQueue<UploadTask> {
return (serviceCache[DuaContext.U_QUEUE]
?: throw AriaException("queue not found: ${DuaContext.U_QUEUE}")) as com.arialyy.aria.queue.ITaskQueue<UploadTask>
?: throw AriaException("queue not found: ${DuaContext.U_QUEUE}")) as ITaskQueue<UploadTask>
}
/**
* get uploadQueue service, if already [registerService] custom queue, return custom queue
*/
fun getSchedulerHandler(): Handler {
if (schedulerHandler != null) {
return schedulerHandler!!
}
val scheduler = serviceCache[DuaContext.SCHEDULER] as ISchedulers?
?: throw AriaException("queue not found: ${DuaContext.SCHEDULER}")
schedulerHandler = Handler(Looper.getMainLooper(), scheduler)
return schedulerHandler!!
}
}

@ -15,14 +15,11 @@
*/
package com.arialyy.aria.core.task;
import android.os.Handler;
import android.text.TextUtils;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.inf.ITaskOption;
import com.arialyy.aria.core.inf.IUtil;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ComponentUtil;
import java.util.HashMap;
@ -33,11 +30,6 @@ import timber.log.Timber;
* Created by AriaL on 2017/6/29.
*/
public abstract class AbsTask implements ITask {
public static final String ERROR_INFO_KEY = "ERROR_INFO_KEY";
/**
* 是否需要重试默认为false
*/
private boolean needRetry = true;
protected ITaskOption mTaskOption;
private boolean isCancel = false, isStop = false;
private IUtil mUtil;
@ -116,21 +108,13 @@ public abstract class AbsTask implements ITask {
return mTaskState;
}
@Override public boolean isNeedRetry() {
return needRetry;
}
public void setNeedRetry(boolean needRetry) {
this.needRetry = needRetry;
}
/**
* 任务是否完成
*
* @return {@code true} 已经完成{@code false} 未完成
*/
public boolean isComplete() {
return mTaskState.isComplete();
return mTaskState.isCompleted();
}
/**

@ -17,7 +17,6 @@
package com.arialyy.aria.core.task;
import android.net.Uri;
import android.os.Handler;
import com.arialyy.aria.core.download.DTaskOption;
/**
@ -26,9 +25,9 @@ import com.arialyy.aria.core.download.DTaskOption;
*/
public class DownloadTask extends AbsTask {
private DownloadTask(DTaskOption taskOption) {
public DownloadTask(DTaskOption taskOption) {
super(taskOption);
taskOption.taskListener.setParams(this, outHandler);
taskOption.taskListener.setParams(this);
}
public Uri getSavePath() {

@ -108,13 +108,6 @@ public interface ITask {
*/
boolean isCancel();
/**
* 任务是否需要重试
*
* @return {@code true}任务已经取消
*/
boolean isNeedRetry();
/**
* 任务的调度类型
* {@link TaskSchedulerType}

@ -25,6 +25,17 @@ import com.arialyy.aria.util.CommonUtil
* @Date 10:04 PM 2023/1/24
**/
class TaskState {
/**
* need to try again?default: false
*/
var needRetry = false
/**
* already fail num
*/
var failNum = 0
var state: Int = IEntity.STATE_WAIT
/**
@ -62,7 +73,11 @@ class TaskState {
fun getPercent() = ((curProgress * 100) / fileSize).toInt()
fun isComplete() = state == IEntity.STATE_COMPLETE
fun isCompleted() = state == IEntity.STATE_COMPLETE
fun isStopped() = state == IEntity.STATE_STOP
fun isRunning() = state == IEntity.STATE_RUNNING
/**
* you need set params in config

@ -13,6 +13,7 @@ import java.lang.reflect.Type
* @Date 2:58 下午 2022/4/25
**/
internal object DbUtil {
/**
* 创建存储数据\更新数据时使用的ContentValues
*

@ -0,0 +1,67 @@
/*
* 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.orm
import com.arialyy.aria.core.inf.BaseEntity
import com.arialyy.aria.core.inf.IEntity
import timber.log.Timber
/**
* @Author laoyuyu
* @Description
* @Date 21:43 AM 2023/1/22
**/
object EntityCachePool {
/**
* key: taskId
*/
private val entityMap = hashMapOf<Int, BaseEntity>()
fun putEntity(taskId: Int, entity: BaseEntity) {
if (taskId <= 0) {
Timber.e("invalid taskId: ${taskId}")
return
}
entityMap[taskId] = entity
}
/**
* get entity by taskId
*/
fun getEntity(taskId: Int): IEntity? {
return entityMap[taskId]
}
/**
* update entity state, if [entityMap] no cache, update fail
* @param state [IEntity]
* @param currentProgress task current progress
*/
fun updateState(taskId: Int, state: Int, currentProgress: Long) {
if (taskId <= 0) {
Timber.e("invalid taskId: $taskId")
return
}
val cacheE = entityMap[taskId]
if (cacheE == null) {
Timber.e("update state fail, taskId not found, taskId: $taskId")
return
}
cacheE.state = state
cacheE.progress = currentProgress
cacheE.update()
}
}

@ -33,7 +33,10 @@ interface DEntityDao {
@Transaction
@Query("SELECT * FROM DEntity")
suspend fun getDEntityList():List<DEntity>
suspend fun getDEntityList(): List<DEntity>
@Query("SELECT * FROM DEntity WHERE :savePath=savePath")
suspend fun getDEntityBySavePath(savePath: String): DEntity
@Query("SELECT * FROM DEntity WHERE :dId=dId")
suspend fun getDEntityById(did: String): DEntity

@ -18,7 +18,10 @@ package com.arialyy.aria.orm.entity
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import com.arialyy.aria.core.inf.IEntity
import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.core.inf.BaseEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
/**
* Download Entity
@ -34,7 +37,7 @@ data class DEntity(
*/
val sourceUrl: String,
/**
* file save path
* file save path, it's uri
*/
val savePath: String,
/**
@ -44,7 +47,16 @@ data class DEntity(
val isSub: Boolean = false,
val createTime: Long,
val fileSize: Long = 0
val updateTime: Long
) : IEntity
) : BaseEntity() {
override fun update() {
fun update() {
updateTime = System.currentTimeMillis()
DuaContext.duaScope.launch(Dispatchers.IO) {
DuaContext.getServiceManager().getDbService().getDuaDb()?.getDEntityDao()
?.update(this@DEntity)
}
}
}
}

@ -47,6 +47,15 @@ public abstract class AbsTaskQueue<TASK extends ITask> implements ITaskQueue<TAS
protected abstract int getMaxTaskSize();
@Override public boolean addTask(TASK task) {
if (task == null) {
Timber.e("task is null");
return false;
}
getCachePool().putTask(task);
return false;
}
@Override public boolean taskExists(int taskId) {
return getCachePool().taskExist(taskId) || getExePool().taskExist(taskId);
}
@ -260,6 +269,4 @@ public abstract class AbsTaskQueue<TASK extends ITask> implements ITaskQueue<TAS
Timber.w("start next fail");
return false;
}
}

@ -51,4 +51,6 @@ public class DTaskQueue extends AbsTaskQueue<DownloadTask> {
@Override public void init(@NonNull Context context) {
}
}

@ -1,6 +1,7 @@
package com.arialyy.aria.schedulers
import android.content.Context
import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.core.inf.IComponentInit
/**
@ -10,6 +11,7 @@ import com.arialyy.aria.core.inf.IComponentInit
**/
class SchedulerComponent : IComponentInit {
override fun init(context: Context) {
DuaContext.getServiceManager()
.registerService(DuaContext.SCHEDULER, TaskSchedulers.getInstance())
}
}

@ -2,7 +2,7 @@
minSdk = "23"
compilesdk = "32"
targetsdk = "30"
buildToolsVersion="30.0.2"
buildToolsVersion = "30.0.2"
appcompat = "1.6.0"
recyclerview = "1.2.1"
room = "2.5.0"
@ -15,25 +15,26 @@ startup = "1.1.1"
timber = "5.0.1"
gson = "2.10.1"
annotation = "1.5.0"
coroutines = "1.6.4"
[libraries]
kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" }
recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
room-common = {module = "androidx.room:room-common", version.ref = "room"}
room-common = { module = "androidx.room:room-common", version.ref = "room" }
junit = { module = "junit:junit", version.ref = "test-junit" }
android-junit = { module = "androidx.test.ext:junit", version.ref = "android-junit" }
android-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "android-espresso" }
android-ktx = { module = "androidx.core:core-ktx", version.ref = "android-ktx" }
appcompat = {module = "androidx.appcompat:appcompat", version.ref = "appcompat"}
lifecycle-viewmodel-ktx = {module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle"}
lifecycle-viewmodel-compose = {module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle"}
lifecycle-runtime-ktx = {module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle"}
startup = {module = "androidx.startup:startup-runtime", version.ref = "startup"}
timber = {module = "com.jakewharton.timber:timber", version.ref = "timber"}
gson = {module = "com.google.code.gson:gson", version.ref = "gson"}
appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" }
lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }
startup = { module = "androidx.startup:startup-runtime", version.ref = "startup" }
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
[bundles]
room = ["room-runtime", "room-common"]

Loading…
Cancel
Save