diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index 9f7316c5..59a744aa 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -97,7 +97,7 @@ import org.xml.sax.SAXException; } /** - * 设置Aria 日志级别 + * 设置Aria的日志级别 * * @param level {@link ALog#LOG_LEVEL_VERBOSE} */ @@ -106,20 +106,34 @@ import org.xml.sax.SAXException; } /** - * 设置上传任务的执行队列类型 + * 设置上传任务的执行队列类型,后续版本会删除该api,请使用: + *
+ *+ * Aria.get(this).getUploadConfig().setQueueMod(mod.tag) + *
+ * * * @param mod {@link QueueMod} + * @deprecated 后续版本会删除该api */ + @Deprecated public AriaManager setUploadQueueMod(QueueMod mod) { mUConfig.setQueueMod(mod.tag); return this; } /** - * 设置下载任务的执行队列类型 + * 设置下载任务的执行队列类型,后续版本会删除该api,请使用: + *+ *+ * Aria.get(this).getDownloadConfig().setQueueMod(mod.tag) + *
+ * * * @param mod {@link QueueMod} + * @deprecated 后续版本会删除该api */ + @Deprecated public AriaManager setDownloadQueueMod(QueueMod mod) { mDConfig.setQueueMod(mod.tag); return this; @@ -270,7 +284,8 @@ import org.xml.sax.SAXException; /** * 不允许在"onDestroy"、"finish"、"onStop"这三个方法中添加注册器 */ - private AbsReceiver checkTarget(String key, AbsReceiver receiver, Object obj, boolean needRmReceiver) { + private AbsReceiver checkTarget(String key, AbsReceiver receiver, Object obj, + boolean needRmReceiver) { StackTraceElement[] stack = Thread.currentThread().getStackTrace(); int i = 0; for (StackTraceElement e : stack) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java new file mode 100644 index 00000000..578c478f --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java @@ -0,0 +1,64 @@ +/* + * 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.delegate; + +import android.text.TextUtils; +import com.arialyy.aria.core.inf.AbsEntity; +import com.arialyy.aria.core.inf.AbsTaskEntity; +import com.arialyy.aria.core.inf.IFtpTarget; +import com.arialyy.aria.core.inf.ITarget; +import com.arialyy.aria.util.ALog; + +/** + * Created by laoyuyu on 2018/3/9. + * ftp 委托 + */ +public class FtpDelegate> + implements IFtpTarget { + private static final String TAG = "FtpDelegate"; + private ENTITY mEntity; + private TASK_ENTITY mTaskEntity; + + public FtpDelegate(TASK_ENTITY mTaskEntity) { + this.mTaskEntity = mTaskEntity; + mEntity = mTaskEntity.getEntity(); + } + + @Override public TARGET charSet(String charSet) { + if (TextUtils.isEmpty(charSet)) return (TARGET) this; + mTaskEntity.charSet = charSet; + return (TARGET) this; + } + + @Override public TARGET login(String userName, String password) { + return login(userName, password, null); + } + + @Override public TARGET login(String userName, String password, String account) { + if (TextUtils.isEmpty(userName)) { + ALog.e(TAG, "用户名不能为null"); + return (TARGET) this; + } else if (TextUtils.isEmpty(password)) { + ALog.e(TAG, "密码不能为null"); + return (TARGET) this; + } + mTaskEntity.urlEntity.needLogin = true; + mTaskEntity.urlEntity.user = userName; + mTaskEntity.urlEntity.password = password; + mTaskEntity.urlEntity.account = account; + return (TARGET) this; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java new file mode 100644 index 00000000..628b1501 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java @@ -0,0 +1,202 @@ +/* + * 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.delegate; + +import android.support.annotation.NonNull; +import android.text.TextUtils; +import com.arialyy.aria.core.common.RequestEnum; +import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.inf.AbsEntity; +import com.arialyy.aria.core.inf.AbsTaskEntity; +import com.arialyy.aria.core.inf.IHttpHeaderTarget; +import com.arialyy.aria.core.inf.ITarget; +import com.arialyy.aria.util.ALog; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * Created by laoyuyu on 2018/3/9. + * HTTP header参数设置委托类 + */ +public class HttpHeaderDelegate > + implements IHttpHeaderTarget { + private static final String TAG = "HttpHeaderDelegate"; + private ENTITY mEntity; + private TASK_ENTITY mTaskEntity; + + public HttpHeaderDelegate(TASK_ENTITY mTaskEntity) { + this.mTaskEntity = mTaskEntity; + mEntity = mTaskEntity.getEntity(); + } + + /** + * 给url请求添加Header数据 + * 如果新的header数据和数据保存的不一致,则更新数据库中对应的header数据 + * + * @param key header对应的key + * @param value header对应的value + */ + @Override + public TARGET addHeader(@NonNull String key, @NonNull String value) { + if (TextUtils.isEmpty(key)) { + ALog.w(TAG, "设置header失败,header对应的key不能为null"); + return (TARGET) this; + } else if (TextUtils.isEmpty(value)) { + ALog.w(TAG, "设置header失败,header对应的value不能为null"); + return (TARGET) this; + } + if (mTaskEntity.headers.get(key) == null) { + mTaskEntity.headers.put(key, value); + mTaskEntity.update(); + } else if (!mTaskEntity.headers.get(key).equals(value)) { + mTaskEntity.headers.put(key, value); + mTaskEntity.update(); + } + return (TARGET) this; + } + + /** + * 给url请求添加一组header数据 + * 如果新的header数据和数据保存的不一致,则更新数据库中对应的header数据 + * + * @param headers 一组http header数据 + */ + @Override + public TARGET addHeaders(@NonNull Map headers) { + if (headers.size() == 0) { + ALog.w(TAG, "设置header失败,map没有header数据"); + return (TARGET) this; + } + /* + 两个map比较逻辑 + 1、比对key是否相同 + 2、如果key相同,比对value是否相同 + 3、只有当上面两个步骤中key 和 value都相同时才能任务两个map数据一致 + */ + boolean mapEquals = false; + if (mTaskEntity.headers.size() == headers.size()) { + int i = 0; + Set keys = mTaskEntity.headers.keySet(); + for (String key : keys) { + if (headers.containsKey(key)) { + i++; + } else { + break; + } + } + if (i == mTaskEntity.headers.size()) { + int j = 0; + Collection values = mTaskEntity.headers.values(); + for (String value : values) { + if (headers.containsValue(value)) { + j++; + } else { + break; + } + } + if (j == mTaskEntity.headers.size()) { + mapEquals = true; + } + } + } + + if (!mapEquals) { + mTaskEntity.headers.clear(); + Set keys = headers.keySet(); + for (String key : keys) { + mTaskEntity.headers.put(key, headers.get(key)); + } + mTaskEntity.update(); + } + + return (TARGET) this; + } + + /** + * 设置请求类型,POST或GET,默认为在GET + * 只试用于HTTP请求 + * + * @param requestEnum {@link RequestEnum} + */ + @Override + public TARGET setRequestMode(RequestEnum requestEnum) { + mTaskEntity.requestEnum = requestEnum; + return (TARGET) this; + } + + /** + * 如果你的下载链接的header中含有md5码信息,那么你可以通过设置key,来获取从header获取该md5码信息。 + * key默认值为:Content-MD5 + * 获取md5信息:{@link DownloadEntity#getMd5Code()} + */ + @Override + public TARGET setHeaderMd5Key(String md5Key) { + if (TextUtils.isEmpty(md5Key)) return (TARGET) this; + mTaskEntity.md5Key = md5Key; + if (TextUtils.isEmpty(mTaskEntity.md5Key) || !mTaskEntity.md5Key.equals(md5Key)) { + mTaskEntity.update(); + } + return (TARGET) this; + } + + /** + * 如果你的文件长度是放在header中,那么你需要配置key来让Aria知道正确的文件长度 + * key默认值为:Content-Length + */ + @Override + public TARGET setHeaderContentLengthKey(String contentLength) { + if (TextUtils.isEmpty(contentLength)) return (TARGET) this; + mTaskEntity.contentLength = contentLength; + if (TextUtils.isEmpty(mTaskEntity.contentLength) || !mTaskEntity.contentLength.equals( + contentLength)) { + mTaskEntity.update(); + } + return (TARGET) this; + } + + /** + * 如果你的下载链接的header中含有文件描述信息,那么你可以通过设置key,来获取从header获取该文件描述信息。 + * key默认值为:Content-Disposition + * 获取文件描述信息:{@link DownloadEntity#getDisposition()} + */ + @Override + public TARGET setHeaderDispositionKey(String dispositionKey) { + if (TextUtils.isEmpty(dispositionKey)) return (TARGET) this; + mTaskEntity.dispositionKey = dispositionKey; + if (TextUtils.isEmpty(mTaskEntity.dispositionKey) || !mTaskEntity.dispositionKey.equals( + dispositionKey)) { + mTaskEntity.update(); + } + return (TARGET) this; + } + + /** + * 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息,你可以通过设置key来获取header中的文件名 + * key默认值为:attachment;filename + * 获取文件名信息:{@link DownloadEntity#getServerFileName()} + */ + @Override + public TARGET setHeaderDispositionFileKey(String dispositionFileKey) { + if (TextUtils.isEmpty(dispositionFileKey)) return (TARGET) this; + mTaskEntity.dispositionFileKey = dispositionFileKey; + if (TextUtils.isEmpty(mTaskEntity.dispositionFileKey) || !mTaskEntity.dispositionFileKey.equals( + dispositionFileKey)) { + mTaskEntity.update(); + } + return (TARGET) this; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java new file mode 100644 index 00000000..b9e33158 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java @@ -0,0 +1,110 @@ +/* + * 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.AriaManager; +import com.arialyy.aria.core.command.normal.NormalCmdFactory; +import com.arialyy.aria.core.inf.AbsEntity; +import com.arialyy.aria.core.inf.AbsTarget; +import com.arialyy.aria.core.inf.AbsTaskEntity; +import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; + +/** + * Created by lyy on 2017/2/28. + */ +abstract class AbsDownloadTarget + extends AbsTarget { + + static final int HTTP = 1; + static final int FTP = 2; + //HTTP任务组 + static final int GROUP_HTTP = 3; + //FTP文件夹 + static final int GROUP_FTP_DIR = 4; + + /** + * 设置的文件保存路径的临时变量 + */ + String mTempFilePath; + + /** + * 将任务设置为最高优先级任务,最高优先级任务有以下特点: + * 1、在下载队列中,有且只有一个最高优先级任务 + * 2、最高优先级任务会一直存在,直到用户手动暂停或任务完成 + * 3、任务调度器不会暂停最高优先级任务 + * 4、用户手动暂停或任务完成后,第二次重新执行该任务,该命令将失效 + * 5、如果下载队列中已经满了,则会停止队尾的任务,当高优先级任务完成后,该队尾任务将自动执行 + * 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务 + */ + protected void setHighestPriority() { + if (checkEntity()) { + AriaManager.getInstance(AriaManager.APP) + .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, + NormalCmdFactory.TASK_HIGHEST_PRIORITY, checkTaskType())) + .exe(); + } + } + + /** + * 添加任务 + */ + public void add() { + if (checkEntity()) { + AriaManager.getInstance(AriaManager.APP) + .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE, + checkTaskType())) + .exe(); + } + } + + /** + * 重定向后,新url的key,默认为location + */ + public void setRedirectUrlKey(String redirectUrlKey) { + if (TextUtils.isEmpty(redirectUrlKey)) { + ALog.e("AbsDownloadTarget", "重定向后,新url的key不能为null"); + return; + } + mTaskEntity.redirectUrlKey = redirectUrlKey; + } + + /** + * 获取任务文件大小 + * + * @return 文件大小 + */ + public long getFileSize() { + return getSize(); + } + + /** + * 获取单位转换后的文件大小 + * + * @return 文件大小{@code xxx mb} + */ + public String getConvertFileSize() { + return getConvertSize(); + } + + /** + * 设置target类型 + * + * @return {@link #HTTP}、{@link #FTP}、{@link #GROUP_HTTP}、{@link #GROUP_FTP_DIR} + */ + protected abstract int getTargetType(); +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java index e6ed4274..4ace4af0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java @@ -16,32 +16,29 @@ package com.arialyy.aria.core.download; import android.text.TextUtils; -import com.arialyy.aria.core.inf.AbsDownloadTarget; -import com.arialyy.aria.core.inf.AbsGroupTaskEntity; -import com.arialyy.aria.core.inf.AbsTarget; import com.arialyy.aria.core.manager.SubTaskManager; +import com.arialyy.aria.core.queue.DownloadGroupTaskQueue; +import com.arialyy.aria.core.queue.DownloadTaskQueue; import com.arialyy.aria.orm.DbEntity; -import com.arialyy.aria.util.CommonUtil; +import com.arialyy.aria.util.ALog; import java.io.File; -import java.util.ArrayList; import java.util.List; /** * Created by Aria.Lao on 2017/7/26. */ -abstract class BaseGroupTarget - extends AbsDownloadTarget { +abstract class BaseGroupTarget + extends AbsDownloadTarget { + private static final String TAG = "BaseGroupTarget"; - List mUrls = new ArrayList<>(); - String mGroupName; /** - * 子任务文件名 + * 组任务名 */ - private List mSubTaskFileName = new ArrayList<>(); + String mGroupName; /** - * 是否已经设置了文件路径 + * 文件夹临时路径 */ - private boolean isSetDirPathed = false; + private String mDirPathTemp; private SubTaskManager mSubTaskManager; @@ -67,6 +64,21 @@ abstract class BaseGroupTarget * - * @param groupDirPath 任务组保存文件夹路径 + * @param dirPath 任务组保存文件夹路径 */ - public TARGET setDownloadDirPath(String groupDirPath) { - if (TextUtils.isEmpty(groupDirPath)) { - throw new NullPointerException("任务组文件夹保存路径不能为null"); - } - - isSetDirPathed = true; - if (mEntity.getDirPath().equals(groupDirPath)) return (TARGET) this; - - File file = new File(groupDirPath); - if (file.exists() && file.isFile()) { - throw new IllegalArgumentException("路径不能为文件"); - } - if (!file.exists()) { - file.mkdirs(); - } - - mEntity.setDirPath(groupDirPath); - if (!TextUtils.isEmpty(mEntity.getDirPath())) { - reChangeDirPath(groupDirPath); - } else { - mEntity.setSubTasks(createSubTask()); - } - mEntity.update(); + public TARGET setDirPath(String dirPath) { + mDirPathTemp = dirPath; return (TARGET) this; } + @Override public boolean isRunning() { + DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey()); + return task != null && task.isRunning(); + } + /** * 改变任务组文件夹路径,修改文件夹路径会将子任务所有路径更换 * @@ -133,81 +129,38 @@ abstract class BaseGroupTarget subTaskFileName) { - - return setSubFileName(subTaskFileName); - } - - /** - * 设置子任务文件名,该方法必须在{@link #setDownloadDirPath(String)}之后调用,否则不生效 + * @return {@code true} 合法 */ - public TARGET setSubFileName(List subTaskFileName) { - if (subTaskFileName == null || subTaskFileName.isEmpty()) return (TARGET) this; - mSubTaskFileName.addAll(subTaskFileName); - if (mUrls.size() != subTaskFileName.size()) { - throw new IllegalArgumentException("下载链接数必须要和保存路径的数量一致"); + boolean checkDirPath() { + final String dirPath = mDirPathTemp; + if (TextUtils.isEmpty(dirPath)) { + ALog.e(TAG, "文件夹路径不能为null"); + return false; + } else if (!dirPath.startsWith("/")) { + ALog.e(TAG, "文件夹路径【" + dirPath + "】错误"); + return false; } - if (isSetDirPathed) { - List entities = mEntity.getSubTask(); - int i = 0; - for (DownloadEntity entity : entities) { - if (i < mSubTaskFileName.size()) { - String newName = mSubTaskFileName.get(i); - updateSubFileName(entity, newName); - } - i++; - } + File file = new File(dirPath); + if (file.isFile()) { + ALog.e(TAG, "路径【" + dirPath + "】是文件,请设置文件夹路径"); + return false; } - return (TARGET) this; - } - /** - * 更新子任务文件名 - */ - private void updateSubFileName(DownloadEntity entity, String newName) { - if (!newName.equals(entity.getFileName())) { - String oldPath = mEntity.getDirPath() + "/" + entity.getFileName(); - String newPath = mEntity.getDirPath() + "/" + newName; - File oldFile = new File(oldPath); - if (oldFile.exists()) { - oldFile.renameTo(new File(newPath)); + if (!mEntity.getDirPath().equals(dirPath)) { + if (!file.exists()) { + file.mkdirs(); } - CommonUtil.renameDownloadConfig(oldFile.getName(), newName); - DbEntity.exeSql( - "UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'"); - entity.setDownloadPath(newPath); - entity.setFileName(newName); - entity.update(); + mEntity.setDirPath(dirPath); + reChangeDirPath(dirPath); + mEntity.update(); } - } - /** - * 创建子任务 - */ - private List createSubTask() { - List list = new ArrayList<>(); - for (int i = 0, len = mUrls.size(); i < len; i++) { - DownloadEntity entity = new DownloadEntity(); - entity.setUrl(mUrls.get(i)); - String fileName = - mSubTaskFileName.isEmpty() ? createFileName(entity.getUrl()) : mSubTaskFileName.get(i); - entity.setDownloadPath(mEntity.getDirPath() + "/" + fileName); - entity.setGroupName(mGroupName); - entity.setGroupChild(true); - entity.setFileName(fileName); - entity.insert(); - list.add(entity); - } - return list; + return true; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java new file mode 100644 index 00000000..b488685e --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java @@ -0,0 +1,200 @@ +/* + * 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.manager.TEManager; +import com.arialyy.aria.core.queue.DownloadTaskQueue; +import com.arialyy.aria.orm.DbEntity; +import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; +import java.io.File; + +/** + * Created by Aria.Lao on 2017/7/26. + */ +abstract class BaseNormalTarget + extends AbsDownloadTarget { + + private static final String TAG = "BaseNormalTarget"; + /** + * 资源地址 + */ + protected String url; + + /** + * 通过实体初始化target + */ + void initTarget(DownloadEntity entity, String targetName, boolean refreshInfo) { + this.url = entity.getUrl(); + mTargetName = targetName; + mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url); + if (mTaskEntity == null) { + mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, entity); + } + mEntity = mTaskEntity.entity; + mTaskEntity.refreshInfo = refreshInfo; + } + + /** + * 通过地址初始化target + */ + void initTarget(String url, String targetName, boolean refreshInfo) { + this.url = url; + mTargetName = targetName; + mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url); + if (mTaskEntity == null) { + mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, url); + } + mEntity = mTaskEntity.entity; + mTaskEntity.refreshInfo = refreshInfo; + } + + /** + * 将任务设置为最高优先级任务,最高优先级任务有以下特点: + * 1、在下载队列中,有且只有一个最高优先级任务 + * 2、最高优先级任务会一直存在,直到用户手动暂停或任务完成 + * 3、任务调度器不会暂停最高优先级任务 + * 4、用户手动暂停或任务完成后,第二次重新执行该任务,该命令将失效 + * 5、如果下载队列中已经满了,则会停止队尾的任务,当高优先级任务完成后,该队尾任务将自动执行 + * 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务 + */ + @Override public void setHighestPriority() { + super.setHighestPriority(); + } + + /** + * 下载任务是否存在 + * + * @return {@code true}任务存在 + */ + @Override public boolean taskExists() { + return DownloadTaskQueue.getInstance().getTask(mEntity.getUrl()) != null; + } + + /** + * 获取下载实体 + */ + public DownloadEntity getDownloadEntity() { + return mEntity; + } + + /** + * 是否在下载,该api后续版本会删除 + * + * @deprecated {@link #isRunning()} + */ + @Deprecated + public boolean isDownloading() { + return isRunning(); + } + + /** + * 是否在下载 + * + * @return {@code true}任务正在下载 + */ + @Override public boolean isRunning() { + DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity.getKey()); + return task != null && task.isRunning(); + } + + /** + * 检查下载实体,判断实体是否合法 + * 合法标准为: + * 1、下载路径不为null,并且下载路径是正常的http或ftp路径 + * 2、保存路径不为null,并且保存路径是android文件系统路径 + * 3、保存路径不能重复 + * + * @return {@code true}合法 + */ + @Override + protected boolean checkEntity() { + return getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath(); + } + + /** + * 检查并设置普通任务的文件保存路径 + * + * @return {@code true}保存路径合法 + */ + private boolean checkFilePath() { + String filePath = mTempFilePath; + if (TextUtils.isEmpty(filePath)) { + ALog.e(TAG, "下载失败,文件保存路径为null"); + return false; + } else if (!filePath.startsWith("/")) { + ALog.e(TAG, "下载失败,文件保存路径【" + filePath + "】错误"); + return false; + } + File file = new File(filePath); + if (file.isDirectory()) { + if (getTargetType() == HTTP) { + ALog.e(TAG, "保存路径【" + filePath + "】不能为文件夹,路径需要是完整的文件路径,如:/mnt/sdcard/game.zip"); + return false; + } else if (getTargetType() == FTP) { + filePath += mEntity.getFileName(); + } + } + //设置文件保存路径,如果新文件路径和就文件路径不同,则修改路径 + if (!filePath.equals(mEntity.getDownloadPath())) { + if (!mTaskEntity.refreshInfo && DbEntity.checkDataExist(DownloadEntity.class, + "downloadPath=?", filePath)) { + ALog.e(TAG, "保存路径【" + filePath + "】已经被其它任务占用,请设置其它保存路径"); + return false; + } + File oldFile = new File(mEntity.getDownloadPath()); + File newFile = new File(filePath); + if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) { + mEntity.setDownloadPath(filePath); + mEntity.setFileName(newFile.getName()); + mTaskEntity.key = filePath; + mTaskEntity.update(); + CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName()); + } + } + return true; + } + + /** + * 检查普通任务的下载地址 + * + * @return {@code true}地址合法 + */ + private boolean checkUrl() { + final String url = mEntity.getUrl(); + if (TextUtils.isEmpty(url)) { + ALog.e(TAG, "下载失败,url为null"); + return false; + } else if (!url.startsWith("http") && !url.startsWith("ftp")) { + ALog.e(TAG, "下载失败,url【" + url + "】错误"); + return false; + } + int index = url.indexOf("://"); + if (index == -1) { + ALog.e(TAG, "下载失败,url【" + url + "】不合法"); + return false; + } + String temp = url.substring(index + 3, url.length()); + if (temp.contains("//")) { + temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); + ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); + mEntity.setUrl(temp); + mEntity.update(); + } + return true; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java index cb714c38..c6697a5e 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java @@ -34,7 +34,7 @@ public class DownloadGroupEntity extends AbsGroupEntity { /** * 任务组下载文件的文件夹地址 * - * @see DownloadGroupTarget#setDownloadDirPath(String) + * @see DownloadGroupTarget#setDirPath(String) */ private String dirPath = ""; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java index 9bd63dd7..903f8b7e 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java @@ -15,21 +15,34 @@ */ package com.arialyy.aria.core.download; -import com.arialyy.aria.core.inf.IEntity; +import android.text.TextUtils; import com.arialyy.aria.core.manager.TEManager; -import com.arialyy.aria.core.queue.DownloadGroupTaskQueue; +import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CommonUtil; +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; /** * Created by AriaL on 2017/6/29. * 下载任务组 */ -public class DownloadGroupTarget - extends BaseGroupTarget { +public class DownloadGroupTarget extends BaseGroupTarget { private final String TAG = "DownloadGroupTarget"; + /** + * 子任务下载地址, + */ + private List mUrls = new ArrayList<>(); + + /** + * 子任务文件名 + */ + private List mSubNameTemp = new ArrayList<>(); DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) { this.mTargetName = targetName; @@ -80,16 +93,190 @@ public class DownloadGroupTarget * 如果你是使用{@link DownloadReceiver#load(DownloadGroupEntity)}进行下载操作,那么你需要设置任务组的下载地址 */ public DownloadGroupTarget setGroupUrl(List urls) { - CheckUtil.checkDownloadUrls(urls); mUrls.clear(); mUrls.addAll(urls); - mEntity.setGroupName(CommonUtil.getMd5Code(urls)); - mEntity.update(); return this; } - @Override public boolean isRunning() { - DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey()); - return task != null && task.isRunning(); + /** + * 设置子任务文件名,该方法必须在{@link #setDirPath(String)}之后调用,否则不生效 + * + * @deprecated {@link #setSubFileName(List)} 请使用该api + */ + @Deprecated public DownloadGroupTarget setSubTaskFileName(List subTaskFileName) { + return setSubFileName(subTaskFileName); + } + + /** + * 设置子任务文件名,该方法必须在{@link #setDirPath(String)}之后调用,否则不生效 + */ + public DownloadGroupTarget setSubFileName(List subTaskFileName) { + if (subTaskFileName == null || subTaskFileName.isEmpty()) { + return this; + } + mSubNameTemp.clear(); + mSubNameTemp.addAll(subTaskFileName); + return this; + } + + /** + * 创建子任务 + */ + private List createSubTask() { + List list = new ArrayList<>(); + for (int i = 0, len = mUrls.size(); i < len; i++) { + DownloadEntity entity = new DownloadEntity(); + entity.setUrl(mUrls.get(i)); + String fileName = + mSubNameTemp.isEmpty() ? CommonUtil.createFileName(entity.getUrl()) : mSubNameTemp.get(i); + entity.setDownloadPath(mEntity.getDirPath() + "/" + fileName); + entity.setGroupName(mGroupName); + entity.setGroupChild(true); + entity.setFileName(fileName); + entity.insert(); + list.add(entity); + } + return list; + } + + @Override protected int getTargetType() { + return GROUP_HTTP; + } + + @Override protected boolean checkEntity() { + if (getTargetType() == GROUP_HTTP) { + if (!checkDirPath()) { + return false; + } + + if (!checkSubName()) { + return false; + } + + if (!checkUrls()) { + return false; + } + + //文件夹路径通过后,并且该实体没有子任务,则创建子任务 + if (mEntity.getSubTask() == null || mEntity.getSubTask().isEmpty()) { + mEntity.setSubTasks(createSubTask()); + mTaskEntity.update(); + } else { + updateSingleSubFileName(); + } + return true; + } + return false; + } + + /** + * 更新所有改动的子任务文件名 + */ + private void updateSingleSubFileName() { + List entities = mEntity.getSubTask(); + int i = 0; + for (DownloadEntity 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 delItem = new HashSet<>(); + + Map reSetUrl = new WeakHashMap<>(); + 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; + } + + String temp = url.substring(index + 3, url.length()); + if (temp.contains("//")) { + temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); + ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); + reSetUrl.put(i, temp); + } + i++; + } + + Set keys = reSetUrl.keySet(); + for (Integer index : keys) { + mUrls.set(index, reSetUrl.get(index)); + } + + for (int index : delItem) { + mUrls.remove(index); + if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) { + mSubNameTemp.remove(index); + } + } + + mEntity.setGroupName(CommonUtil.getMd5Code(mUrls)); + mEntity.update(); + + return true; + } + + /** + * 更新单个子任务文件名 + */ + private void updateSingleSubFileName(DownloadEntity entity, String newName) { + if (!newName.equals(entity.getFileName())) { + String oldPath = mEntity.getDirPath() + "/" + entity.getFileName(); + String newPath = mEntity.getDirPath() + "/" + newName; + File oldFile = new File(oldPath); + if (oldFile.exists()) { + oldFile.renameTo(new File(newPath)); + } + CommonUtil.renameDownloadConfig(oldFile.getName(), newName); + DbEntity.exeSql( + "UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'"); + 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; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java index 21ca515b..e4efccb6 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java @@ -27,7 +27,6 @@ import com.arialyy.aria.core.inf.AbsReceiver; import com.arialyy.aria.core.inf.AbsTarget; import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers; import com.arialyy.aria.core.scheduler.DownloadSchedulers; -import com.arialyy.aria.core.scheduler.ISchedulerListener; import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CommonUtil; @@ -41,7 +40,6 @@ import java.util.Set; */ public class DownloadReceiver extends AbsReceiver { private final String TAG = "DownloadReceiver"; - public ISchedulerListener listener; /** * 设置最大下载速度,单位:kb @@ -114,8 +112,18 @@ public class DownloadReceiver extends AbsReceiver { /** * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组 + * + * @param urls 人刷谁 */ + @Deprecated public DownloadGroupTarget load(List urls) { + return loadGroup(urls); + } + + /** + * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组 + */ + public DownloadGroupTarget loadGroup(List urls) { CheckUtil.checkDownloadUrls(urls); return new DownloadGroupTarget(urls, targetName); } @@ -170,12 +178,24 @@ public class DownloadReceiver extends AbsReceiver { } /** - * 使用任务组实体执行任务组的实体执行任务组的下载操作 + * 使用任务组实体执行任务组的实体执行任务组的下载操作,后续版本会删除该api * * @param groupEntity 如果加载的任务实体没有子项的下载地址, * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 + * @deprecated {@link #loadGroup(DownloadGroupEntity)} */ + @Deprecated public DownloadGroupTarget load(DownloadGroupEntity groupEntity) { + return loadGroup(groupEntity); + } + + /** + * 使用任务组实体执行任务组的实体执行任务组的下载操作 + * + * @param groupEntity 如果加载的任务实体没有子项的下载地址, + * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 + */ + public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) { return new DownloadGroupTarget(groupEntity, targetName); } @@ -232,7 +252,6 @@ public class DownloadReceiver extends AbsReceiver { @Override public void destroy() { targetName = null; - listener = null; } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java index 5a8b20ed..d29b6d79 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java @@ -16,35 +16,27 @@ package com.arialyy.aria.core.download; import android.support.annotation.NonNull; -import android.text.TextUtils; -import com.arialyy.aria.core.inf.AbsDownloadTarget; -import com.arialyy.aria.core.manager.TEManager; -import com.arialyy.aria.core.queue.DownloadTaskQueue; -import com.arialyy.aria.orm.DbEntity; -import com.arialyy.aria.util.CommonUtil; -import java.io.File; +import com.arialyy.aria.core.common.RequestEnum; +import com.arialyy.aria.core.delegate.HttpHeaderDelegate; +import com.arialyy.aria.core.inf.IHttpHeaderTarget; +import java.util.Map; /** * Created by lyy on 2016/12/5. * https://github.com/AriaLyy/Aria */ -public class DownloadTarget - extends AbsDownloadTarget { - protected String url; +public class DownloadTarget extends BaseNormalTarget + implements IHttpHeaderTarget { + private static final String TAG = "DownloadTarget"; + private HttpHeaderDelegate mDelegate; DownloadTarget(DownloadEntity entity, String targetName) { this(entity, targetName, false); } DownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) { - this.url = entity.getUrl(); - mTargetName = targetName; - mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url); - if (mTaskEntity == null) { - mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, entity); - } - mEntity = mTaskEntity.entity; - mTaskEntity.refreshInfo = refreshInfo; + initTarget(entity, targetName, refreshInfo); + initTHis(); } DownloadTarget(String url, String targetName) { @@ -52,14 +44,12 @@ public class DownloadTarget } DownloadTarget(String url, String targetName, boolean refreshInfo) { - this.url = url; - mTargetName = targetName; - mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url); - if (mTaskEntity == null) { - mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, url); - } - mEntity = mTaskEntity.entity; - mTaskEntity.refreshInfo = refreshInfo; + initTarget(url, targetName, refreshInfo); + initTHis(); + } + + private void initTHis() { + mDelegate = new HttpHeaderDelegate<>(mTaskEntity); } /** @@ -75,25 +65,15 @@ public class DownloadTarget } /** - * 将任务设置为最高优先级任务,最高优先级任务有以下特点: - * 1、在下载队列中,有且只有一个最高优先级任务 - * 2、最高优先级任务会一直存在,直到用户手动暂停或任务完成 - * 3、任务调度器不会暂停最高优先级任务 - * 4、用户手动暂停或任务完成后,第二次重新执行该任务,该命令将失效 - * 5、如果下载队列中已经满了,则会停止队尾的任务,当高优先级任务完成后,该队尾任务将自动执行 - * 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务 - */ - @Override public void setHighestPriority() { - super.setHighestPriority(); - } - - /** - * 下载任务是否存在 + * 设置文件存储路径 + * 该api后续版本会删除 * - * @return {@code true}任务存在 + * @param downloadPath 文件保存路径 + * @deprecated {@link #setFilePath(String)} 请使用这个api */ - @Override public boolean taskExists() { - return DownloadTaskQueue.getInstance().getTask(mEntity.getUrl()) != null; + @Deprecated + public DownloadTarget setDownloadPath(@NonNull String downloadPath) { + return setFilePath(downloadPath); } /** @@ -101,38 +81,13 @@ public class DownloadTarget * 如:原文件路径 /mnt/sdcard/test.zip * 如果需要将test.zip改为game.zip,只需要重新设置文件路径为:/mnt/sdcard/game.zip * - * @param downloadPath 路径必须为文件路径,不能为文件夹路径 + * @param filePath 路径必须为文件路径,不能为文件夹路径 */ - public DownloadTarget setDownloadPath(@NonNull String downloadPath) { - if (TextUtils.isEmpty(downloadPath)) { - throw new IllegalArgumentException("文件保持路径不能为null"); - } - File file = new File(downloadPath); - if (file.isDirectory()) { - throw new IllegalArgumentException("保存路径不能为文件夹,路径需要是完整的文件路径,如:/mnt/sdcard/game.zip"); - } - if (!downloadPath.equals(mEntity.getDownloadPath())) { - if (!mTaskEntity.refreshInfo && DbEntity.checkDataExist(DownloadEntity.class, - "downloadPath=?", downloadPath)) { - throw new IllegalArgumentException("保存路径【" + downloadPath + "】已经被其它任务占用,请设置其它保存路径"); - } - File oldFile = new File(mEntity.getDownloadPath()); - File newFile = new File(downloadPath); - if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) { - mEntity.setDownloadPath(downloadPath); - mEntity.setFileName(newFile.getName()); - mTaskEntity.key = downloadPath; - mTaskEntity.update(); - CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName()); - } - } + public DownloadTarget setFilePath(@NonNull String filePath) { + mTempFilePath = filePath; return this; } - public DownloadEntity getDownloadEntity() { - return mEntity; - } - /** * 从header中获取文件描述信息 */ @@ -140,17 +95,35 @@ public class DownloadTarget return mEntity.getDisposition(); } - /** - * 是否在下载 - * - * @deprecated {@link #isRunning()} - */ - public boolean isDownloading() { - return isRunning(); + @Override protected int getTargetType() { + return HTTP; + } + + @Override public DownloadTarget addHeader(@NonNull String key, @NonNull String value) { + return mDelegate.addHeader(key, value); + } + + @Override public DownloadTarget addHeaders(Map headers) { + return mDelegate.addHeaders(headers); + } + + @Override public DownloadTarget setRequestMode(RequestEnum requestEnum) { + return mDelegate.setRequestMode(requestEnum); + } + + @Override public DownloadTarget setHeaderMd5Key(String md5Key) { + return mDelegate.setHeaderMd5Key(md5Key); + } + + @Override public DownloadTarget setHeaderContentLengthKey(String contentLength) { + return mDelegate.setHeaderContentLengthKey(contentLength); + } + + @Override public DownloadTarget setHeaderDispositionKey(String dispositionKey) { + return mDelegate.setHeaderDispositionKey(dispositionKey); } - @Override public boolean isRunning() { - DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity.getKey()); - return task != null && task.isRunning(); + @Override public DownloadTarget setHeaderDispositionFileKey(String dispositionFileKey) { + return mDelegate.setHeaderDispositionFileKey(dispositionFileKey); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java index f7c51df7..ffeacb14 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java @@ -16,18 +16,20 @@ package com.arialyy.aria.core.download; import android.text.TextUtils; +import com.arialyy.aria.core.delegate.FtpDelegate; import com.arialyy.aria.core.inf.AbsTaskEntity; +import com.arialyy.aria.core.inf.IFtpTarget; import com.arialyy.aria.core.manager.TEManager; -import com.arialyy.aria.core.queue.DownloadGroupTaskQueue; import com.arialyy.aria.util.ALog; /** * Created by Aria.Lao on 2017/7/26. * ftp文件夹下载 */ -public class FtpDirDownloadTarget - extends BaseGroupTarget { +public class FtpDirDownloadTarget extends BaseGroupTarget implements + IFtpTarget { private final String TAG = "FtpDirDownloadTarget"; + private FtpDelegate mDelegate; FtpDirDownloadTarget(String url, String targetName) { mTargetName = targetName; @@ -42,51 +44,57 @@ public class FtpDirDownloadTarget } mTaskEntity.requestType = AbsTaskEntity.D_FTP_DIR; mEntity = mTaskEntity.entity; + + mDelegate = new FtpDelegate<>(mTaskEntity); } - /** - * 设置字符编码 - */ - public FtpDirDownloadTarget charSet(String charSet) { - if (TextUtils.isEmpty(charSet)) return this; - mTaskEntity.charSet = charSet; - return this; + @Override protected int getTargetType() { + return GROUP_FTP_DIR; } - /** - * ftp 用户登录信息 - * - * @param userName ftp用户名 - * @param password ftp用户密码 - */ - public FtpDirDownloadTarget login(String userName, String password) { - return login(userName, password, null); + @Override protected boolean checkEntity() { + return getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl(); } /** - * ftp 用户登录信息 + * 检查普通任务的下载地址 * - * @param userName ftp用户名 - * @param password ftp用户密码 - * @param account ftp账号 + * @return {@code true}地址合法 */ - public FtpDirDownloadTarget login(String userName, String password, String account) { - if (TextUtils.isEmpty(userName)) { - ALog.e(TAG, "用户名不能为null"); - return this; - } else if (TextUtils.isEmpty(password)) { - ALog.e(TAG, "密码不能为null"); - return this; + private boolean checkUrl() { + final String url = mGroupName; + if (TextUtils.isEmpty(url)) { + ALog.e(TAG, "下载失败,url为null"); + return false; + } else if (!url.startsWith("ftp")) { + ALog.e(TAG, "下载失败,url【" + url + "】错误"); + return false; } - mTaskEntity.urlEntity.needLogin = true; - mTaskEntity.urlEntity.user = userName; - mTaskEntity.urlEntity.password = password; - mTaskEntity.urlEntity.account = account; - return this; + int index = url.indexOf("://"); + if (index == -1) { + ALog.e(TAG, "下载失败,url【" + url + "】不合法"); + return false; + } + String temp = url.substring(index + 3, url.length()); + if (temp.contains("//")) { + temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); + ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); + mGroupName = temp; + mEntity.setGroupName(temp); + mEntity.update(); + } + return true; + } + + @Override public FtpDirDownloadTarget charSet(String charSet) { + return mDelegate.charSet(charSet); + } + + @Override public FtpDirDownloadTarget login(String userName, String password) { + return mDelegate.login(userName, password); } - @Override public boolean isRunning() { - DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey()); - return task != null && task.isRunning(); + @Override public FtpDirDownloadTarget login(String userName, String password, String account) { + return mDelegate.login(userName, password, account); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java index ccc18455..d9b7b54b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java @@ -16,21 +16,22 @@ package com.arialyy.aria.core.download; import android.support.annotation.NonNull; -import android.text.TextUtils; +import com.arialyy.aria.core.delegate.FtpDelegate; import com.arialyy.aria.core.inf.AbsTaskEntity; -import com.arialyy.aria.util.ALog; +import com.arialyy.aria.core.inf.IFtpTarget; import com.arialyy.aria.util.CommonUtil; -import java.io.File; /** * Created by lyy on 2016/12/5. * https://github.com/AriaLyy/Aria */ -public class FtpDownloadTarget extends DownloadTarget { +public class FtpDownloadTarget extends BaseNormalTarget + implements IFtpTarget { private final String TAG = "FtpDownloadTarget"; + private FtpDelegate mDelegate; FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) { - super(entity, targetName, refreshInfo); + initTarget(entity, targetName, refreshInfo); init(refreshInfo); } @@ -39,7 +40,7 @@ public class FtpDownloadTarget extends DownloadTarget { } FtpDownloadTarget(String url, String targetName, boolean refreshInfo) { - super(url, targetName); + initTarget(url, targetName, refreshInfo); init(refreshInfo); } @@ -49,6 +50,19 @@ public class FtpDownloadTarget extends DownloadTarget { mTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(url); mTaskEntity.refreshInfo = refreshInfo; mTaskEntity.requestType = AbsTaskEntity.D_FTP; + + mDelegate = new FtpDelegate<>(mTaskEntity); + } + + /** + * 设置文件保存文件夹路径 + * + * @param filePath 文件保存路径 + * @deprecated {@link #setFilePath(String)} 请使用这个api + */ + @Deprecated + public FtpDownloadTarget setDownloadPath(@NonNull String filePath) { + return setFilePath(filePath); } /** @@ -57,69 +71,26 @@ public class FtpDownloadTarget extends DownloadTarget { * 1、如果保存路径是该文件的保存路径,如:/mnt/sdcard/file.zip,则使用路径中的文件名file.zip * 2、如果保存路径是文件夹路径,如:/mnt/sdcard/,则使用FTP服务器该文件的文件名 * - * @param downloadPath 路径必须为文件路径,不能为文件夹路径 + * @param filePath 路径必须为文件路径,不能为文件夹路径 */ - @Override public FtpDownloadTarget setDownloadPath(@NonNull String downloadPath) { - if (TextUtils.isEmpty(downloadPath)) { - throw new IllegalArgumentException("文件保持路径不能为null"); - } - File file = new File(downloadPath); - if (file.isDirectory()) { - downloadPath += mEntity.getFileName(); - } - if (!downloadPath.equals(mEntity.getDownloadPath())) { - File oldFile = new File(mEntity.getDownloadPath()); - File newFile = new File(downloadPath); - if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) { - mEntity.setDownloadPath(downloadPath); - mEntity.setFileName(newFile.getName()); - mTaskEntity.key = downloadPath; - mEntity.update(); - mTaskEntity.update(); - CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName()); - } - } + public FtpDownloadTarget setFilePath(@NonNull String filePath) { + mTempFilePath = filePath; return this; } - /** - * 设置字符编码 - */ - public FtpDownloadTarget charSet(String charSet) { - if (TextUtils.isEmpty(charSet)) return this; - mTaskEntity.charSet = charSet; - return this; + @Override protected int getTargetType() { + return FTP; } - /** - * ftp 用户登录信息 - * - * @param userName ftp用户名 - * @param password ftp用户密码 - */ - public FtpDownloadTarget login(String userName, String password) { - return login(userName, password, null); + @Override public FtpDownloadTarget charSet(String charSet) { + return mDelegate.charSet(charSet); } - /** - * ftp 用户登录信息 - * - * @param userName ftp用户名 - * @param password ftp用户密码 - * @param account ftp账号 - */ - public FtpDownloadTarget login(String userName, String password, String account) { - if (TextUtils.isEmpty(userName)) { - ALog.e(TAG, "用户名不能为null"); - return this; - } else if (TextUtils.isEmpty(password)) { - ALog.e(TAG, "密码不能为null"); - return this; - } - mTaskEntity.urlEntity.needLogin = true; - mTaskEntity.urlEntity.user = userName; - mTaskEntity.urlEntity.password = password; - mTaskEntity.urlEntity.account = account; - return this; + @Override public FtpDownloadTarget login(String userName, String password) { + return mDelegate.login(userName, password); + } + + @Override public FtpDownloadTarget login(String userName, String password, String account) { + return mDelegate.login(userName, password, account); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java deleted file mode 100644 index f5909a1f..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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; - -import android.text.TextUtils; -import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.command.normal.NormalCmdFactory; -import com.arialyy.aria.core.download.DownloadEntity; -import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.CommonUtil; - -/** - * Created by lyy on 2017/2/28. - */ -public abstract class AbsDownloadTarget - extends AbsTarget { - - /** - * 如果你的下载链接的header中含有md5码信息,那么你可以通过设置key,来获取从header获取该md5码信息。 - * key默认值为:Content-MD5 - * 获取md5信息:{@link DownloadEntity#getMd5Code()} - */ - public TARGET setHeaderMd5Key(String md5Key) { - if (TextUtils.isEmpty(md5Key)) return (TARGET) this; - mTaskEntity.md5Key = md5Key; - if (TextUtils.isEmpty(mTaskEntity.md5Key) || !mTaskEntity.md5Key.equals(md5Key)) { - mTaskEntity.update(); - } - return (TARGET) this; - } - - /** - * 如果你的文件长度是放在header中,那么你需要配置key来让Aria知道正确的文件长度 - * key默认值为:Content-Length - */ - public TARGET setHeaderContentLengthKey(String contentLength) { - if (TextUtils.isEmpty(contentLength)) return (TARGET) this; - mTaskEntity.contentLength = contentLength; - if (TextUtils.isEmpty(mTaskEntity.contentLength) || !mTaskEntity.contentLength.equals( - contentLength)) { - mTaskEntity.update(); - } - return (TARGET) this; - } - - /** - * 如果你的下载链接的header中含有文件描述信息,那么你可以通过设置key,来获取从header获取该文件描述信息。 - * key默认值为:Content-Disposition - * 获取文件描述信息:{@link DownloadEntity#getDisposition()} - */ - public TARGET setHeaderDispositionKey(String dispositionKey) { - if (TextUtils.isEmpty(dispositionKey)) return (TARGET) this; - mTaskEntity.dispositionKey = dispositionKey; - if (TextUtils.isEmpty(mTaskEntity.dispositionKey) || !mTaskEntity.dispositionKey.equals( - dispositionKey)) { - mTaskEntity.save(); - } - return (TARGET) this; - } - - /** - * 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息,你可以通过设置key来获取header中的文件名 - * key默认值为:attachment;filename - * 获取文件名信息:{@link DownloadEntity#getServerFileName()} - */ - public TARGET setHeaderDispositionFileKey(String dispositionFileKey) { - if (TextUtils.isEmpty(dispositionFileKey)) return (TARGET) this; - mTaskEntity.dispositionFileKey = dispositionFileKey; - if (TextUtils.isEmpty(mTaskEntity.dispositionFileKey) || !mTaskEntity.dispositionFileKey.equals( - dispositionFileKey)) { - mTaskEntity.save(); - } - return (TARGET) this; - } - - /** - * 将任务设置为最高优先级任务,最高优先级任务有以下特点: - * 1、在下载队列中,有且只有一个最高优先级任务 - * 2、最高优先级任务会一直存在,直到用户手动暂停或任务完成 - * 3、任务调度器不会暂停最高优先级任务 - * 4、用户手动暂停或任务完成后,第二次重新执行该任务,该命令将失效 - * 5、如果下载队列中已经满了,则会停止队尾的任务,当高优先级任务完成后,该队尾任务将自动执行 - * 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务 - */ - protected void setHighestPriority() { - AriaManager.getInstance(AriaManager.APP) - .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, - NormalCmdFactory.TASK_HIGHEST_PRIORITY, checkTaskType())) - .exe(); - } - - /** - * 重定向后,新url的key,默认为location - */ - public void setRedirectUrlKey(String redirectUrlKey) { - if (TextUtils.isEmpty(redirectUrlKey)) { - ALog.e("AbsDownloadTarget", "重定向后,新url的key不能为null"); - return; - } - mTaskEntity.redirectUrlKey = redirectUrlKey; - } - - /** - * 获取任务文件大小 - * - * @return 文件大小 - */ - public long getFileSize() { - return getSize(); - } - - /** - * 获取单位转换后的文件大小 - * - * @return 文件大小{@code xxx mb} - */ - public String getConvertFileSize() { - return getConvertSize(); - } - - /** - * 添加任务 - */ - public void add() { - AriaManager.getInstance(AriaManager.APP) - .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE, - checkTaskType())) - .exe(); - } - - /** - * 重新下载 - */ - public void reStart() { - cancel(); - start(); - } -} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java index 6e2d69c4..742f4af6 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java @@ -15,13 +15,11 @@ */ package com.arialyy.aria.core.inf; -import android.support.annotation.NonNull; import android.text.TextUtils; import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.command.ICmd; import com.arialyy.aria.core.command.normal.CancelCmd; import com.arialyy.aria.core.command.normal.NormalCmdFactory; -import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.manager.TEManager; @@ -30,8 +28,6 @@ import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.Set; /** * Created by AriaL on 2017/7/3. @@ -65,27 +61,12 @@ public abstract class AbsTarget headers) { - return addHeaders(headers, false); - } - - /** - * 给url请求添加头部 - * - * @param refreshHeader 更新数据库中保存的头部信息 - */ - public TARGET addHeaders(Map headers, boolean refreshHeader) { - if (headers != null && headers.size() > 0) { - Set keys = headers.keySet(); - for (String key : keys) { - mTaskEntity.headers.put(key, headers.get(key)); - } - } - if (refreshHeader) { - mTaskEntity.update(); - } - return (TARGET) this; - } - - /** - * 设置请求类型,POST或GET,默认为在GET - * 只试用于HTTP请求 + * 检查实体是否合法 * - * @param requestEnum {@link RequestEnum} + * @return {@code true} 合法 */ - public TARGET setRequestMode(RequestEnum requestEnum) { - mTaskEntity.requestEnum = requestEnum; - return (TARGET) this; - } - - /** - * 开始任务 - */ - @Override public void start() { - AriaManager.getInstance(AriaManager.APP) - .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START, - checkTaskType())) - .exe(); - } + protected abstract boolean checkEntity(); protected int checkTaskType() { int taskType = 0; @@ -238,53 +156,76 @@ public abstract class AbsTarget cmds = new ArrayList<>(); - int taskType = checkTaskType(); - cmds.add( - CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP, taskType)); - cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START, - taskType)); - AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe(); + if (checkEntity()) { + List cmds = new ArrayList<>(); + int taskType = checkTaskType(); + cmds.add( + CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP, + taskType)); + cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START, + taskType)); + AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe(); + } } /** @@ -294,35 +235,23 @@ public abstract class AbsTarget 0) { - tempUrl = url.substring(0, end); - int tempEnd = tempUrl.lastIndexOf("/"); - if (tempEnd > 0) { - fileName = tempUrl.substring(tempEnd + 1, tempUrl.length()); - } - } else { - int tempEnd = url.lastIndexOf("/"); - if (tempEnd > 0) { - fileName = url.substring(tempEnd + 1, url.length()); - } - } - if (TextUtils.isEmpty(fileName)) { - fileName = CommonUtil.keyToHashKey(url); + public void reStart() { + if (checkEntity()) { + cancel(); + start(); } - return fileName; } + + } diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java deleted file mode 100644 index be6541f1..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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; - -import android.support.annotation.NonNull; -import com.arialyy.aria.core.queue.UploadTaskQueue; -import com.arialyy.aria.core.upload.UploadEntity; -import com.arialyy.aria.core.upload.UploadTask; -import com.arialyy.aria.core.upload.UploadTaskEntity; -import com.arialyy.aria.util.CheckUtil; - -/** - * Created by AriaL on 2017/6/29. - * 任务组超类 - */ -public abstract class AbsUploadTarget - extends AbsTarget { - - /** - * 设置上传路径 - * - * @param uploadUrl 上传路径 - */ - public TARGET setUploadUrl(@NonNull String uploadUrl) { - uploadUrl = CheckUtil.checkUrl(uploadUrl); - if (mEntity.getUrl().equals(uploadUrl)) return (TARGET) this; - mEntity.setUrl(uploadUrl); - mEntity.update(); - return (TARGET) this; - } - - /** - * 下载任务是否存在 - */ - @Override public boolean taskExists() { - return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null; - } - - /** - * 是否在下载 - * - * @deprecated {@link #isRunning()} - */ - public boolean isUploading() { - return isRunning(); - } - - @Override public boolean isRunning() { - UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity.getKey()); - return task != null && task.isRunning(); - } -} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java new file mode 100644 index 00000000..5f5a68fd --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java @@ -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.inf; + +/** + * Created by laoyuyu on 2018/3/9. + */ +public interface IFtpTarget { + /** + * 设置字符编码 + */ + TARGET charSet(String charSet); + + /** + * ftp 用户登录信。 + * 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)} + * + * @param userName ftp用户名 + * @param password ftp用户密码 + */ + TARGET login(String userName, String password); + + /** + * ftp 用户登录信息 + * 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)} + * + * @param userName ftp用户名 + * @param password ftp用户密码 + * @param account ftp账号 + */ + TARGET login(String userName, String password, String account); +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java new file mode 100644 index 00000000..8cd41def --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java @@ -0,0 +1,79 @@ +/* + * 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; + +import android.support.annotation.NonNull; +import com.arialyy.aria.core.common.RequestEnum; +import com.arialyy.aria.core.download.DownloadEntity; +import java.util.Map; + +/** + * Created by laoyuyu on 2018/3/9. + * HTTP Header功能接口 + */ +public interface IHttpHeaderTarget { + + /** + * 给url请求添加Header数据 + * 如果新的header数据和数据保存的不一致,则更新数据库中对应的header数据 + * + * @param key header对应的key + * @param value header对应的value + */ + TARGET addHeader(@NonNull String key, @NonNull String value); + + /** + * 给url请求添加一组header数据 + * 如果新的header数据和数据保存的不一致,则更新数据库中对应的header数据 + * + * @param headers 一组http header数据 + */ + TARGET addHeaders(Map headers); + + /** + * 设置HTTP请求类型 + * + * @param requestEnum {@link RequestEnum} + */ + TARGET setRequestMode(RequestEnum requestEnum); + + /** + * 如果你的下载链接的header中含有md5码信息,那么你可以通过设置key,来获取从header获取该md5码信息。 + * key默认值为:Content-MD5 + * 获取md5信息:{@link DownloadEntity#getMd5Code()} + */ + TARGET setHeaderMd5Key(String md5Key); + + /** + * 如果你的文件长度是放在header中,那么你需要配置key来让Aria知道正确的文件长度 + * key默认值为:Content-Length + */ + TARGET setHeaderContentLengthKey(String contentLength); + + /** + * 如果你的下载链接的header中含有文件描述信息,那么你可以通过设置key,来获取从header获取该文件描述信息。 + * key默认值为:Content-Disposition + * 获取文件描述信息:{@link DownloadEntity#getDisposition()} + */ + TARGET setHeaderDispositionKey(String dispositionKey); + + /** + * 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息,你可以通过设置key来获取header中的文件名 + * key默认值为:attachment;filename + * 获取文件名信息:{@link DownloadEntity#getServerFileName()} + */ + TARGET setHeaderDispositionFileKey(String dispositionFileKey); +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java index 527e8078..21149e0f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java @@ -15,53 +15,51 @@ */ package com.arialyy.aria.core.inf; -import android.support.annotation.NonNull; -import com.arialyy.aria.core.common.RequestEnum; -import java.util.Map; - /** * Created by AriaL on 2017/6/29. */ public interface ITarget { + /** - * 任务文件大小 + * 获取任务状态 + * + * @return {@link IEntity} */ - long getSize(); + int getTaskState(); /** - * 转换后的大小 + * 任务是否在执行 + * + * @return {@code true} 任务正在执行 */ - String getConvertSize(); + boolean isRunning(); /** - * 获取任务进度百分比 + * 任务是否存在 + * + * @return {@code true} 任务存在 */ - int getPercent(); + boolean taskExists(); /** - * 获取任务进度,如果任务存在,则返回当前进度 + * 任务文件大小 */ - long getCurrentProgress(); + long getSize(); /** - * 给url请求添加头部 - * - * @param key 头部key - * @param header 头部value + * 转换后的大小 */ - TARGET addHeader(@NonNull String key, @NonNull String header) ; + String getConvertSize(); /** - * 给url请求添加头部 + * 获取任务进度百分比 */ - TARGET addHeaders(Map headers); + int getPercent(); /** - * 设置请求类型 - * - * @param requestEnum {@link RequestEnum} + * 获取任务进度,如果任务存在,则返回当前进度 */ - TARGET setRequestMode(RequestEnum requestEnum); + long getCurrentProgress(); /** * 开始下载 @@ -82,5 +80,4 @@ public interface ITarget { * 取消下载 */ void cancel(); - } diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java index b8c02a25..2c90fc26 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java @@ -150,10 +150,10 @@ abstract class AbsTaskQueue + extends AbsTarget { + +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java new file mode 100644 index 00000000..9a2a31b4 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java @@ -0,0 +1,139 @@ +/* + * 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.upload; + +import android.support.annotation.NonNull; +import android.text.TextUtils; +import com.arialyy.aria.core.manager.TEManager; +import com.arialyy.aria.core.queue.UploadTaskQueue; +import com.arialyy.aria.util.ALog; +import java.io.File; + +/** + * Created by AriaL on 2018/3/9. + */ +abstract class BaseNormalTarget + extends AbsUploadTarget { + private static final String TAG = "BaseNormalTarget"; + + protected void initTarget(String filePath) { + mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, filePath); + if (mTaskEntity == null) { + mTaskEntity = TEManager.getInstance().createTEntity(UploadTaskEntity.class, filePath); + } + mEntity = mTaskEntity.entity; + File file = new File(filePath); + mEntity.setFileName(file.getName()); + mEntity.setFileSize(file.length()); + } + + /** + * 设置上传路径 + * + * @param uploadUrl 上传路径 + */ + public abstract TARGET setUploadUrl(@NonNull String uploadUrl); + + /** + * 上传任务是否存在 + * + * @return {@code true}存在 + */ + @Override public boolean taskExists() { + return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null; + } + + /** + * 是否在上传 + * + * @deprecated {@link #isRunning()} + */ + public boolean isUploading() { + return isRunning(); + } + + @Override public boolean isRunning() { + UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity.getKey()); + return task != null && task.isRunning(); + } + + @Override protected boolean checkEntity() { + return checkUrl() && checkFilePath(); + } + + /** + * 检查上传文件路径是否合法 + * + * @return {@code true} 合法 + */ + private boolean checkFilePath() { + String filePath = mEntity.getFilePath(); + if (TextUtils.isEmpty(filePath)) { + ALog.e(TAG, "上传失败,文件路径为null"); + return false; + } else if (!filePath.startsWith("/")) { + ALog.e(TAG, "上传失败,文件路径【" + filePath + "】不合法"); + return false; + } + + File file = new File(mEntity.getFilePath()); + if (!file.exists()) { + ALog.e(TAG, "上传失败,文件【" + filePath + "】不存在"); + return false; + } + if (file.isDirectory()) { + ALog.e(TAG, "上传失败,文件【" + filePath + "】不能死文件夹"); + return false; + } + + if (filePath.contains("//")) { + filePath = filePath.replaceAll("//", "/"); + ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + filePath); + mEntity.setFilePath(filePath); + mEntity.update(); + } + return true; + } + + /** + * 检查普通任务的下载地址 + * + * @return {@code true}地址合法 + */ + private boolean checkUrl() { + final String url = mEntity.getUrl(); + if (TextUtils.isEmpty(url)) { + ALog.e(TAG, "上传失败,url为null"); + return false; + } else if (!url.startsWith("http") && !url.startsWith("ftp")) { + ALog.e(TAG, "上传失败,url【" + url + "】错误"); + return false; + } + int index = url.indexOf("://"); + if (index == -1) { + ALog.e(TAG, "上传失败,url【" + url + "】不合法"); + return false; + } + String temp = url.substring(index + 3, url.length()); + if (temp.contains("//")) { + temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); + ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); + mEntity.setUrl(temp); + mEntity.update(); + } + return true; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java index 7bcccac5..8892c8b8 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java @@ -16,13 +16,12 @@ package com.arialyy.aria.core.upload; import android.support.annotation.NonNull; -import android.text.TextUtils; import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.command.normal.NormalCmdFactory; +import com.arialyy.aria.core.delegate.FtpDelegate; import com.arialyy.aria.core.inf.AbsTaskEntity; -import com.arialyy.aria.core.inf.AbsUploadTarget; +import com.arialyy.aria.core.inf.IFtpTarget; import com.arialyy.aria.core.manager.TEManager; -import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CommonUtil; import java.io.File; @@ -31,9 +30,10 @@ import java.io.File; * Created by Aria.Lao on 2017/7/27. * ftp单任务上传 */ -public class FtpUploadTarget - extends AbsUploadTarget { +public class FtpUploadTarget extends BaseNormalTarget + implements IFtpTarget { private final String TAG = "FtpUploadTarget"; + private FtpDelegate mDelegate; FtpUploadTarget(String filePath, String targetName) { this.mTargetName = targetName; @@ -41,15 +41,9 @@ public class FtpUploadTarget } private void initTask(String filePath) { - mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, filePath); - if (mTaskEntity == null) { - mTaskEntity = TEManager.getInstance().createTEntity(UploadTaskEntity.class, filePath); - } - mEntity = mTaskEntity.entity; - File file = new File(filePath); - mEntity.setFileName(file.getName()); - mEntity.setFileSize(file.length()); + initTarget(filePath); mTaskEntity.requestType = AbsTaskEntity.U_FTP; + mDelegate = new FtpDelegate<>(mTaskEntity); } /** @@ -57,6 +51,7 @@ public class FtpUploadTarget * * @param uploadUrl 上传路径 */ + @Override public FtpUploadTarget setUploadUrl(@NonNull String uploadUrl) { uploadUrl = CheckUtil.checkUrl(uploadUrl); if (!uploadUrl.endsWith("/")) { @@ -70,55 +65,26 @@ public class FtpUploadTarget } /** - * 设置字符编码 + * 添加任务 */ - public FtpUploadTarget charSet(String charSet) { - if (TextUtils.isEmpty(charSet)) return this; - mTaskEntity.charSet = charSet; - return this; + public void add() { + if (checkEntity()) { + AriaManager.getInstance(AriaManager.APP) + .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE, + checkTaskType())) + .exe(); + } } - /** - * ftp 用户登录信。 - * 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)} - * - * @param userName ftp用户名 - * @param password ftp用户密码 - */ - public FtpUploadTarget login(String userName, String password) { - return login(userName, password, null); + @Override public FtpUploadTarget charSet(String charSet) { + return mDelegate.charSet(charSet); } - /** - * ftp 用户登录信息 - * 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)} - * - * @param userName ftp用户名 - * @param password ftp用户密码 - * @param account ftp账号 - */ - public FtpUploadTarget login(String userName, String password, String account) { - if (TextUtils.isEmpty(userName)) { - ALog.e(TAG, "用户名不能为null"); - return this; - } else if (TextUtils.isEmpty(password)) { - ALog.e(TAG, "密码不能为null"); - return this; - } - mTaskEntity.urlEntity.needLogin = true; - mTaskEntity.urlEntity.user = userName; - mTaskEntity.urlEntity.password = password; - mTaskEntity.urlEntity.account = account; - return this; + @Override public FtpUploadTarget login(String userName, String password) { + return mDelegate.login(userName, password); } - /** - * 添加任务 - */ - public void add() { - AriaManager.getInstance(AriaManager.APP) - .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE, - checkTaskType())) - .exe(); + @Override public FtpUploadTarget login(String userName, String password, String account) { + return mDelegate.login(userName, password, account); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java index a86c2219..3d9b6040 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java @@ -36,7 +36,6 @@ import java.util.Set; */ public class UploadReceiver extends AbsReceiver { private static final String TAG = "UploadReceiver"; - public ISchedulerListener listener; /** * 加载HTTP单文件上传任务 @@ -104,7 +103,6 @@ public class UploadReceiver extends AbsReceiver { @Override public void destroy() { targetName = null; - listener = null; } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java index b3b49956..eeacbfd9 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java @@ -16,16 +16,21 @@ package com.arialyy.aria.core.upload; import android.support.annotation.NonNull; -import com.arialyy.aria.core.inf.AbsUploadTarget; -import com.arialyy.aria.core.manager.TEManager; +import com.arialyy.aria.core.common.RequestEnum; +import com.arialyy.aria.core.delegate.HttpHeaderDelegate; import com.arialyy.aria.core.inf.AbsTaskEntity; -import java.io.File; +import com.arialyy.aria.core.inf.IHttpHeaderTarget; +import com.arialyy.aria.util.CheckUtil; +import java.util.Map; /** * Created by lyy on 2017/2/28. - * http 当文件上传 + * http 单文件上传 */ -public class UploadTarget extends AbsUploadTarget { +public class UploadTarget extends BaseNormalTarget + implements IHttpHeaderTarget { + private static final String TAG = "UploadTarget"; + private HttpHeaderDelegate mDelegate; UploadTarget(String filePath, String targetName) { this.mTargetName = targetName; @@ -33,17 +38,22 @@ public class UploadTarget extends AbsUploadTarget (mTaskEntity); + } + + @Override public UploadTarget setUploadUrl(@NonNull String uploadUrl) { + uploadUrl = CheckUtil.checkUrl(uploadUrl); + if (mEntity.getUrl().equals(uploadUrl)) { + return this; + } + mEntity.setUrl(uploadUrl); + mEntity.update(); + return this; } /** @@ -73,4 +83,32 @@ public class UploadTarget extends AbsUploadTarget headers) { + return mDelegate.addHeaders(headers); + } + + @Override public UploadTarget setRequestMode(RequestEnum requestEnum) { + return mDelegate.setRequestMode(requestEnum); + } + + @Override public UploadTarget setHeaderMd5Key(String md5Key) { + return mDelegate.setHeaderMd5Key(md5Key); + } + + @Override public UploadTarget setHeaderContentLengthKey(String contentLength) { + return mDelegate.setHeaderContentLengthKey(contentLength); + } + + @Override public UploadTarget setHeaderDispositionKey(String dispositionKey) { + return mDelegate.setHeaderDispositionKey(dispositionKey); + } + + @Override public UploadTarget setHeaderDispositionFileKey(String dispositionFileKey) { + return mDelegate.setHeaderDispositionFileKey(dispositionFileKey); + } } diff --git a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java index 103a5153..1f67935c 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java @@ -109,6 +109,34 @@ public class CheckUtil { return url; } + ///** + // * 检查普通任务的下载地址 + // * + // * @return {@code true}地址合法 + // */ + //public static boolean checkUrl(DownloadEntity entity, String url) { + // if (TextUtils.isEmpty(url)) { + // ALog.e(TAG, "下载失败,url为null"); + // return false; + // } else if (!url.startsWith("http") && !url.startsWith("ftp")) { + // ALog.e(TAG, "下载失败,url【" + url + "】错误"); + // return false; + // } + // int index = url.indexOf("://"); + // if (index == -1) { + // ALog.e(TAG, "下载失败,url【" + url + "】不合法"); + // return false; + // } + // String temp = url.substring(index + 3, url.length()); + // if (temp.contains("//")) { + // temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); + // ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); + // entity.setUrl(temp); + // entity.update(); + // } + // return true; + //} + /** * 检测下载链接组是否为null */ diff --git a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java index ee215f6f..f52ef139 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -73,6 +73,32 @@ import java.util.regex.Pattern; public class CommonUtil { private static final String TAG = "CommonUtil"; + /** + * 创建文件名,如果url链接有后缀名,则使用url中的后缀名 + * + * @return url 的 hashKey + */ + public static String createFileName(String url) { + int end = url.indexOf("?"); + String tempUrl, fileName = ""; + if (end > 0) { + tempUrl = url.substring(0, end); + int tempEnd = tempUrl.lastIndexOf("/"); + if (tempEnd > 0) { + fileName = tempUrl.substring(tempEnd + 1, tempUrl.length()); + } + } else { + int tempEnd = url.lastIndexOf("/"); + if (tempEnd > 0) { + fileName = url.substring(tempEnd + 1, url.length()); + } + } + if (TextUtils.isEmpty(fileName)) { + fileName = CommonUtil.keyToHashKey(url); + } + return fileName; + } + /** * 分割获取url,协议,ip/域名,端口,内容 * diff --git a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java index 75397bd1..4762fe1f 100644 --- a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java @@ -80,7 +80,7 @@ public class DownloadGroupActivity extends BaseActivity