parent
b3501dc3c3
commit
4b8eeca164
@ -0,0 +1,159 @@ |
||||
/* |
||||
* 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.download; |
||||
|
||||
import android.support.annotation.CheckResult; |
||||
import android.text.TextUtils; |
||||
import com.arialyy.aria.core.inf.AbsEntity; |
||||
import com.arialyy.aria.core.inf.IGroupTarget; |
||||
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue; |
||||
import com.arialyy.aria.orm.DbEntity; |
||||
import com.arialyy.aria.util.ALog; |
||||
import com.arialyy.aria.util.CommonUtil; |
||||
import java.io.File; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* Created by lyy on 2019/4/9. |
||||
* 下载组合任务功能 |
||||
*/ |
||||
abstract class AbsGroupDelegate<TARGET extends AbsDGTarget> implements IGroupTarget { |
||||
protected String TAG; |
||||
private TARGET mTarget; |
||||
private DGTaskWrapper mWrapper; |
||||
/** |
||||
* 组任务名 |
||||
*/ |
||||
private String mGroupHash; |
||||
/** |
||||
* 文件夹临时路径 |
||||
*/ |
||||
private String mDirPathTemp; |
||||
/** |
||||
* 是否需要修改路径 |
||||
*/ |
||||
private boolean needModifyPath = false; |
||||
|
||||
AbsGroupDelegate(TARGET target, DGTaskWrapper wrapper) { |
||||
TAG = CommonUtil.getClassName(getClass()); |
||||
mTarget = target; |
||||
mWrapper = wrapper; |
||||
setGroupHash(wrapper.getKey()); |
||||
mTarget.setTaskWrapper(wrapper); |
||||
if (getEntity() != null) { |
||||
mDirPathTemp = getEntity().getDirPath(); |
||||
} |
||||
} |
||||
|
||||
@Override public boolean isRunning() { |
||||
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(getEntity().getKey()); |
||||
return task != null && task.isRunning(); |
||||
} |
||||
|
||||
@CheckResult |
||||
TARGET setDirPath(String dirPath) { |
||||
mDirPathTemp = dirPath; |
||||
return mTarget; |
||||
} |
||||
|
||||
/** |
||||
* 改变任务组文件夹路径,修改文件夹路径会将子任务所有路径更换 |
||||
* |
||||
* @param newDirPath 新的文件夹路径 |
||||
*/ |
||||
void reChangeDirPath(String newDirPath) { |
||||
List<DTaskWrapper> subTasks = mWrapper.getSubTaskWrapper(); |
||||
if (subTasks != null && !subTasks.isEmpty()) { |
||||
List<DbEntity> des = new ArrayList<>(); |
||||
for (DTaskWrapper dte : subTasks) { |
||||
DownloadEntity de = dte.getEntity(); |
||||
String oldPath = de.getDownloadPath(); |
||||
String newPath = newDirPath + "/" + de.getFileName(); |
||||
File file = new File(oldPath); |
||||
if (file.exists()) { |
||||
file.renameTo(new File(newPath)); |
||||
} |
||||
de.setDownloadPath(newPath); |
||||
des.add(de); |
||||
} |
||||
AbsEntity.saveAll(des); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 检查并设置文件夹路径 |
||||
* |
||||
* @return {@code true} 合法 |
||||
*/ |
||||
@Override public boolean checkDirPath() { |
||||
if (TextUtils.isEmpty(mDirPathTemp)) { |
||||
ALog.e(TAG, "文件夹路径不能为null"); |
||||
return false; |
||||
} else if (!mDirPathTemp.startsWith("/")) { |
||||
ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误"); |
||||
return false; |
||||
} |
||||
File file = new File(mDirPathTemp); |
||||
if (file.isFile()) { |
||||
ALog.e(TAG, "路径【" + mDirPathTemp + "】是文件,请设置文件夹路径"); |
||||
return false; |
||||
} |
||||
|
||||
if (TextUtils.isEmpty(getEntity().getDirPath()) || !getEntity().getDirPath() |
||||
.equals(mDirPathTemp)) { |
||||
if (!file.exists()) { |
||||
file.mkdirs(); |
||||
} |
||||
needModifyPath = true; |
||||
getEntity().setDirPath(mDirPathTemp); |
||||
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mDirPathTemp)); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
@Override public DownloadGroupEntity getEntity() { |
||||
return mWrapper.getEntity(); |
||||
} |
||||
|
||||
@Override public boolean taskExists() { |
||||
return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", mWrapper.getKey()); |
||||
} |
||||
|
||||
DGTaskWrapper getTaskWrapper() { |
||||
return mWrapper; |
||||
} |
||||
|
||||
boolean isNeedModifyPath() { |
||||
return needModifyPath; |
||||
} |
||||
|
||||
String getDirPathTemp() { |
||||
return mDirPathTemp; |
||||
} |
||||
|
||||
TARGET getTarget() { |
||||
return mTarget; |
||||
} |
||||
|
||||
public String getGroupHash() { |
||||
return mGroupHash; |
||||
} |
||||
|
||||
public void setGroupHash(String groupHash) { |
||||
this.mGroupHash = groupHash; |
||||
} |
||||
} |
@ -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.core.download; |
||||
|
||||
import android.text.TextUtils; |
||||
import com.arialyy.aria.core.FtpUrlEntity; |
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper; |
||||
import com.arialyy.aria.util.ALog; |
||||
|
||||
/** |
||||
* Created by lyy on 2017/4/9. |
||||
* ftp文件夹下载功能代理 |
||||
*/ |
||||
class FtpDirDelegate extends AbsGroupDelegate<FtpDirDownloadTarget> { |
||||
FtpDirDelegate(FtpDirDownloadTarget target, DGTaskWrapper wrapper) { |
||||
super(target, wrapper); |
||||
wrapper.setRequestType(AbsTaskWrapper.D_FTP_DIR); |
||||
} |
||||
|
||||
@Override public boolean checkEntity() { |
||||
boolean b = checkDirPath() && checkUrl(); |
||||
if (b) { |
||||
getEntity().save(); |
||||
if (getTaskWrapper().getSubTaskWrapper() != null) { |
||||
//初始化子项的登录信息
|
||||
FtpUrlEntity tUrlEntity = getTaskWrapper().asFtp().getUrlEntity(); |
||||
for (DTaskWrapper wrapper : getTaskWrapper().getSubTaskWrapper()) { |
||||
FtpUrlEntity urlEntity = wrapper.asFtp().getUrlEntity(); |
||||
urlEntity.needLogin = tUrlEntity.needLogin; |
||||
urlEntity.account = tUrlEntity.account; |
||||
urlEntity.user = tUrlEntity.user; |
||||
urlEntity.password = tUrlEntity.password; |
||||
// 处理ftps详细
|
||||
if (tUrlEntity.isFtps) { |
||||
urlEntity.isFtps = true; |
||||
urlEntity.protocol = tUrlEntity.protocol; |
||||
urlEntity.storePath = tUrlEntity.storePath; |
||||
urlEntity.storePass = tUrlEntity.storePass; |
||||
urlEntity.keyAlias = tUrlEntity.keyAlias; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if (getTaskWrapper().asFtp().getUrlEntity().isFtps) { |
||||
if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().storePath)) { |
||||
ALog.e(TAG, "证书路径为空"); |
||||
return false; |
||||
} |
||||
if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().keyAlias)) { |
||||
ALog.e(TAG, "证书别名为空"); |
||||
return false; |
||||
} |
||||
} |
||||
return b; |
||||
} |
||||
|
||||
/** |
||||
* 检查普通任务的下载地址 |
||||
* |
||||
* @return {@code true}地址合法 |
||||
*/ |
||||
private boolean checkUrl() { |
||||
final String url = getGroupHash(); |
||||
if (TextUtils.isEmpty(url)) { |
||||
ALog.e(TAG, "下载失败,url为null"); |
||||
return false; |
||||
} else if (!url.startsWith("ftp")) { |
||||
ALog.e(TAG, "下载失败,url【" + url + "】错误"); |
||||
return false; |
||||
} |
||||
int index = url.indexOf("://"); |
||||
if (index == -1) { |
||||
ALog.e(TAG, "下载失败,url【" + url + "】不合法"); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,238 @@ |
||||
/* |
||||
* 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.download; |
||||
|
||||
import android.support.annotation.CheckResult; |
||||
import android.text.TextUtils; |
||||
import com.arialyy.aria.core.common.RequestEnum; |
||||
import com.arialyy.aria.orm.DbEntity; |
||||
import com.arialyy.aria.util.ALog; |
||||
import com.arialyy.aria.util.CommonUtil; |
||||
import java.util.ArrayList; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* Created by lyy on 2019/4/9. |
||||
* |
||||
* http组合任务功能代理 |
||||
*/ |
||||
class HttpGroupDelegate extends AbsGroupDelegate<DownloadGroupTarget> { |
||||
|
||||
/** |
||||
* 子任务下载地址, |
||||
*/ |
||||
private List<String> mUrls = new ArrayList<>(); |
||||
|
||||
/** |
||||
* 子任务文件名 |
||||
*/ |
||||
private List<String> mSubNameTemp = new ArrayList<>(); |
||||
|
||||
HttpGroupDelegate(DownloadGroupTarget target, DGTaskWrapper wrapper) { |
||||
super(target, wrapper); |
||||
mUrls.addAll(wrapper.getEntity().getUrls()); |
||||
} |
||||
|
||||
@CheckResult |
||||
DownloadGroupTarget setGroupUrl(List<String> urls) { |
||||
mUrls.clear(); |
||||
mUrls.addAll(urls); |
||||
return getTarget(); |
||||
} |
||||
|
||||
/** |
||||
* 设置子任务文件名,该方法必须在{@link #setDirPath(String)}之后调用,否则不生效 |
||||
*/ |
||||
@CheckResult |
||||
DownloadGroupTarget setSubFileName(List<String> subTaskFileName) { |
||||
if (subTaskFileName == null || subTaskFileName.isEmpty()) { |
||||
ALog.e(TAG, "修改子任务的文件名失败:列表为null"); |
||||
return getTarget(); |
||||
} |
||||
if (subTaskFileName.size() != getTaskWrapper().getSubTaskWrapper().size()) { |
||||
ALog.e(TAG, "修改子任务的文件名失败:子任务文件名列表数量和子任务的数量不匹配"); |
||||
return getTarget(); |
||||
} |
||||
mSubNameTemp.clear(); |
||||
mSubNameTemp.addAll(subTaskFileName); |
||||
return getTarget(); |
||||
} |
||||
|
||||
/** |
||||
* 更新组合任务下载地址 |
||||
* |
||||
* @param urls 新的组合任务下载地址列表 |
||||
*/ |
||||
@CheckResult |
||||
DownloadGroupTarget updateUrls(List<String> urls) { |
||||
if (urls == null || urls.isEmpty()) { |
||||
throw new NullPointerException("下载地址列表为空"); |
||||
} |
||||
if (urls.size() != mUrls.size()) { |
||||
throw new IllegalArgumentException("新下载地址数量和旧下载地址数量不一致"); |
||||
} |
||||
mUrls.clear(); |
||||
mUrls.addAll(urls); |
||||
String newHash = CommonUtil.getMd5Code(urls); |
||||
setGroupHash(newHash); |
||||
getEntity().setGroupHash(newHash); |
||||
getEntity().update(); |
||||
if (getEntity().getSubEntities() != null && !getEntity().getSubEntities().isEmpty()) { |
||||
for (DownloadEntity de : getEntity().getSubEntities()) { |
||||
de.setGroupHash(newHash); |
||||
de.update(); |
||||
} |
||||
} |
||||
return getTarget(); |
||||
} |
||||
|
||||
@Override public boolean checkEntity() { |
||||
if (!checkDirPath()) { |
||||
return false; |
||||
} |
||||
|
||||
if (!checkSubName()) { |
||||
return false; |
||||
} |
||||
|
||||
if (!checkUrls()) { |
||||
return false; |
||||
} |
||||
|
||||
if (getTaskWrapper().getEntity().getFileSize() == 0) { |
||||
ALog.e(TAG, "组合任务必须设置文件文件大小"); |
||||
return false; |
||||
} |
||||
|
||||
if (getTaskWrapper().asHttp().getRequestEnum() == RequestEnum.POST) { |
||||
for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) { |
||||
subTask.asHttp().setRequestEnum(RequestEnum.POST); |
||||
} |
||||
} |
||||
|
||||
getEntity().save(); |
||||
|
||||
if (isNeedModifyPath()) { |
||||
reChangeDirPath(getDirPathTemp()); |
||||
} |
||||
|
||||
if (!mSubNameTemp.isEmpty()) { |
||||
updateSingleSubFileName(); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 更新所有改动的子任务文件名 |
||||
*/ |
||||
private void updateSingleSubFileName() { |
||||
List<DTaskWrapper> entities = getTaskWrapper().getSubTaskWrapper(); |
||||
int i = 0; |
||||
for (DTaskWrapper entity : entities) { |
||||
if (i < mSubNameTemp.size()) { |
||||
String newName = mSubNameTemp.get(i); |
||||
updateSingleSubFileName(entity, newName); |
||||
} |
||||
i++; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 检查urls是否合法,并删除不合法的子任务 |
||||
* |
||||
* @return {@code true} 合法 |
||||
*/ |
||||
private boolean checkUrls() { |
||||
if (mUrls.isEmpty()) { |
||||
ALog.e(TAG, "下载失败,子任务下载列表为null"); |
||||
return false; |
||||
} |
||||
Set<Integer> delItem = new HashSet<>(); |
||||
|
||||
int i = 0; |
||||
for (String url : mUrls) { |
||||
if (TextUtils.isEmpty(url)) { |
||||
ALog.e(TAG, "子任务url为null,即将删除该子任务。"); |
||||
delItem.add(i); |
||||
continue; |
||||
} else if (!url.startsWith("http")) { |
||||
//} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
|
||||
ALog.e(TAG, "子任务url【" + url + "】错误,即将删除该子任务。"); |
||||
delItem.add(i); |
||||
continue; |
||||
} |
||||
int index = url.indexOf("://"); |
||||
if (index == -1) { |
||||
ALog.e(TAG, "子任务url【" + url + "】不合法,即将删除该子任务。"); |
||||
delItem.add(i); |
||||
continue; |
||||
} |
||||
|
||||
i++; |
||||
} |
||||
|
||||
for (int index : delItem) { |
||||
mUrls.remove(index); |
||||
if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) { |
||||
mSubNameTemp.remove(index); |
||||
} |
||||
} |
||||
|
||||
getEntity().setGroupHash(CommonUtil.getMd5Code(mUrls)); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 更新单个子任务文件名 |
||||
*/ |
||||
private void updateSingleSubFileName(DTaskWrapper taskEntity, String newName) { |
||||
DownloadEntity entity = taskEntity.getEntity(); |
||||
if (!newName.equals(entity.getFileName())) { |
||||
String oldPath = getEntity().getDirPath() + "/" + entity.getFileName(); |
||||
String newPath = getEntity().getDirPath() + "/" + newName; |
||||
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=? or isComplete='true'", |
||||
newPath)) { |
||||
ALog.w(TAG, String.format("更新文件名失败,路径【%s】已存在或文件已下载", newPath)); |
||||
return; |
||||
} |
||||
|
||||
CommonUtil.modifyTaskRecord(oldPath, newPath); |
||||
entity.setDownloadPath(newPath); |
||||
entity.setFileName(newName); |
||||
entity.update(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 如果用户设置了子任务文件名,检查子任务文件名 |
||||
* |
||||
* @return {@code true} 合法 |
||||
*/ |
||||
private boolean checkSubName() { |
||||
if (mSubNameTemp == null || mSubNameTemp.isEmpty()) { |
||||
return true; |
||||
} |
||||
if (mUrls.size() != mSubNameTemp.size()) { |
||||
ALog.e(TAG, "子任务文件名必须和子任务数量一致"); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
/* |
||||
* 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; |
||||
|
||||
/** |
||||
* Created by lyy on 2019/4/5. |
||||
* 组合任务接收器功能接口 |
||||
*/ |
||||
public interface IGroupTarget { |
||||
|
||||
/** |
||||
* 获取实体 |
||||
*/ |
||||
AbsEntity getEntity(); |
||||
|
||||
/** |
||||
* 任务是否存在 |
||||
* |
||||
* @return {@code true}任务存在,{@code false} 任务不存在 |
||||
*/ |
||||
boolean taskExists(); |
||||
|
||||
/** |
||||
* 任务是否在执行 |
||||
* |
||||
* @return {@code true} 任务正在执行,{@code false} 任务没有执行 |
||||
*/ |
||||
boolean isRunning(); |
||||
|
||||
/** |
||||
* 检查实体是否合法 |
||||
* |
||||
* @return {@code true}合法 |
||||
*/ |
||||
boolean checkEntity(); |
||||
|
||||
/** |
||||
* 检查文件夹路径 |
||||
* 1、文件夹路径不能为空 |
||||
* 2、文件夹路径不能是文件 |
||||
* |
||||
* @return {@code true} 合法 |
||||
*/ |
||||
boolean checkDirPath(); |
||||
} |
After Width: | Height: | Size: 809 KiB |
Loading…
Reference in new issue