HttpDBlockInterceptor

v4
laoyuyu 2 years ago
parent 4a74e457d5
commit 9a2976827f
  1. 6
      Aria/src/main/java/com/arialyy/aria/core/common/FtpOption.java
  2. 6
      Aria/src/main/java/com/arialyy/aria/core/common/HttpOption.java
  3. 6
      Aria/src/main/java/com/arialyy/aria/core/download/CheckDEntityUtil.java
  4. 4
      Aria/src/main/java/com/arialyy/aria/core/download/CheckDGEntityUtil.java
  5. 4
      Aria/src/main/java/com/arialyy/aria/core/download/CheckFtpDirEntityUtil.java
  6. 16
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  7. 4
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveOption.java
  8. 8
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8Option.java
  9. 4
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8VodOption.java
  10. 6
      Aria/src/main/java/com/arialyy/aria/core/upload/CheckUEntityUtil.java
  11. 12
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
  12. 6
      FtpComponent/src/main/java/com/arialyy/aria/ftp/AbsFtpInfoTask.java
  13. 6
      Http/src/main/java/com/arialyy/aria/http/HttpUtil.kt
  14. 74
      Http/src/main/java/com/arialyy/aria/http/download/HttpDBlockInterceptor.kt
  15. 8
      Http/src/main/java/com/arialyy/aria/http/download/HttpDFileInfoTask.java
  16. 4
      Http/src/main/java/com/arialyy/aria/http/download/HttpDHeaderInterceptor.kt
  17. 4
      M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoTask.java
  18. 4
      M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java
  19. 5
      PublicComponent/src/main/java/com/arialyy/aria/core/inf/IBlockManager.java
  20. 32
      PublicComponent/src/main/java/com/arialyy/aria/core/task/BlockState.kt
  21. 38
      PublicComponent/src/main/java/com/arialyy/aria/core/task/BlockUtil.kt
  22. 13
      PublicComponent/src/main/java/com/arialyy/aria/core/task/DBlockManager.kt
  23. 3
      PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskResp.kt
  24. 4
      PublicComponent/src/main/java/com/arialyy/aria/orm/dao/RecordDao.kt
  25. 23
      PublicComponent/src/main/java/com/arialyy/aria/orm/entity/BlockRecord.kt
  26. 83
      PublicComponent/src/main/java/com/arialyy/aria/util/CheckUtil.kt
  27. 70
      PublicComponent/src/main/java/com/arialyy/aria/util/Ext.kt
  28. 1
      PublicComponent/src/main/java/com/arialyy/aria/util/FileUtil.java
  29. 183
      PublicComponent/src/main/java/com/arialyy/aria/util/FileUtils.kt

@ -21,7 +21,7 @@ import com.arialyy.aria.core.IdEntity;
import com.arialyy.aria.core.ProtocolType; import com.arialyy.aria.core.ProtocolType;
import com.arialyy.aria.core.processor.IFtpUploadInterceptor; import com.arialyy.aria.core.processor.IFtpUploadInterceptor;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import java.text.DateFormatSymbols; import java.text.DateFormatSymbols;
import java.util.Collection; import java.util.Collection;
import java.util.Locale; import java.util.Locale;
@ -158,7 +158,7 @@ public class FtpOption extends BaseOption {
if (uploadInterceptor == null) { if (uploadInterceptor == null) {
throw new NullPointerException("ftp拦截器为空"); throw new NullPointerException("ftp拦截器为空");
} }
CheckUtil.checkMemberClass(uploadInterceptor.getClass()); FileUtils.checkMemberClass(uploadInterceptor.getClass());
this.uploadInterceptor = uploadInterceptor; this.uploadInterceptor = uploadInterceptor;
return this; return this;
} }
@ -212,7 +212,7 @@ public class FtpOption extends BaseOption {
ALog.e(TAG, "ip为空"); ALog.e(TAG, "ip为空");
return this; return this;
} }
if (!CheckUtil.checkIp(ip)) { if (!FileUtils.checkIp(ip)) {
ALog.e(TAG, "ip地址错误:" + ip); ALog.e(TAG, "ip地址错误:" + ip);
return this; return this;
} }

@ -19,7 +19,7 @@ import android.text.TextUtils;
import com.arialyy.aria.core.processor.IHttpFileLenAdapter; import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
import com.arialyy.aria.core.processor.IHttpFileNameAdapter; import com.arialyy.aria.core.processor.IHttpFileNameAdapter;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import java.net.Proxy; import java.net.Proxy;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -166,7 +166,7 @@ public class HttpOption extends BaseOption {
if (fileLenAdapter == null) { if (fileLenAdapter == null) {
throw new IllegalArgumentException("adapter为空"); throw new IllegalArgumentException("adapter为空");
} }
CheckUtil.checkMemberClass(fileLenAdapter.getClass()); FileUtils.checkMemberClass(fileLenAdapter.getClass());
this.fileLenAdapter = fileLenAdapter; this.fileLenAdapter = fileLenAdapter;
return this; return this;
} }
@ -174,7 +174,7 @@ public class HttpOption extends BaseOption {
if (fileNameAdapter == null) { if (fileNameAdapter == null) {
throw new IllegalArgumentException("adapter为空"); throw new IllegalArgumentException("adapter为空");
} }
CheckUtil.checkMemberClass(fileNameAdapter.getClass()); FileUtils.checkMemberClass(fileNameAdapter.getClass());
this.fileNameAdapter = fileNameAdapter; this.fileNameAdapter = fileNameAdapter;
return this; return this;
} }

@ -23,7 +23,7 @@ import com.arialyy.aria.core.inf.ITargetHandler;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.FileUtil; import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.RecordUtil; import com.arialyy.aria.util.RecordUtil;
@ -154,7 +154,7 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
//设置文件保存路径,如果新文件路径和旧文件路径不同,则修改路径 //设置文件保存路径,如果新文件路径和旧文件路径不同,则修改路径
if (!filePath.equals(mEntity.getFilePath())) { if (!filePath.equals(mEntity.getFilePath())) {
// 检查路径冲突 // 检查路径冲突
if (!CheckUtil.checkDPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath, if (!FileUtils.checkDPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath,
mWrapper.getRequestType())) { mWrapper.getRequestType())) {
return false; return false;
} }
@ -189,7 +189,7 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
if (TextUtils.isEmpty(url)) { if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "下载失败,url为null"); ALog.e(TAG, "下载失败,url为null");
return false; return false;
} else if (!CheckUtil.checkUrl(url)) { } else if (!FileUtils.checkUrl(url)) {
ALog.e(TAG, "下载失败,url【" + url + "】错误"); ALog.e(TAG, "下载失败,url【" + url + "】错误");
return false; return false;
} }

@ -22,7 +22,7 @@ import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.core.inf.IOptionConstant; import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.FileUtil; import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.RecordUtil; import com.arialyy.aria.util.RecordUtil;
import java.io.File; import java.io.File;
@ -85,7 +85,7 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
} }
// 检查路径冲突 // 检查路径冲突
if (mWrapper.isNewTask() && !CheckUtil.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(), if (mWrapper.isNewTask() && !FileUtils.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
dirPath)) { dirPath)) {
return false; return false;
} }

@ -20,7 +20,7 @@ import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.inf.ICheckEntityUtil; import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.core.inf.IOptionConstant; import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import java.io.File; import java.io.File;
public class CheckFtpDirEntityUtil implements ICheckEntityUtil { public class CheckFtpDirEntityUtil implements ICheckEntityUtil {
@ -61,7 +61,7 @@ public class CheckFtpDirEntityUtil implements ICheckEntityUtil {
} }
// 检查路径冲突 // 检查路径冲突
if (mWrapper.isNewTask() && !CheckUtil.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(), if (mWrapper.isNewTask() && !FileUtils.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
dirPath)) { dirPath)) {
return false; return false;
} }

@ -45,7 +45,7 @@ import com.arialyy.aria.core.scheduler.TaskSchedulers;
import com.arialyy.aria.core.task.ITask; import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ComponentUtil; import com.arialyy.aria.util.ComponentUtil;
import com.arialyy.aria.util.DbDataHelper; import com.arialyy.aria.util.DbDataHelper;
@ -270,7 +270,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果url错误或查找不到数据则返回null * @return 如果url错误或查找不到数据则返回null
*/ */
public DownloadEntity getFirstDownloadEntity(String downloadUrl) { public DownloadEntity getFirstDownloadEntity(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) { if (!FileUtils.checkUrl(downloadUrl)) {
return null; return null;
} }
return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl); return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
@ -282,7 +282,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果url错误或查找不到数据则返回null * @return 如果url错误或查找不到数据则返回null
*/ */
public List<DownloadEntity> getDownloadEntity(String downloadUrl) { public List<DownloadEntity> getDownloadEntity(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) { if (!FileUtils.checkUrl(downloadUrl)) {
return null; return null;
} }
return DbEntity.findDatas(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl); return DbEntity.findDatas(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
@ -308,7 +308,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果实体不存在返回null * @return 如果实体不存在返回null
*/ */
public DownloadGroupEntity getGroupEntity(List<String> urls) { public DownloadGroupEntity getGroupEntity(List<String> urls) {
if (CheckUtil.checkDownloadUrlsIsEmpty(urls)) { if (FileUtils.checkDownloadUrlsIsEmpty(urls)) {
return null; return null;
} }
return DbDataHelper.getDGEntityByHash(CommonUtil.getMd5Code(urls)); return DbDataHelper.getDGEntityByHash(CommonUtil.getMd5Code(urls));
@ -321,7 +321,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果实体不存在返回null * @return 如果实体不存在返回null
*/ */
public DownloadGroupEntity getFtpDirEntity(String url) { public DownloadGroupEntity getFtpDirEntity(String url) {
if (!CheckUtil.checkUrl(url)) { if (!FileUtils.checkUrl(url)) {
return null; return null;
} }
return DbDataHelper.getDGEntityByHash(url); return DbDataHelper.getDGEntityByHash(url);
@ -387,7 +387,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null * @return 如果页数大于总页数返回null
*/ */
public List<DownloadEntity> getTaskList(int page, int num) { public List<DownloadEntity> getTaskList(int page, int num) {
CheckUtil.checkPageParams(page, num); FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num, return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!=''", "false"); "isGroupChild=? and downloadPath!=''", "false");
} }
@ -408,7 +408,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null * @return 如果页数大于总页数返回null
*/ */
public List<DownloadEntity> getAllNotCompleteTask(int page, int num) { public List<DownloadEntity> getAllNotCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num); FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num, return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false"); "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
} }
@ -429,7 +429,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null * @return 如果页数大于总页数返回null
*/ */
public List<DownloadEntity> getAllCompleteTask(int page, int num) { public List<DownloadEntity> getAllCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num); FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true"); "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
} }

@ -17,7 +17,7 @@ package com.arialyy.aria.core.download.m3u8;
import com.arialyy.aria.core.processor.ILiveTsUrlConverter; import com.arialyy.aria.core.processor.ILiveTsUrlConverter;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
/** /**
* m3u8直播参数设置 * m3u8直播参数设置
@ -38,7 +38,7 @@ public class M3U8LiveOption extends M3U8Option<M3U8LiveOption> {
* @param liveTsUrlConverter {@link ILiveTsUrlConverter} * @param liveTsUrlConverter {@link ILiveTsUrlConverter}
*/ */
public M3U8LiveOption setLiveTsUrlConvert(ILiveTsUrlConverter liveTsUrlConverter) { public M3U8LiveOption setLiveTsUrlConvert(ILiveTsUrlConverter liveTsUrlConverter) {
CheckUtil.checkMemberClass(liveTsUrlConverter.getClass()); FileUtils.checkMemberClass(liveTsUrlConverter.getClass());
this.liveTsUrlConverter = liveTsUrlConverter; this.liveTsUrlConverter = liveTsUrlConverter;
return this; return this;
} }

@ -21,7 +21,7 @@ import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
import com.arialyy.aria.core.processor.IKeyUrlConverter; import com.arialyy.aria.core.processor.IKeyUrlConverter;
import com.arialyy.aria.core.processor.ITsMergeHandler; import com.arialyy.aria.core.processor.ITsMergeHandler;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.ComponentUtil; import com.arialyy.aria.util.ComponentUtil;
/** /**
@ -101,7 +101,7 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
* 需要注意的是只有{@link #merge(boolean)}设置合并ts文件该方法才会生效 * 需要注意的是只有{@link #merge(boolean)}设置合并ts文件该方法才会生效
*/ */
public OP setMergeHandler(ITsMergeHandler mergeHandler) { public OP setMergeHandler(ITsMergeHandler mergeHandler) {
CheckUtil.checkMemberClass(mergeHandler.getClass()); FileUtils.checkMemberClass(mergeHandler.getClass());
this.mergeHandler = mergeHandler; this.mergeHandler = mergeHandler;
return (OP) this; return (OP) this;
} }
@ -123,7 +123,7 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
* @param bandWidthUrlConverter {@link IBandWidthUrlConverter} * @param bandWidthUrlConverter {@link IBandWidthUrlConverter}
*/ */
public OP setBandWidthUrlConverter(IBandWidthUrlConverter bandWidthUrlConverter) { public OP setBandWidthUrlConverter(IBandWidthUrlConverter bandWidthUrlConverter) {
CheckUtil.checkMemberClass(bandWidthUrlConverter.getClass()); FileUtils.checkMemberClass(bandWidthUrlConverter.getClass());
this.bandWidthUrlConverter = bandWidthUrlConverter; this.bandWidthUrlConverter = bandWidthUrlConverter;
return (OP) this; return (OP) this;
} }
@ -134,7 +134,7 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
* @param keyUrlConverter {@link IKeyUrlConverter} * @param keyUrlConverter {@link IKeyUrlConverter}
*/ */
public OP setKeyUrlConverter(IKeyUrlConverter keyUrlConverter) { public OP setKeyUrlConverter(IKeyUrlConverter keyUrlConverter) {
CheckUtil.checkMemberClass(keyUrlConverter.getClass()); FileUtils.checkMemberClass(keyUrlConverter.getClass());
this.keyUrlConverter = keyUrlConverter; this.keyUrlConverter = keyUrlConverter;
return (OP) this; return (OP) this;
} }

@ -17,7 +17,7 @@ package com.arialyy.aria.core.download.m3u8;
import com.arialyy.aria.core.processor.IVodTsUrlConverter; import com.arialyy.aria.core.processor.IVodTsUrlConverter;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
/** /**
* m3u8点播文件参数设置 * m3u8点播文件参数设置
@ -39,7 +39,7 @@ public class M3U8VodOption extends M3U8Option<M3U8VodOption> {
* @param vodUrlConverter {@link IVodTsUrlConverter} * @param vodUrlConverter {@link IVodTsUrlConverter}
*/ */
public M3U8VodOption setVodTsUrlConvert(IVodTsUrlConverter vodUrlConverter) { public M3U8VodOption setVodTsUrlConvert(IVodTsUrlConverter vodUrlConverter) {
CheckUtil.checkMemberClass(vodUrlConverter.getClass()); FileUtils.checkMemberClass(vodUrlConverter.getClass());
this.vodUrlConverter = vodUrlConverter; this.vodUrlConverter = vodUrlConverter;
return this; return this;
} }

@ -18,7 +18,7 @@ package com.arialyy.aria.core.upload;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.inf.ICheckEntityUtil; import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import java.io.File; import java.io.File;
public class CheckUEntityUtil implements ICheckEntityUtil { public class CheckUEntityUtil implements ICheckEntityUtil {
@ -62,7 +62,7 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
} }
// 任务是新任务,并且路径冲突就不会继续执行 // 任务是新任务,并且路径冲突就不会继续执行
if (mWrapper.isNewTask() if (mWrapper.isNewTask()
&& !CheckUtil.checkUPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath, && !FileUtils.checkUPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath,
mWrapper.getRequestType())) { mWrapper.getRequestType())) {
return false; return false;
} }
@ -86,7 +86,7 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
if (TextUtils.isEmpty(url)) { if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "上传失败,url为null"); ALog.e(TAG, "上传失败,url为null");
return false; return false;
} else if (!CheckUtil.checkUrl(url)) { } else if (!FileUtils.checkUrl(url)) {
ALog.e(TAG, "上传失败,url【" + url + "】错误"); ALog.e(TAG, "上传失败,url【" + url + "】错误");
return false; return false;
} }

@ -39,7 +39,7 @@ import com.arialyy.aria.core.upload.target.HttpNormalTarget;
import com.arialyy.aria.core.upload.target.UTargetFactory; import com.arialyy.aria.core.upload.target.UTargetFactory;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.ComponentUtil; import com.arialyy.aria.util.ComponentUtil;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -73,7 +73,7 @@ public class UploadReceiver extends AbsReceiver {
public HttpBuilderTarget load(String filePath) { public HttpBuilderTarget load(String filePath) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_HTTP); ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_HTTP);
CheckUtil.checkUploadPathIsEmpty(filePath); FileUtils.checkUploadPathIsEmpty(filePath);
return UTargetFactory.getInstance() return UTargetFactory.getInstance()
.generateBuilderTarget(HttpBuilderTarget.class, filePath); .generateBuilderTarget(HttpBuilderTarget.class, filePath);
} }
@ -99,7 +99,7 @@ public class UploadReceiver extends AbsReceiver {
public FtpBuilderTarget loadFtp(String filePath) { public FtpBuilderTarget loadFtp(String filePath) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_FTP); ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_FTP);
CheckUtil.checkUploadPathIsEmpty(filePath); FileUtils.checkUploadPathIsEmpty(filePath);
return UTargetFactory.getInstance() return UTargetFactory.getInstance()
.generateBuilderTarget(FtpBuilderTarget.class, filePath); .generateBuilderTarget(FtpBuilderTarget.class, filePath);
} }
@ -178,7 +178,7 @@ public class UploadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null * @return 如果页数大于总页数返回null
*/ */
public List<UploadEntity> getTaskList(int page, int num) { public List<UploadEntity> getTaskList(int page, int num) {
CheckUtil.checkPageParams(page, num); FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(UploadEntity.class, page, num, return DbEntity.findDatas(UploadEntity.class, page, num,
"isGroupChild=? and downloadPath!=''", "false"); "isGroupChild=? and downloadPath!=''", "false");
} }
@ -199,7 +199,7 @@ public class UploadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null * @return 如果页数大于总页数返回null
*/ */
public List<UploadEntity> getAllNotCompleteTask(int page, int num) { public List<UploadEntity> getAllNotCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num); FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(UploadEntity.class, page, num, return DbEntity.findDatas(UploadEntity.class, page, num,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false"); "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
} }
@ -220,7 +220,7 @@ public class UploadReceiver extends AbsReceiver {
* @return 如果页数大于总页数返回null * @return 如果页数大于总页数返回null
*/ */
public List<UploadEntity> getAllCompleteTask(int page, int num) { public List<UploadEntity> getAllCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num); FileUtils.checkPageParams(page, num);
return DbEntity.findDatas(UploadEntity.class, return DbEntity.findDatas(UploadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true"); "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
} }

@ -34,7 +34,7 @@ import com.arialyy.aria.core.loader.ILoaderVisitor;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.exception.AriaFTPException; import com.arialyy.aria.exception.AriaFTPException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.SSLContextUtil; import com.arialyy.aria.util.SSLContextUtil;
import java.io.IOException; import java.io.IOException;
@ -140,7 +140,7 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
private FTPClient createFtpClient() throws IOException, InterruptedException { private FTPClient createFtpClient() throws IOException, InterruptedException {
FTPClient client = null; FTPClient client = null;
final FtpUrlEntity urlEntity = mTaskOption.getUrlEntity(); final FtpUrlEntity urlEntity = mTaskOption.getUrlEntity();
if (CheckUtil.checkIp(urlEntity.hostName)) { if (FileUtils.checkIp(urlEntity.hostName)) {
client = newInstanceClient(urlEntity); client = newInstanceClient(urlEntity);
client.setConnectTimeout(mConnectTimeOut); // 连接10s超时 client.setConnectTimeout(mConnectTimeOut); // 连接10s超时
InetAddress ip = InetAddress.getByName(urlEntity.hostName); InetAddress ip = InetAddress.getByName(urlEntity.hostName);
@ -338,7 +338,7 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
} else { } else {
msg = String.format("%s, code: %s, msg: %s", msg, client.getReplyCode(), msg = String.format("%s, code: %s, msg: %s", msg, client.getReplyCode(),
client.getReplyString()); client.getReplyString());
needRetry = needRetry && !CheckUtil.ftpIsBadRequest(client.getReplyCode()); needRetry = needRetry && !FileUtils.ftpIsBadRequest(client.getReplyCode());
} }
callback.onFail(mEntity, new AriaFTPException(msg), needRetry); callback.onFail(mEntity, new AriaFTPException(msg), needRetry);

@ -17,7 +17,7 @@ package com.arialyy.aria.http
import android.text.TextUtils import android.text.TextUtils
import com.arialyy.aria.http.download.HttpDTaskOption import com.arialyy.aria.http.download.HttpDTaskOption
import com.arialyy.aria.util.CheckUtil import com.arialyy.aria.util.FileUtils
import com.arialyy.aria.util.Regular import com.arialyy.aria.util.Regular
import timber.log.Timber import timber.log.Timber
import java.io.IOException import java.io.IOException
@ -83,7 +83,7 @@ internal object HttpUtil {
Timber.e("url is null") Timber.e("url is null")
return false return false
} }
if (!CheckUtil.checkUrl(option.sourUrl!!)) { if (!FileUtils.checkUrl(option.sourUrl!!)) {
Timber.e("invalid url, ${option.sourUrl}") Timber.e("invalid url, ${option.sourUrl}")
return false return false
} }
@ -91,7 +91,7 @@ internal object HttpUtil {
Timber.e("save path is null") Timber.e("save path is null")
return false return false
} }
if (!CheckUtil.checkUri(option.savePathUri)) { if (!FileUtils.uriEffective(option.savePathUri)) {
Timber.e("invalid uri, ${option.savePathUri}") Timber.e("invalid uri, ${option.savePathUri}")
return false return false
} }

@ -15,6 +15,8 @@
*/ */
package com.arialyy.aria.http.download package com.arialyy.aria.http.download
import android.os.Handler
import android.os.Looper
import com.arialyy.aria.core.DuaContext import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.core.inf.IBlockManager import com.arialyy.aria.core.inf.IBlockManager
import com.arialyy.aria.core.task.BlockUtil import com.arialyy.aria.core.task.BlockUtil
@ -22,7 +24,12 @@ import com.arialyy.aria.core.task.ITask
import com.arialyy.aria.core.task.ITaskInterceptor import com.arialyy.aria.core.task.ITaskInterceptor
import com.arialyy.aria.core.task.TaskChain import com.arialyy.aria.core.task.TaskChain
import com.arialyy.aria.core.task.TaskResp import com.arialyy.aria.core.task.TaskResp
import com.arialyy.aria.orm.entity.BlockRecord
import com.arialyy.aria.orm.entity.TaskRecord import com.arialyy.aria.orm.entity.TaskRecord
import com.arialyy.aria.util.FileUri
import com.arialyy.aria.util.FileUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
@ -35,6 +42,7 @@ internal class HttpDBlockInterceptor : ITaskInterceptor {
private lateinit var task: ITask private lateinit var task: ITask
private lateinit var option: HttpDTaskOption private lateinit var option: HttpDTaskOption
private lateinit var blockManager: IBlockManager private lateinit var blockManager: IBlockManager
private lateinit var taskRecord: TaskRecord
override suspend fun interceptor(chain: TaskChain): TaskResp { override suspend fun interceptor(chain: TaskChain): TaskResp {
task = chain.getTask() task = chain.getTask()
@ -45,16 +53,40 @@ internal class HttpDBlockInterceptor : ITaskInterceptor {
return TaskResp(TaskResp.CODE_GET_FILE_INFO_FAIL) return TaskResp(TaskResp.CODE_GET_FILE_INFO_FAIL)
} }
val savePath = FileUri.getPathByUri(task.getTaskOption(HttpDTaskOption::class.java).savePathUri)
if (savePath.isNullOrEmpty()) {
Timber.e("saveUri is null")
return TaskResp(TaskResp.CODE_SAVE_URI_NULL)
}
// if task not support resume, don't save record // if task not support resume, don't save record
if (task.taskState.fileSize == 0L) { if (task.taskState.fileSize == 0L) {
chain.blockManager.setBlockNum(1) chain.blockManager.setBlockNum(1)
// if block exist, delete the existed block
removeBlock()
return chain.proceed(chain.getTask()) return chain.proceed(chain.getTask())
} }
val blockNum = checkRecord() val blockNum = checkRecord()
chain.blockManager.setBlockNum(blockNum) chain.blockManager.setBlockNum(blockNum)
val result = checkBlock()
if (result != TaskResp.CODE_SUCCESS) {
return TaskResp(result)
}
return chain.proceed(chain.getTask()) return chain.proceed(chain.getTask())
} }
private fun removeBlock() {
val saveUri = task.getTaskOption(HttpDTaskOption::class.java).savePathUri
if (!FileUtils.uriEffective(saveUri)) {
return
}
val blockF = File(BlockUtil.getBlockPathFormUri(saveUri!!, 0))
if (blockF.exists()) {
blockF.delete()
}
}
/** /**
* check task record, if record no exist, create taskRecord * check task record, if record no exist, create taskRecord
* @return blockNum * @return blockNum
@ -74,21 +106,51 @@ internal class HttpDBlockInterceptor : ITaskInterceptor {
blockNum = blockNumInfo.first, blockNum = blockNumInfo.first,
blockSize = task.taskState.blockSize blockSize = task.taskState.blockSize
) )
taskRecord.blockList.addAll(BlockUtil.createBlockRecord(task.taskState.fileSize))
taskRecord.blockList.addAll(
BlockUtil.createBlockRecord(
task.getTaskOption(HttpDTaskOption::class.java).savePathUri!!,
task.taskState.fileSize
)
)
recordDao.insert(taskRecord) recordDao.insert(taskRecord)
this.taskRecord = taskRecord
return taskRecord.blockNum return taskRecord.blockNum
} }
Timber.d("record existed") Timber.d("record existed")
checkBlock(recordWrapper.taskRecord) taskRecord = recordWrapper.taskRecord
return recordWrapper.taskRecord.blockNum return recordWrapper.taskRecord.blockNum
} }
/**ø /**
* if block already exist, upload progress * if block already exist, upload progress
*/ */
private fun checkBlock(record: TaskRecord) { private suspend fun checkBlock(): Int {
for (br in record.blockList) { val handler = Handler(Looper.myLooper()!!, blockManager.handlerCallback)
val block = File() val needUpdateBlockRecord = mutableSetOf<BlockRecord>()
for (br in taskRecord.blockList) {
val blockF = File(br.blockPath)
if (blockF.exists()) {
if (br.curProgress == blockF.length() && !br.isComplete) {
br.isComplete = true
needUpdateBlockRecord.add(br)
}
if (br.curProgress != blockF.length()) {
br.curProgress = blockF.length()
needUpdateBlockRecord.add(br)
blockManager.putUnfinishedBlock(br)
}
// update task progress
handler.obtainMessage(IBlockManager.STATE_UPDATE_PROGRESS, br.curProgress)
}
}
handler.removeCallbacksAndMessages(null)
// update block record
val dao = DuaContext.getServiceManager().getDbService().getDuaDb().getRecordDao()
withContext(Dispatchers.IO) {
dao.updateBlockList(needUpdateBlockRecord.toMutableList())
} }
return TaskResp.CODE_SUCCESS
} }
} }

@ -31,7 +31,7 @@ import com.arialyy.aria.exception.AriaHTTPException;
import com.arialyy.aria.http.ConnectionHelp; import com.arialyy.aria.http.ConnectionHelp;
import com.arialyy.aria.http.HttpTaskOption; import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.FileUtil; import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.RecordUtil; import com.arialyy.aria.util.RecordUtil;
@ -262,7 +262,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
} else { } else {
failDownload(new AriaHTTPException( failDownload(new AriaHTTPException(
String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code, String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code,
conn.getResponseMessage(), mEntity.getUrl())), !CheckUtil.httpIsBadRequest(code)); conn.getResponseMessage(), mEntity.getUrl())), !FileUtils.httpIsBadRequest(code));
} }
if (end) { if (end) {
doNext(code, isChunked); doNext(code, isChunked);
@ -324,7 +324,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
ALog.d(TAG, String.format("文件重命名为:%s", newName)); ALog.d(TAG, String.format("文件重命名为:%s", newName));
File oldFile = new File(mEntity.getFilePath()); File oldFile = new File(mEntity.getFilePath());
String newPath = oldFile.getParent() + "/" + newName; String newPath = oldFile.getParent() + "/" + newName;
if (!CheckUtil.checkDPathConflicts(false, newPath, mTaskWrapper.getRequestType())) { if (!FileUtils.checkDPathConflicts(false, newPath, mTaskWrapper.getRequestType())) {
ALog.e(TAG, "文件重命名失败"); ALog.e(TAG, "文件重命名失败");
return; return;
} }
@ -353,7 +353,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
newUrl = uri.getHost() + newUrl; newUrl = uri.getHost() + newUrl;
} }
if (!CheckUtil.checkUrl(newUrl)) { if (!FileUtils.checkUrl(newUrl)) {
failDownload(new AriaHTTPException("下载失败,重定向url错误"), false); failDownload(new AriaHTTPException("下载失败,重定向url错误"), false);
return; return;
} }

@ -28,7 +28,7 @@ import com.arialyy.aria.core.task.TaskChain
import com.arialyy.aria.core.task.TaskResp import com.arialyy.aria.core.task.TaskResp
import com.arialyy.aria.http.HttpUtil import com.arialyy.aria.http.HttpUtil
import com.arialyy.aria.http.request.IRequest import com.arialyy.aria.http.request.IRequest
import com.arialyy.aria.util.CheckUtil import com.arialyy.aria.util.FileUtils
import timber.log.Timber import timber.log.Timber
import java.io.BufferedReader import java.io.BufferedReader
import java.io.IOException import java.io.IOException
@ -169,7 +169,7 @@ internal class HttpDHeaderInterceptor : ITaskInterceptor {
val uri = Uri.parse(taskOption.sourUrl!!) val uri = Uri.parse(taskOption.sourUrl!!)
tempUrl = uri.host + newUrl tempUrl = uri.host + newUrl
} }
if (!CheckUtil.checkUrl(tempUrl)) { if (!FileUtils.checkUrl(tempUrl)) {
Timber.e("get redirect url fail, $tempUrl") Timber.e("get redirect url fail, $tempUrl")
return -1 return -1
} }

@ -34,7 +34,7 @@ import com.arialyy.aria.exception.AriaM3U8Exception;
import com.arialyy.aria.http.ConnectionHelp; import com.arialyy.aria.http.ConnectionHelp;
import com.arialyy.aria.http.HttpTaskOption; import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.FileUtil; import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.Regular; import com.arialyy.aria.util.Regular;
@ -327,7 +327,7 @@ final public class M3U8InfoTask implements IInfoTask {
newUrl = uri.getHost() + newUrl; newUrl = uri.getHost() + newUrl;
} }
if (!CheckUtil.checkUrl(newUrl)) { if (!FileUtils.checkUrl(newUrl)) {
failDownload("下载失败,重定向url错误", false); failDownload("下载失败,重定向url错误", false);
return; return;
} }

@ -25,7 +25,7 @@ import com.arialyy.aria.exception.AriaM3U8Exception;
import com.arialyy.aria.http.ConnectionHelp; import com.arialyy.aria.http.ConnectionHelp;
import com.arialyy.aria.http.HttpTaskOption; import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -159,7 +159,7 @@ public final class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
newUrl = uri.getHost() + newUrl; newUrl = uri.getHost() + newUrl;
} }
if (!CheckUtil.checkUrl(newUrl)) { if (!FileUtils.checkUrl(newUrl)) {
fail(new AriaM3U8Exception("下载失败,重定向url错误"), false); fail(new AriaM3U8Exception("下载失败,重定向url错误"), false);
return; return;
} }

@ -18,6 +18,7 @@ package com.arialyy.aria.core.inf;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.arialyy.aria.orm.entity.BlockRecord;
/** /**
* 线程任务状态 * 线程任务状态
@ -41,6 +42,10 @@ public interface IBlockManager {
void setBlockNum(int blockNum); void setBlockNum(int blockNum);
void putUnfinishedBlock(BlockRecord record);
BlockRecord getUnfinishedBlock();
/** /**
* 是否有失败的快 * 是否有失败的快
* *

@ -1,32 +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.task
import com.arialyy.aria.orm.entity.BlockRecord
class BlockState(val blockState: BlockRecord, val blockPath: String) {
companion object {
/**
* dir/.fileName.blockId
*/
const val BLOCK_PATH = "%s/.%s.%d"
const val BLOCK_SIZE = 1024 * 1024 * 5L
}
var curProgress: Long = 0
}

@ -1,9 +1,11 @@
package com.arialyy.aria.core.task package com.arialyy.aria.core.task
import android.bluetooth.BluetoothClass import android.net.Uri
import com.arialyy.aria.orm.entity.BlockRecord import com.arialyy.aria.orm.entity.BlockRecord
import com.arialyy.aria.orm.entity.TaskRecord import com.arialyy.aria.orm.entity.TaskRecord
import com.arialyy.aria.util.FileUri
import com.arialyy.aria.util.FileUtil import com.arialyy.aria.util.FileUtil
import com.arialyy.aria.util.FileUtils
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
@ -24,22 +26,35 @@ import java.io.File
*/ */
object BlockUtil { object BlockUtil {
fun getBlockPathFormUri(fileSaveUri: Uri, blockId: Int): String {
val filePath = FileUri.getPathByUri(fileSaveUri) ?: "/"
val fileName = FileUtils.getFileNameFromPath(filePath)
val dirPath = FileUtils.getFilePathFromFullPath(filePath)
return BlockRecord.BLOCK_PATH.format(dirPath, fileName, blockId)
}
/** /**
* create block record * create block record
*/ */
fun createBlockRecord(fileSize: Long): List<BlockRecord> { fun createBlockRecord(fileSaveUri: Uri, fileSize: Long): List<BlockRecord> {
val filePath = FileUri.getPathByUri(fileSaveUri) ?: "/"
val fileName = FileUtils.getFileNameFromPath(filePath)
val dirPath = FileUtils.getFilePathFromFullPath(filePath)
val blockNumInfo = getBlockNum(fileSize) val blockNumInfo = getBlockNum(fileSize)
val lastIndex = blockNumInfo.first - 1 val lastIndex = blockNumInfo.first - 1
val brList = mutableListOf<BlockRecord>() val brList = mutableListOf<BlockRecord>()
for (bi in 0 until blockNumInfo.first) { for (bi in 0 until blockNumInfo.first) {
val sl = bi * BlockState.BLOCK_SIZE val sl = bi * BlockRecord.BLOCK_SIZE
val blockSize = if (bi == lastIndex) blockNumInfo.second else BlockState.BLOCK_SIZE val blockSize = if (bi == lastIndex) blockNumInfo.second else BlockRecord.BLOCK_SIZE
val el = sl + blockSize val el = sl + blockSize
val blockRecord = BlockRecord( val blockRecord = BlockRecord(
bId = bi, bId = bi,
startLocation = bi * BlockState.BLOCK_SIZE, startLocation = bi * BlockRecord.BLOCK_SIZE,
endLocation = el, endLocation = el,
blockSize = blockSize, blockSize = blockSize,
blockPath = BlockRecord.BLOCK_PATH.format(dirPath, fileName, bi)
) )
brList.add(blockRecord) brList.add(blockRecord)
} }
@ -51,11 +66,11 @@ object BlockUtil {
* @return pair<blockNum, lastBlockSize> * @return pair<blockNum, lastBlockSize>
*/ */
fun getBlockNum(fileLen: Long): Pair<Int, Long> { fun getBlockNum(fileLen: Long): Pair<Int, Long> {
if (fileLen <= BlockState.BLOCK_SIZE) { if (fileLen <= BlockRecord.BLOCK_SIZE) {
return Pair(1, 0) return Pair(1, 0)
} }
val blockNum = (fileLen / BlockState.BLOCK_SIZE).toInt() val blockNum = (fileLen / BlockRecord.BLOCK_SIZE).toInt()
val lastBlockSize = fileLen % BlockState.BLOCK_SIZE val lastBlockSize = fileLen % BlockRecord.BLOCK_SIZE
return Pair(if (lastBlockSize != 0L) blockNum + 1 else blockNum, lastBlockSize) return Pair(if (lastBlockSize != 0L) blockNum + 1 else blockNum, lastBlockSize)
} }
@ -68,16 +83,16 @@ object BlockUtil {
val fileName = targetF.name val fileName = targetF.name
if (record.blockNum == 1) { if (record.blockNum == 1) {
// if this task not support blocks or fileSize < 5m, just need rename // if this task not support blocks or fileSize < 5m, just need rename
return File(BlockState.BLOCK_PATH.format(dir, fileName, 0)).renameTo(targetF) return File(BlockRecord.BLOCK_PATH.format(dir, fileName, 0)).renameTo(targetF)
} }
val blockList = mutableListOf<File>() val blockList = mutableListOf<File>()
for (i in 0 until record.blockNum) { for (i in 0 until record.blockNum) {
val subF = File(BlockState.BLOCK_PATH.format(dir, fileName, i)) val subF = File(BlockRecord.BLOCK_PATH.format(dir, fileName, i))
if (!subF.exists()) { if (!subF.exists()) {
Timber.e("this block: $i not exists") Timber.e("this block: $i not exists")
return false return false
} }
if (subF.length() != BlockState.BLOCK_SIZE.toLong()) { if (subF.length() != BlockRecord.BLOCK_SIZE.toLong()) {
Timber.e("this block: $i size abnormal, size: ${subF.length()}") Timber.e("this block: $i size abnormal, size: ${subF.length()}")
return false return false
} }
@ -85,5 +100,4 @@ object BlockUtil {
} }
return FileUtil.mergeFile(record.filePath, blockList) return FileUtil.mergeFile(record.filePath, blockList)
} }
} }

@ -20,11 +20,13 @@ import android.os.Looper
import com.arialyy.aria.core.inf.IBlockManager import com.arialyy.aria.core.inf.IBlockManager
import com.arialyy.aria.core.listener.IEventListener import com.arialyy.aria.core.listener.IEventListener
import com.arialyy.aria.exception.AriaException import com.arialyy.aria.exception.AriaException
import com.arialyy.aria.orm.entity.BlockRecord
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.LinkedBlockingDeque
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
class BlockManager(private val eventListener: IEventListener) : IBlockManager { class BlockManager(private val eventListener: IEventListener) : IBlockManager {
private val blockList = mutableListOf<BlockState>() private val unfinishedBlockQueue = LinkedBlockingDeque<BlockRecord>()
private val canceledNum = AtomicInteger(0) // 已经取消的线程的数 private val canceledNum = AtomicInteger(0) // 已经取消的线程的数
private val stoppedNum = AtomicInteger(0) // 已经停止的线程数 private val stoppedNum = AtomicInteger(0) // 已经停止的线程数
private val failedNum = AtomicInteger(0) // 失败的线程数 private val failedNum = AtomicInteger(0) // 失败的线程数
@ -88,12 +90,12 @@ class BlockManager(private val eventListener: IEventListener) : IBlockManager {
looper.quit() looper.quit()
} }
fun addBlockState(state: BlockState) { override fun putUnfinishedBlock(record: BlockRecord) {
blockList.add(state) unfinishedBlockQueue.offer(record)
} }
fun getBlockState(): BlockState { override fun getUnfinishedBlock(): BlockRecord {
return blockList.removeFirst() return unfinishedBlockQueue.remove()
} }
override fun setLopper(looper: Looper) { override fun setLopper(looper: Looper) {
@ -138,5 +140,4 @@ class BlockManager(private val eventListener: IEventListener) : IBlockManager {
override fun getHandlerCallback(): Callback { override fun getHandlerCallback(): Callback {
return callback return callback
} }
} }

@ -7,9 +7,10 @@ package com.arialyy.aria.core.task
**/ **/
class TaskResp(val code: Int = CODE_DEF) { class TaskResp(val code: Int = CODE_DEF) {
companion object { companion object {
const val CODE_COMPLETE = 1 const val CODE_SUCCESS = 1
const val CODE_INTERRUPT = 999 const val CODE_INTERRUPT = 999
const val CODE_DEF = 0 const val CODE_DEF = 0
const val CODE_SAVE_URI_NULL = 3
const val CODE_GET_FILE_INFO_FAIL = 2 const val CODE_GET_FILE_INFO_FAIL = 2
} }

@ -53,6 +53,10 @@ interface RecordDao {
@Update @Update
suspend fun update(record: TaskRecord) suspend fun update(record: TaskRecord)
@Transaction
@Update
suspend fun updateBlockList(blockList: List<BlockRecord>)
@Delete @Delete
suspend fun deleteTaskRecord(record: TaskRecord) suspend fun deleteTaskRecord(record: TaskRecord)

@ -18,7 +18,7 @@ package com.arialyy.aria.orm.entity
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.ForeignKey.Companion.CASCADE import androidx.room.ForeignKey.Companion.CASCADE
import androidx.room.PrimaryKey import androidx.room.Ignore
/** /**
* @Author laoyuyu * @Author laoyuyu
@ -49,5 +49,22 @@ data class BlockRecord(
val blockSize: Long = 0, val blockSize: Long = 0,
val isComplete: Boolean = false /**
) * block path
*/
val blockPath: String,
var isComplete: Boolean = false
) {
companion object {
/**
* dir/.fileName.blockId
*/
const val BLOCK_PATH = "%s/.%s.%d"
const val BLOCK_SIZE = 1024 * 1024 * 5L
}
@Ignore
var curProgress = 0L
}

@ -1,83 +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.util
import android.database.Cursor
import android.net.Uri
import com.arialyy.aria.core.DuaContext
import timber.log.Timber
import java.io.InputStream
object CheckUtil {
val HTTP_REGEX =
Regex(
"(https?)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]",
RegexOption.IGNORE_CASE
)
/**
* check if url is correct
*/
fun checkUrl(url: String) = HTTP_REGEX.matches(url)
/**
* 1. Check if Uri is correct
* 2. Whether the file corresponding to Uri exists (may be deleted, or the system db has Uri related records, but the file is invalid or damaged)
*
* https://stackoverflow.com/questions/7645951/how-to-check-if-resource-pointed-by-uri-is-available
*/
fun checkUri(uri: Uri?): Boolean {
if (uri == null) return false
val resolver = DuaContext.context.contentResolver
//1. Check Uri
var cursor: Cursor? = null
val isUriExist: Boolean = try {
cursor = resolver.query(uri, null, null, null, null)
//cursor null: content Uri was invalid or some other error occurred
//cursor.moveToFirst() false: Uri was ok but no entry found.
(cursor != null && cursor.moveToFirst())
} catch (t: Throwable) {
Timber.e("1.Check Uri Error: ${t.message}")
false
} finally {
try {
cursor?.close()
} catch (t: Throwable) {
}
}
//2. Check File Exist
//如果系统 db 存有 Uri 相关记录, 但是文件失效或者损坏 (If the system db has Uri related records, but the file is invalid or damaged)
var ins: InputStream? = null
val isFileExist: Boolean = try {
ins = resolver.openInputStream(uri)
// file exists
true
} catch (t: Throwable) {
// File was not found eg: open failed: ENOENT (No such file or directory)
Timber.e("2. Check File Exist Error: ${t.message}")
false
} finally {
try {
ins?.close()
} catch (t: Throwable) {
}
}
return isUriExist && isFileExist
}
}

@ -0,0 +1,70 @@
/*
* 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.util
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import com.arialyy.aria.core.DuaContext
import timber.log.Timber
internal const val AUTHORITY = ".andoFileProvider"
/**
* @return 传入的Uri是否已具备访问权限 (Whether the incoming Uri has access permission)
*/
fun giveUriPermission(uri: Uri?): Boolean {
return uri?.run {
when (DuaContext.context.checkUriPermission(
this,
android.os.Process.myPid(),
android.os.Process.myUid(),
Intent.FLAG_GRANT_READ_URI_PERMISSION
)) {
PackageManager.PERMISSION_GRANTED -> true
PackageManager.PERMISSION_DENIED -> {
DuaContext.context.grantUriPermission(
DuaContext.context.packageName, this, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
false
}
else -> false
}
} ?: false
}
fun revokeUriPermission(uri: Uri?) {
DuaContext.context.revokeUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
inline fun <R> Uri.use(block: Uri.() -> R): R {
var isAlreadyHavePermission = false
try {
isAlreadyHavePermission = giveUriPermission(this)
return block()
} catch (t: Throwable) {
Timber.e("giveUriPermission Error ${t.message}")
} finally {
if (!isAlreadyHavePermission) {
try {
revokeUriPermission(this)
} catch (t: Throwable) {
Timber.e("revokeUriPermission Error ${t.message}")
}
}
}
return block()
}

@ -56,6 +56,7 @@ import timber.log.Timber;
/** /**
* 文件操作工具类 * 文件操作工具类
*/ */
@Deprecated
public class FileUtil { public class FileUtil {
private static final String TAG = "FileUtil"; private static final String TAG = "FileUtil";
private static final Pattern DIR_SEPORATOR = Pattern.compile("/"); private static final Pattern DIR_SEPORATOR = Pattern.compile("/");

@ -0,0 +1,183 @@
/*
* 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.util
import android.content.ContentResolver
import android.database.Cursor
import android.net.Uri
import android.provider.OpenableColumns
import com.arialyy.aria.core.DuaContext
import timber.log.Timber
import java.io.InputStream
import java.util.Locale
object FileUtils {
val HTTP_REGEX =
Regex(
"(https?)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]",
RegexOption.IGNORE_CASE
)
/**
* check if url is correct
*/
fun checkUrl(url: String) = HTTP_REGEX.matches(url)
/**
* https://github.com/javakam/FileOperator/blob/master/library_core/src/main/java/ando/file/core/FileUtils.kt
*
* 1. Check if Uri is correct
* 2. Whether the file corresponding to Uri exists (may be deleted, or the system db has Uri related records, but the file is invalid or damaged)
*
* https://stackoverflow.com/questions/7645951/how-to-check-if-resource-pointed-by-uri-is-available
*/
fun uriEffective(uri: Uri?): Boolean {
if (uri == null) return false
val resolver = DuaContext.context.contentResolver
//1. Check Uri
var cursor: Cursor? = null
val isUriExist: Boolean = try {
cursor = resolver.query(uri, null, null, null, null)
//cursor null: content Uri was invalid or some other error occurred
//cursor.moveToFirst() false: Uri was ok but no entry found.
(cursor != null && cursor.moveToFirst())
} catch (t: Throwable) {
Timber.e("1.Check Uri Error: ${t.message}")
false
} finally {
try {
cursor?.close()
} catch (t: Throwable) {
}
}
//2. Check File Exist
//如果系统 db 存有 Uri 相关记录, 但是文件失效或者损坏 (If the system db has Uri related records, but the file is invalid or damaged)
return isUriExist && checkFileExistByUri(uri, resolver)
}
/**
* check file exist
* @return true exist
*/
fun checkFileExistByUri(uri: Uri, resolver: ContentResolver): Boolean {
var ins: InputStream? = null
val isFileExist: Boolean = try {
ins = resolver.openInputStream(uri)
// file exists
true
} catch (t: Throwable) {
// File was not found eg: open failed: ENOENT (No such file or directory)
Timber.e("2. Check File Exist Error: ${t.message}")
false
} finally {
try {
ins?.close()
} catch (t: Throwable) {
}
}
return isFileExist
}
/**
* ### 路径分割
*
* ```
* eg:
* srcPath=/storage/emulated/0/Movies/myVideo.mp4 path=/storage/emulated/0/Movies name=myVideo suffix=mp4 nameSuffix=myVideo.mp4
*
* /xxx/xxx/note.txt -> path: /xxx/xxx name: note suffix: txt
* ///note.txt -> path: /// name: note suffix: txt
* /note.txt -> path: "" name: note suffix: txt
* note.txt -> path: "" name: note suffix: txt
* ```
*/
fun splitFilePath(
srcPath: String?,
nameSplit: Char = '/',
suffixSplit: Char = '.',
block: ((path: String, name: String, suffix: String, nameSuffix: String) -> Unit)? = null,
) {
if (srcPath.isNullOrBlank()) return
val cut = srcPath.lastIndexOf(nameSplit)
// /xxx/xxx/note.txt +0: /xxx/xxx +1: /xxx/xxx/
val path = if (cut == -1) "" else srcPath.substring(0, cut)
val nameSuffix = if (cut == -1) srcPath else srcPath.substring(cut + 1)
val dot = nameSuffix.lastIndexOf(suffixSplit)
if (dot != -1) {
val suffix = nameSuffix.substring((dot + 1)).lowercase(Locale.getDefault())
val name = nameSuffix.substring(0, dot)
Timber.d("splitFilePath srcPath=$srcPath path=$path name=$name suffix=$suffix nameSuffix=$nameSuffix")
block?.invoke(path, name, suffix, nameSuffix)
}
}
/**
* abc.jpg -> jpg
*/
fun getFileNameSuffix(path: String): String {
var nameSuffix = path
splitFilePath(srcPath = path) { _: String, _: String, suffix: String, _: String ->
nameSuffix = suffix
}
return nameSuffix
}
/**
* /storage/emulated/0/Movies/myVideo.mp4 -> /storage/emulated/0/Movies
*/
fun getFilePathFromFullPath(path: String?, split: Char = '/'): String? {
if (path.isNullOrBlank()) return null
val cut = path.lastIndexOf(split)
// (cut+1): /storage/emulated/0/Movies/
if (cut != -1) return path.substring(0, cut)
return path
}
/**
* /storage/emulated/0/Movies/myVideo.mp4 -> myVideo.mp4
*/
fun getFileNameFromPath(path: String?, split: Char = '/'): String? {
if (path.isNullOrBlank()) return null
val cut = path.lastIndexOf(split)
if (cut != -1) return path.substring(cut + 1)
return path
}
/**
* /storage/emulated/0/Movies/myVideo.mp4 -> myVideo.mp4
*/
fun getFileNameFromUri(uri: Uri?): String? =
uri?.use {
var filename: String? = null
val resolver = DuaContext.context.contentResolver
val mimeType = resolver.getType(uri)
if (mimeType == null) {
filename = getFileNameFromPath(FileUri.getPathByUri(uri))
} else {
resolver.query(uri, null, null, null, null)?.use { c: Cursor ->
val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
if (c.moveToFirst()) filename = c.getString(nameIndex)
}
}
filename
}
}
Loading…
Cancel
Save