parent
7ee1347ab4
commit
2a92321785
@ -0,0 +1,44 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one |
||||
* or more contributor license agreements. See the NOTICE file |
||||
* distributed with this work for additional information |
||||
* regarding copyright ownership. The ASF licenses this file |
||||
* to you under the Apache License, Version 2.0 (the |
||||
* "License"); you may not use this file except in compliance |
||||
* with the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.arialyy.aria.core.command; |
||||
|
||||
import com.arialyy.aria.core.download.AbsGroupTaskWrapper; |
||||
import com.arialyy.aria.core.task.ITask; |
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
||||
|
||||
public class CmdHelper { |
||||
/** |
||||
* 创建任务命令 |
||||
* |
||||
* @param taskType {@link ITask#DOWNLOAD}、{@link ITask#DOWNLOAD_GROUP}、{@link ITask#UPLOAD} |
||||
*/ |
||||
public static <T extends AbsTaskWrapper> AbsNormalCmd createNormalCmd(T entity, int cmd, |
||||
int taskType) { |
||||
return NormalCmdFactory.getInstance().createCmd(entity, cmd, taskType); |
||||
} |
||||
|
||||
/** |
||||
* 创建任务组命令 |
||||
* |
||||
* @param childUrl 子任务url |
||||
*/ |
||||
public static <T extends AbsGroupTaskWrapper> AbsGroupCmd createGroupCmd(T entity, int cmd, |
||||
String childUrl) { |
||||
return GroupCmdFactory.getInstance().createCmd(entity, cmd, childUrl); |
||||
} |
||||
} |
@ -1,457 +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.common; |
||||
|
||||
import com.arialyy.aria.core.config.Configuration; |
||||
import com.arialyy.aria.core.download.DTaskWrapper; |
||||
import com.arialyy.aria.core.download.DownloadEntity; |
||||
import com.arialyy.aria.core.download.m3u8.BaseM3U8Loader; |
||||
import com.arialyy.aria.core.inf.AbsNormalEntity; |
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper; |
||||
import com.arialyy.aria.core.inf.ITaskWrapper; |
||||
import com.arialyy.aria.core.upload.UploadEntity; |
||||
import com.arialyy.aria.orm.DbEntity; |
||||
import com.arialyy.aria.util.ALog; |
||||
import com.arialyy.aria.util.CommonUtil; |
||||
import com.arialyy.aria.util.DbDataHelper; |
||||
import com.arialyy.aria.util.FileUtil; |
||||
import com.arialyy.aria.util.RecordUtil; |
||||
import java.io.File; |
||||
import java.util.ArrayList; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Properties; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* 处理任务记录,分配线程区间 |
||||
*/ |
||||
public class RecordHandler { |
||||
private final String TAG = "RecordHandler"; |
||||
|
||||
public static final int TYPE_DOWNLOAD = 1; |
||||
public static final int TYPE_UPLOAD = 2; |
||||
public static final int TYPE_M3U8_VOD = 3; |
||||
public static final int TYPE_M3U8_LIVE = 4; |
||||
|
||||
private static final String STATE = "_state_"; |
||||
private static final String RECORD = "_record_"; |
||||
/** |
||||
* 小于1m的文件不启用多线程 |
||||
*/ |
||||
private static final long SUB_LEN = 1024 * 1024; |
||||
|
||||
/** |
||||
* 分块文件路径 |
||||
*/ |
||||
public static final String SUB_PATH = "%s.%s.part"; |
||||
|
||||
@Deprecated private File mConfigFile; |
||||
private TaskRecord mTaskRecord; |
||||
private AbsTaskWrapper mTaskWrapper; |
||||
private AbsNormalEntity mEntity; |
||||
|
||||
RecordHandler(AbsTaskWrapper wrapper) { |
||||
mTaskWrapper = wrapper; |
||||
mEntity = (AbsNormalEntity) mTaskWrapper.getEntity(); |
||||
} |
||||
|
||||
/** |
||||
* 获取任务记录,如果任务记录存在,检查任务记录 |
||||
* 检查记录 对于分块任务: 子分块不存在或被删除,子线程将重新下载 |
||||
* 对于普通任务: 预下载文件不存在,则任务任务呗删除 |
||||
* 如果任务记录不存在或线程记录不存在,初始化记录 |
||||
* |
||||
* @return 任务记录 |
||||
*/ |
||||
TaskRecord getRecord() { |
||||
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName())); |
||||
if (mConfigFile.exists()) { |
||||
convertDb(); |
||||
} else { |
||||
mTaskRecord = DbDataHelper.getTaskRecord(getFilePath()); |
||||
if (mTaskRecord == null) { |
||||
initRecord(true); |
||||
} else { |
||||
if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.isEmpty()) { |
||||
initRecord(false); |
||||
} |
||||
|
||||
if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) { |
||||
handleM3U8Record(); |
||||
} else if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) { |
||||
ALog.i(TAG, "直播下载不处理历史记录"); |
||||
} else { |
||||
if (mTaskRecord.isBlock) { |
||||
handleBlockRecord(); |
||||
} else if (!mTaskWrapper.isSupportBP()) { |
||||
handleNoSupportBPRecord(); |
||||
} else if (!mTaskRecord.isBlock && mTaskRecord.threadNum > 1) { |
||||
handleNoBlockMultiThreadRecord(); |
||||
} else { |
||||
handleSingleThreadRecord(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
saveRecord(); |
||||
return mTaskRecord; |
||||
} |
||||
|
||||
/** |
||||
* 处理m3u8记录, |
||||
* 1、如果分片文件存在,并且分片文件的记录没有完成,则需要删除该分片文件 |
||||
* 2、如果记录显示已完成,但是分片文件不存在,则重新开始该分片 |
||||
* 3、如果记录显示已完成,并且文件存在,记录当前任务进度 |
||||
*/ |
||||
private void handleM3U8Record() { |
||||
DTaskWrapper wrapper = (DTaskWrapper) mTaskWrapper; |
||||
String cacheDir = wrapper.asM3U8().getCacheDir(); |
||||
long currentProgress = 0; |
||||
int completeNum = 0; |
||||
for (ThreadRecord record : mTaskRecord.threadRecords) { |
||||
File temp = new File(BaseM3U8Loader.getTsFilePath(cacheDir, record.threadId)); |
||||
if (!record.isComplete) { |
||||
if (temp.exists()) { |
||||
temp.delete(); |
||||
} |
||||
record.startLocation = 0; |
||||
//ALog.d(TAG, String.format("分片【%s】未完成,将重新下载该分片", record.threadId));
|
||||
} else { |
||||
if (!temp.exists()) { |
||||
record.startLocation = 0; |
||||
record.isComplete = false; |
||||
ALog.w(TAG, String.format("分片【%s】不存在,将重新下载该分片", record.threadId)); |
||||
} else { |
||||
completeNum++; |
||||
currentProgress += temp.length(); |
||||
} |
||||
} |
||||
} |
||||
wrapper.asM3U8().setCompleteNum(completeNum); |
||||
wrapper.getEntity().setCurrentProgress(currentProgress); |
||||
mTaskRecord.bandWidth = wrapper.asM3U8().getBandWidth(); |
||||
} |
||||
|
||||
/** |
||||
* 处理不支持断点的记录 |
||||
*/ |
||||
private void handleNoSupportBPRecord() { |
||||
ThreadRecord tr = mTaskRecord.threadRecords.get(0); |
||||
tr.startLocation = 0; |
||||
tr.endLocation = mEntity.getFileSize(); |
||||
tr.taskKey = mTaskRecord.filePath; |
||||
tr.blockLen = tr.endLocation; |
||||
tr.isComplete = false; |
||||
} |
||||
|
||||
/** |
||||
* 处理为不分块的多线程任务 |
||||
*/ |
||||
private void handleNoBlockMultiThreadRecord() { |
||||
File file = new File(mTaskRecord.filePath); |
||||
if (!file.exists()) { |
||||
ALog.w(TAG, String.format("文件【%s】不存在,重新分配线程区间", mTaskRecord.filePath)); |
||||
DbEntity.deleteData(ThreadRecord.class, "taskKey=?", mTaskRecord.filePath); |
||||
initRecord(false); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 处理单线程的任务的记录 |
||||
*/ |
||||
private void handleSingleThreadRecord() { |
||||
File file = new File(mTaskRecord.filePath); |
||||
ThreadRecord tr = mTaskRecord.threadRecords.get(0); |
||||
if (!file.exists()) { |
||||
ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath())); |
||||
tr.startLocation = 0; |
||||
tr.isComplete = false; |
||||
tr.endLocation = mEntity.getFileSize(); |
||||
} else if (mTaskRecord.isOpenDynamicFile) { |
||||
if (file.length() > mEntity.getFileSize()) { |
||||
ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath())); |
||||
file.delete(); |
||||
tr.startLocation = 0; |
||||
tr.isComplete = false; |
||||
tr.endLocation = mEntity.getFileSize(); |
||||
} else if (file.length() == mEntity.getFileSize()) { |
||||
tr.isComplete = true; |
||||
} else { |
||||
if (file.length() != tr.startLocation) { |
||||
ALog.i(TAG, String.format("修正【%s】的进度记录为:%s", file.getPath(), file.length())); |
||||
tr.startLocation = file.length(); |
||||
tr.isComplete = false; |
||||
} |
||||
} |
||||
} |
||||
mTaskWrapper.setNewTask(false); |
||||
} |
||||
|
||||
/** |
||||
* 处理分块任务的记录,分块文件(blockFileLen)长度必须需要小于等于线程区间(threadRectLen)的长度 |
||||
*/ |
||||
private void handleBlockRecord() { |
||||
// 默认线程分块长度
|
||||
long normalRectLen = mEntity.getFileSize() / mTaskRecord.threadRecords.size(); |
||||
for (ThreadRecord tr : mTaskRecord.threadRecords) { |
||||
long threadRect = tr.blockLen; |
||||
|
||||
File temp = new File(String.format(SUB_PATH, mTaskRecord.filePath, tr.threadId)); |
||||
if (!temp.exists()) { |
||||
ALog.i(TAG, String.format("分块文件【%s】不存在,该分块将重新开始", temp.getPath())); |
||||
tr.isComplete = false; |
||||
tr.startLocation = tr.threadId * normalRectLen; |
||||
} else { |
||||
if (!tr.isComplete) { |
||||
ALog.i(TAG, String.format( |
||||
"startLocation = %s; endLocation = %s; block = %s; tempLen = %s; threadId = %s", |
||||
tr.startLocation, tr.endLocation, threadRect, temp.length(), tr.threadId)); |
||||
|
||||
long blockFileLen = temp.length(); // 磁盘中的分块文件长度
|
||||
/* |
||||
* 检查磁盘中的分块文件 |
||||
*/ |
||||
if (blockFileLen > threadRect) { |
||||
ALog.i(TAG, String.format("分块【%s】错误,分块长度【%s】 > 线程区间长度【%s】,将重新开始该分块", |
||||
tr.threadId, blockFileLen, threadRect)); |
||||
temp.delete(); |
||||
tr.startLocation = tr.threadId * threadRect; |
||||
continue; |
||||
} |
||||
|
||||
long realLocation = |
||||
tr.threadId * normalRectLen + blockFileLen; //正常情况下,该线程的startLocation的位置
|
||||
/* |
||||
* 检查记录文件 |
||||
*/ |
||||
if (blockFileLen == threadRect) { |
||||
ALog.i(TAG, String.format("分块【%s】已完成,更新记录", temp.getPath())); |
||||
tr.startLocation = blockFileLen; |
||||
tr.isComplete = true; |
||||
} else if (tr.startLocation != realLocation) { // 处理记录小于分块文件长度的情况
|
||||
ALog.i(TAG, String.format("修正分块【%s】的进度记录为:%s", temp.getPath(), realLocation)); |
||||
tr.startLocation = realLocation; |
||||
} |
||||
} else { |
||||
ALog.i(TAG, String.format("分块【%s】已完成", temp.getPath())); |
||||
} |
||||
} |
||||
} |
||||
mTaskWrapper.setNewTask(false); |
||||
} |
||||
|
||||
/** |
||||
* convertDb 是兼容性代码 从3.4.1开始,线程配置信息将存储在数据库中。 将配置文件的内容复制到数据库中,并将配置文件删除 |
||||
*/ |
||||
private void convertDb() { |
||||
List<RecordWrapper> records = |
||||
DbEntity.findRelationData(RecordWrapper.class, "TaskRecord.filePath=?", |
||||
getFilePath()); |
||||
if (records == null || records.size() == 0) { |
||||
Properties pro = FileUtil.loadConfig(mConfigFile); |
||||
if (pro.isEmpty()) { |
||||
ALog.d(TAG, "老版本的线程记录为空,任务为新任务"); |
||||
initRecord(true); |
||||
return; |
||||
} |
||||
|
||||
Set<Object> keys = pro.keySet(); |
||||
// 老版本记录是5s存一次,但是5s中内,如果线程执行完成,record记录是没有的,只有state记录...
|
||||
// 第一步应该是record 和 state去重取正确的线程数
|
||||
Set<Integer> set = new HashSet<>(); |
||||
for (Object key : keys) { |
||||
String str = String.valueOf(key); |
||||
int i = Integer.parseInt(str.substring(str.length() - 1)); |
||||
set.add(i); |
||||
} |
||||
int threadNum = set.size(); |
||||
if (threadNum == 0) { |
||||
ALog.d(TAG, "线程数为空,任务为新任务"); |
||||
initRecord(true); |
||||
return; |
||||
} |
||||
mTaskWrapper.setNewTask(false); |
||||
mTaskRecord = createTaskRecord(threadNum); |
||||
mTaskRecord.isOpenDynamicFile = false; |
||||
mTaskRecord.isBlock = false; |
||||
File tempFile = new File(getFilePath()); |
||||
for (int i = 0; i < threadNum; i++) { |
||||
ThreadRecord tRecord = new ThreadRecord(); |
||||
tRecord.taskKey = mTaskRecord.filePath; |
||||
Object state = pro.getProperty(tempFile.getName() + STATE + i); |
||||
Object record = pro.getProperty(tempFile.getName() + RECORD + i); |
||||
if (state != null && Integer.parseInt(String.valueOf(state)) == 1) { |
||||
tRecord.isComplete = true; |
||||
continue; |
||||
} |
||||
if (record != null) { |
||||
long temp = Long.parseLong(String.valueOf(record)); |
||||
tRecord.startLocation = temp > 0 ? temp : 0; |
||||
} else { |
||||
tRecord.startLocation = 0; |
||||
} |
||||
mTaskRecord.threadRecords.add(tRecord); |
||||
} |
||||
mConfigFile.delete(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 初始化任务记录,分配线程区间 |
||||
* |
||||
* @param newRecord {@code true} 需要创建新{@link TaskRecord} |
||||
*/ |
||||
private void initRecord(boolean newRecord) { |
||||
if (newRecord) { |
||||
mTaskRecord = createTaskRecord(getNewTaskThreadNum()); |
||||
} |
||||
mTaskWrapper.setNewTask(true); |
||||
int requestType = mTaskWrapper.getRequestType(); |
||||
if (requestType == ITaskWrapper.M3U8_LIVE) { |
||||
return; |
||||
} |
||||
long blockSize = mEntity.getFileSize() / mTaskRecord.threadNum; |
||||
// 处理线程区间记录
|
||||
for (int i = 0; i < mTaskRecord.threadNum; i++) { |
||||
long startL = i * blockSize, endL = (i + 1) * blockSize; |
||||
ThreadRecord tr; |
||||
tr = new ThreadRecord(); |
||||
tr.taskKey = mTaskRecord.filePath; |
||||
tr.threadId = i; |
||||
tr.startLocation = startL; |
||||
tr.isComplete = false; |
||||
if (requestType == ITaskWrapper.M3U8_VOD) { |
||||
tr.startLocation = 0; |
||||
tr.threadType = TaskRecord.TYPE_M3U8_VOD; |
||||
tr.tsUrl = ((DTaskWrapper) mTaskWrapper).asM3U8().getUrls().get(i); |
||||
} else { |
||||
tr.threadType = TaskRecord.TYPE_HTTP_FTP; |
||||
//最后一个线程的结束位置即为文件的总长度
|
||||
if (i == (mTaskRecord.threadNum - 1)) { |
||||
endL = mEntity.getFileSize(); |
||||
} |
||||
tr.endLocation = endL; |
||||
tr.blockLen = RecordUtil.getBlockLen(mEntity.getFileSize(), i, mTaskRecord.threadNum); |
||||
} |
||||
mTaskRecord.threadRecords.add(tr); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 创建任务记录 |
||||
* |
||||
* @param threadNum 线程总数 |
||||
*/ |
||||
private TaskRecord createTaskRecord(int threadNum) { |
||||
TaskRecord record = new TaskRecord(); |
||||
record.fileName = mEntity.getFileName(); |
||||
record.filePath = getFilePath(); |
||||
record.threadRecords = new ArrayList<>(); |
||||
record.threadNum = threadNum; |
||||
int requestType = mTaskWrapper.getRequestType(); |
||||
if (requestType == ITaskWrapper.M3U8_VOD) { |
||||
record.taskType = TaskRecord.TYPE_M3U8_VOD; |
||||
record.isOpenDynamicFile = true; |
||||
record.bandWidth = ((DTaskWrapper)mTaskWrapper).asM3U8().getBandWidth(); |
||||
} else if (requestType == ITaskWrapper.M3U8_LIVE) { |
||||
record.taskType = TaskRecord.TYPE_M3U8_LIVE; |
||||
record.isOpenDynamicFile = true; |
||||
record.bandWidth = ((DTaskWrapper)mTaskWrapper).asM3U8().getBandWidth(); |
||||
} else { |
||||
if (getRecordType() == TYPE_DOWNLOAD) { |
||||
record.isBlock = threadNum > 1 && Configuration.getInstance().downloadCfg.isUseBlock(); |
||||
// 线程数为1,或者使用了分块,则认为是使用动态长度文件
|
||||
record.isOpenDynamicFile = threadNum == 1 || record.isBlock; |
||||
} else { |
||||
record.isBlock = false; |
||||
} |
||||
record.taskType = TaskRecord.TYPE_HTTP_FTP; |
||||
record.isGroupRecord = mEntity.isGroupChild(); |
||||
if (record.isGroupRecord) { |
||||
if (mEntity instanceof DownloadEntity) { |
||||
record.dGroupHash = ((DownloadEntity) mEntity).getGroupHash(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return record; |
||||
} |
||||
|
||||
/** |
||||
* 保存任务记录 |
||||
*/ |
||||
private void saveRecord() { |
||||
mTaskRecord.threadNum = mTaskRecord.threadRecords.size(); |
||||
mTaskRecord.save(); |
||||
if (mTaskRecord.threadRecords != null && !mTaskRecord.threadRecords.isEmpty()) { |
||||
DbEntity.saveAll(mTaskRecord.threadRecords); |
||||
} |
||||
ALog.d(TAG, String.format("保存记录,线程记录数:%s", mTaskRecord.threadRecords.size())); |
||||
} |
||||
|
||||
/** |
||||
* 获取记录类型 |
||||
* |
||||
* @return {@link #TYPE_DOWNLOAD}、{@link #TYPE_UPLOAD} |
||||
*/ |
||||
private int getRecordType() { |
||||
if (mEntity instanceof DownloadEntity) { |
||||
return TYPE_DOWNLOAD; |
||||
} else { |
||||
return TYPE_UPLOAD; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取任务路径 |
||||
* |
||||
* @return 任务文件路径 |
||||
*/ |
||||
private String getFilePath() { |
||||
if (mEntity instanceof DownloadEntity) { |
||||
return ((DownloadEntity) mTaskWrapper.getEntity()).getFilePath(); |
||||
} else { |
||||
return ((UploadEntity) mTaskWrapper.getEntity()).getFilePath(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 小于1m的文件或是任务组的子任务、线程数强制为1 |
||||
* 不支持断点或chunked模式的线程数都为,线程数强制为1 |
||||
*/ |
||||
private int getNewTaskThreadNum() { |
||||
if (getRecordType() == TYPE_DOWNLOAD) { |
||||
if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) { |
||||
return ((DTaskWrapper) mTaskWrapper).asM3U8().getUrls().size(); |
||||
} |
||||
if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) { |
||||
return 1; |
||||
} |
||||
if (!mTaskWrapper.isSupportBP() || mTaskWrapper.asHttp().isChunked()) { |
||||
return 1; |
||||
} |
||||
int threadNum = Configuration.getInstance().downloadCfg.getThreadNum(); |
||||
return mEntity.getFileSize() <= SUB_LEN |
||||
|| mEntity.isGroupChild() |
||||
|| threadNum == 1 |
||||
? 1 |
||||
: threadNum; |
||||
} else { |
||||
return 1; |
||||
} |
||||
} |
||||
} |
@ -1,129 +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.download.downloader; |
||||
|
||||
import com.arialyy.aria.core.common.AbsThreadTask; |
||||
import com.arialyy.aria.core.common.NormalFileer; |
||||
import com.arialyy.aria.core.common.RecordHandler; |
||||
import com.arialyy.aria.core.common.SubThreadConfig; |
||||
import com.arialyy.aria.core.download.DTaskWrapper; |
||||
import com.arialyy.aria.core.download.DownloadEntity; |
||||
import com.arialyy.aria.core.event.Event; |
||||
import com.arialyy.aria.core.event.SpeedEvent; |
||||
import com.arialyy.aria.core.inf.IDownloadListener; |
||||
import com.arialyy.aria.core.inf.ITaskWrapper; |
||||
import com.arialyy.aria.exception.BaseException; |
||||
import com.arialyy.aria.exception.TaskException; |
||||
import com.arialyy.aria.util.ALog; |
||||
import com.arialyy.aria.util.BufferedRandomAccessFile; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Created by AriaL on 2017/7/1. 文件下载器 |
||||
*/ |
||||
public class Downloader extends NormalFileer<DownloadEntity, DTaskWrapper> { |
||||
private String TAG = "Downloader"; |
||||
|
||||
public Downloader(IDownloadListener listener, DTaskWrapper taskWrapper) { |
||||
super(listener, taskWrapper); |
||||
mTempFile = new File(mEntity.getFilePath()); |
||||
setUpdateInterval(taskWrapper.getConfig().getUpdateInterval()); |
||||
} |
||||
|
||||
@Override protected boolean handleNewTask() { |
||||
if (!mRecord.isBlock) { |
||||
if (mTempFile.exists()) { |
||||
mTempFile.delete(); |
||||
} |
||||
//CommonUtil.createFile(mTempFile.getPath());
|
||||
} else { |
||||
for (int i = 0; i < mTotalThreadNum; i++) { |
||||
File blockFile = new File(String.format(RecordHandler.SUB_PATH, mTempFile.getPath(), i)); |
||||
if (blockFile.exists()) { |
||||
ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i)); |
||||
blockFile.delete(); |
||||
} |
||||
} |
||||
} |
||||
BufferedRandomAccessFile file = null; |
||||
try { |
||||
if (mTotalThreadNum > 1 && !mRecord.isBlock) { |
||||
file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192); |
||||
//设置文件长度
|
||||
file.setLength(mEntity.getFileSize()); |
||||
} |
||||
return true; |
||||
} catch (IOException e) { |
||||
failDownload(new TaskException(TAG, |
||||
String.format("下载失败,filePath: %s, url: %s", mEntity.getDownloadPath(), |
||||
mEntity.getUrl()), e)); |
||||
} finally { |
||||
if (file != null) { |
||||
try { |
||||
file.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 如果使用"Content-Disposition"中的文件名,需要更新{@link #mTempFile}的路径 |
||||
*/ |
||||
void updateTempFile() { |
||||
if (!mTempFile.getPath().equals(mEntity.getFilePath())) { |
||||
if (!mTempFile.exists()) { |
||||
mTempFile = new File(mEntity.getFilePath()); |
||||
} else { |
||||
boolean b = mTempFile.renameTo(new File(mEntity.getDownloadPath())); |
||||
ALog.d(TAG, String.format("更新tempFile文件名%s", b ? "成功" : "失败")); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Event |
||||
public void setMaxSpeed(SpeedEvent event) { |
||||
setMaxSpeed(event.speed); |
||||
} |
||||
|
||||
@Override protected void onPostPre() { |
||||
super.onPostPre(); |
||||
((IDownloadListener) mListener).onPostPre(mEntity.getFileSize()); |
||||
File file = new File(mEntity.getDownloadPath()); |
||||
if (!file.getParentFile().exists()) { |
||||
file.getParentFile().mkdirs(); |
||||
} |
||||
} |
||||
|
||||
@Override protected AbsThreadTask selectThreadTask(SubThreadConfig<DTaskWrapper> config) { |
||||
switch (mTaskWrapper.getRequestType()) { |
||||
case ITaskWrapper.D_FTP: |
||||
case ITaskWrapper.D_FTP_DIR: |
||||
return new FtpThreadTask(config); |
||||
case ITaskWrapper.D_HTTP: |
||||
return new HttpThreadTask(config); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private void failDownload(BaseException e) { |
||||
closeTimer(); |
||||
mListener.onFail(false, e); |
||||
} |
||||
} |
@ -1,140 +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.download.downloader; |
||||
|
||||
import com.arialyy.aria.core.common.CompleteInfo; |
||||
import com.arialyy.aria.core.common.IUtil; |
||||
import com.arialyy.aria.core.common.OnFileInfoCallback; |
||||
import com.arialyy.aria.core.download.DTaskWrapper; |
||||
import com.arialyy.aria.core.inf.AbsEntity; |
||||
import com.arialyy.aria.core.inf.IDownloadListener; |
||||
import com.arialyy.aria.core.inf.ITaskWrapper; |
||||
import com.arialyy.aria.exception.BaseException; |
||||
|
||||
/** |
||||
* Created by lyy on 2015/8/25. |
||||
* D_HTTP\FTP单任务下载工具 |
||||
*/ |
||||
public class SimpleDownloadUtil implements IUtil { |
||||
private String TAG = "SimpleDownloadUtil"; |
||||
private IDownloadListener mListener; |
||||
private Downloader mDownloader; |
||||
private DTaskWrapper mTaskWrapper; |
||||
private boolean isStop = false, isCancel = false; |
||||
|
||||
public SimpleDownloadUtil(DTaskWrapper wrapper, IDownloadListener downloadListener) { |
||||
mTaskWrapper = wrapper; |
||||
mListener = downloadListener; |
||||
mDownloader = new Downloader(downloadListener, wrapper); |
||||
} |
||||
|
||||
@Override public String getKey() { |
||||
return mTaskWrapper.getKey(); |
||||
} |
||||
|
||||
@Override public long getFileSize() { |
||||
return mDownloader.getFileSize(); |
||||
} |
||||
|
||||
/** |
||||
* 获取当前下载位置 |
||||
*/ |
||||
@Override public long getCurrentLocation() { |
||||
return mDownloader.getCurrentLocation(); |
||||
} |
||||
|
||||
@Override public boolean isRunning() { |
||||
return mDownloader.isRunning(); |
||||
} |
||||
|
||||
/** |
||||
* 取消下载 |
||||
*/ |
||||
@Override public void cancel() { |
||||
isCancel = true; |
||||
mDownloader.cancel(); |
||||
} |
||||
|
||||
/** |
||||
* 停止下载 |
||||
*/ |
||||
@Override public void stop() { |
||||
isStop = true; |
||||
mDownloader.stop(); |
||||
} |
||||
|
||||
/** |
||||
* 多线程断点续传下载文件,开始下载 |
||||
*/ |
||||
@Override public void start() { |
||||
if (isStop || isCancel) { |
||||
return; |
||||
} |
||||
mListener.onPre(); |
||||
// 如果网址没有变,而服务器端端文件改变,以下代码就没有用了
|
||||
//if (mTaskWrapper.getEntity().getFileSize() <= 1
|
||||
// || mTaskWrapper.isRefreshInfo()
|
||||
// || mTaskWrapper.getRequestType() == AbsTaskWrapper.D_FTP
|
||||
// || mTaskWrapper.getState() == IEntity.STATE_FAIL) {
|
||||
// new Thread(createInfoThread()).create();
|
||||
//} else {
|
||||
// mDownloader.create();
|
||||
//}
|
||||
new Thread(createInfoThread()).start(); |
||||
} |
||||
|
||||
private void failDownload(BaseException e, boolean needRetry) { |
||||
if (isStop || isCancel) { |
||||
return; |
||||
} |
||||
mListener.onFail(needRetry, e); |
||||
mDownloader.onDestroy(); |
||||
} |
||||
|
||||
/** |
||||
* 通过链接类型创建不同的获取文件信息的线程 |
||||
*/ |
||||
private Runnable createInfoThread() { |
||||
switch (mTaskWrapper.getRequestType()) { |
||||
case ITaskWrapper.D_FTP: |
||||
return new FtpFileInfoThread(mTaskWrapper, new OnFileInfoCallback() { |
||||
@Override public void onComplete(String url, CompleteInfo info) { |
||||
mDownloader.updateTempFile(); |
||||
mDownloader.start(); |
||||
} |
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { |
||||
failDownload(e, needRetry); |
||||
mDownloader.closeTimer(); |
||||
} |
||||
}); |
||||
case ITaskWrapper.D_HTTP: |
||||
return new HttpFileInfoThread(mTaskWrapper, new OnFileInfoCallback() { |
||||
@Override public void onComplete(String url, CompleteInfo info) { |
||||
mDownloader.updateTempFile(); |
||||
mDownloader.start(); |
||||
} |
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { |
||||
failDownload(e, needRetry); |
||||
mDownloader.closeTimer(); |
||||
} |
||||
}); |
||||
} |
||||
return null; |
||||
} |
||||
} |
@ -1,133 +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.download.group; |
||||
|
||||
import android.os.Handler; |
||||
import com.arialyy.aria.core.common.CompleteInfo; |
||||
import com.arialyy.aria.core.common.IUtil; |
||||
import com.arialyy.aria.core.common.OnFileInfoCallback; |
||||
import com.arialyy.aria.core.download.DTaskWrapper; |
||||
import com.arialyy.aria.core.download.DownloadEntity; |
||||
import com.arialyy.aria.core.download.downloader.Downloader; |
||||
import com.arialyy.aria.core.download.downloader.HttpFileInfoThread; |
||||
import com.arialyy.aria.core.inf.AbsEntity; |
||||
import com.arialyy.aria.core.inf.ITaskWrapper; |
||||
import com.arialyy.aria.core.scheduler.ISchedulers; |
||||
import com.arialyy.aria.exception.BaseException; |
||||
import com.arialyy.aria.util.ALog; |
||||
|
||||
/** |
||||
* 子任务下载器,负责创建{@link Downloader} |
||||
*/ |
||||
class SubDLoadUtil implements IUtil { |
||||
private final String TAG = "SubDownloadLoader"; |
||||
|
||||
private Downloader mDownloader; |
||||
private DTaskWrapper mWrapper; |
||||
private Handler mSchedulers; |
||||
private ChildDLoadListener mListener; |
||||
private boolean needGetInfo; |
||||
|
||||
/** |
||||
* @param schedulers 调度器 |
||||
* @param needGetInfo {@code true} 需要获取文件信息。{@code false} 不需要获取文件信息 |
||||
*/ |
||||
SubDLoadUtil(Handler schedulers, DTaskWrapper taskWrapper, boolean needGetInfo) { |
||||
mWrapper = taskWrapper; |
||||
mSchedulers = schedulers; |
||||
this.needGetInfo = needGetInfo; |
||||
mListener = new ChildDLoadListener(mSchedulers, SubDLoadUtil.this); |
||||
} |
||||
|
||||
@Override public String getKey() { |
||||
return mWrapper.getKey(); |
||||
} |
||||
|
||||
public DTaskWrapper getWrapper() { |
||||
return mWrapper; |
||||
} |
||||
|
||||
public DownloadEntity getEntity() { |
||||
return mWrapper.getEntity(); |
||||
} |
||||
|
||||
/** |
||||
* 重新开始任务 |
||||
*/ |
||||
void reStart() { |
||||
if (mDownloader != null) { |
||||
mDownloader.retryTask(); |
||||
} |
||||
} |
||||
|
||||
public Downloader getDownloader() { |
||||
return mDownloader; |
||||
} |
||||
|
||||
@Override public long getFileSize() { |
||||
return mDownloader == null ? -1 : mDownloader.getFileSize(); |
||||
} |
||||
|
||||
@Override public long getCurrentLocation() { |
||||
return mDownloader == null ? -1 : mDownloader.getCurrentLocation(); |
||||
} |
||||
|
||||
@Override public boolean isRunning() { |
||||
return mDownloader != null && mDownloader.isRunning(); |
||||
} |
||||
|
||||
@Override public void cancel() { |
||||
if (mDownloader != null && isRunning()) { |
||||
mDownloader.cancel(); |
||||
} else { |
||||
mSchedulers.obtainMessage(ISchedulers.CANCEL, this).sendToTarget(); |
||||
} |
||||
} |
||||
|
||||
@Override public void stop() { |
||||
if (mDownloader != null && isRunning()) { |
||||
mDownloader.stop(); |
||||
} else { |
||||
mSchedulers.obtainMessage(ISchedulers.STOP, this).sendToTarget(); |
||||
} |
||||
} |
||||
|
||||
@Override public void start() { |
||||
if (mWrapper.getRequestType() == ITaskWrapper.D_HTTP) { |
||||
if (needGetInfo) { |
||||
new Thread(new HttpFileInfoThread(mWrapper, new OnFileInfoCallback() { |
||||
|
||||
@Override public void onComplete(String url, CompleteInfo info) { |
||||
mDownloader = new Downloader(mListener, mWrapper); |
||||
mDownloader.start(); |
||||
} |
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { |
||||
mSchedulers.obtainMessage(ISchedulers.FAIL, SubDLoadUtil.this).sendToTarget(); |
||||
} |
||||
})).start(); |
||||
} else { |
||||
mDownloader = new Downloader(mListener, mWrapper); |
||||
mDownloader.start(); |
||||
} |
||||
} else if (mWrapper.getRequestType() == ITaskWrapper.D_FTP) { |
||||
mDownloader = new Downloader(mListener, mWrapper); |
||||
mDownloader.start(); |
||||
} else { |
||||
ALog.w(TAG, String.format("不识别的类型,requestType:%s", mWrapper.getRequestType())); |
||||
} |
||||
} |
||||
} |
@ -1,145 +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.download.m3u8; |
||||
|
||||
import android.text.TextUtils; |
||||
import com.arialyy.aria.core.common.CompleteInfo; |
||||
import com.arialyy.aria.core.common.IUtil; |
||||
import com.arialyy.aria.core.common.OnFileInfoCallback; |
||||
import com.arialyy.aria.core.download.DTaskWrapper; |
||||
import com.arialyy.aria.core.download.M3U8Listener; |
||||
import com.arialyy.aria.core.inf.AbsEntity; |
||||
import com.arialyy.aria.exception.BaseException; |
||||
import com.arialyy.aria.exception.M3U8Exception; |
||||
import java.io.File; |
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* M3U8点播文件下载工具 |
||||
* 工作流程: |
||||
* 1、创建一个和文件同父路径并且同名隐藏文件夹 |
||||
* 2、将所有m3u8的ts文件下载到该文件夹中 |
||||
* 3、完成所有分片下载后,合并ts文件 |
||||
* 4、删除该隐藏文件夹 |
||||
*/ |
||||
public class M3U8VodUtil implements IUtil { |
||||
private final String TAG = "M3U8DownloadUtil"; |
||||
|
||||
private DTaskWrapper mWrapper; |
||||
private M3U8Listener mListener; |
||||
private boolean isStop = false, isCancel = false; |
||||
private List<String> mUrls = new ArrayList<>(); |
||||
private M3U8VodLoader mLoader; |
||||
|
||||
public M3U8VodUtil(DTaskWrapper wrapper, M3U8Listener listener) { |
||||
mWrapper = wrapper; |
||||
mListener = listener; |
||||
mLoader = new M3U8VodLoader(mListener, mWrapper); |
||||
} |
||||
|
||||
@Override public String getKey() { |
||||
return mWrapper.getKey(); |
||||
} |
||||
|
||||
@Override public long getFileSize() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override public long getCurrentLocation() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override public boolean isRunning() { |
||||
return mLoader.isRunning(); |
||||
} |
||||
|
||||
@Override public void cancel() { |
||||
isCancel = true; |
||||
mLoader.cancel(); |
||||
} |
||||
|
||||
@Override public void stop() { |
||||
isStop = true; |
||||
mLoader.stop(); |
||||
} |
||||
|
||||
@Override public void start() { |
||||
if (isStop || isCancel) { |
||||
return; |
||||
} |
||||
mListener.onPre(); |
||||
// peer数量小于0,
|
||||
M3U8Entity m3U8Entity = mWrapper.getEntity().getM3U8Entity(); |
||||
if (m3U8Entity.getPeerNum() <= 0 || (m3U8Entity.isGenerateIndexFile() && !new File( |
||||
String.format(M3U8InfoThread.M3U8_INDEX_FORMAT, |
||||
mWrapper.getEntity().getFilePath())).exists())) { |
||||
getVodInfo(); |
||||
} else { |
||||
mLoader.start(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取点播文件信息 |
||||
*/ |
||||
private void getVodInfo() { |
||||
M3U8InfoThread thread = new M3U8InfoThread(mWrapper, new OnFileInfoCallback() { |
||||
@Override public void onComplete(String key, CompleteInfo info) { |
||||
IVodTsUrlConverter converter = mWrapper.asM3U8().getVodUrlConverter(); |
||||
if (converter != null) { |
||||
if (TextUtils.isEmpty(mWrapper.asM3U8().getBandWidthUrl())) { |
||||
mUrls.addAll(converter.convert(mWrapper.getEntity().getUrl(), (List<String>) info.obj)); |
||||
} else { |
||||
mUrls.addAll( |
||||
converter.convert(mWrapper.asM3U8().getBandWidthUrl(), (List<String>) info.obj)); |
||||
} |
||||
} else { |
||||
mUrls.addAll((Collection<? extends String>) info.obj); |
||||
} |
||||
if (mUrls.isEmpty()) { |
||||
failDownload(new M3U8Exception(TAG, "获取地址失败"), false); |
||||
return; |
||||
} else if (!mUrls.get(0).startsWith("http")) { |
||||
failDownload(new M3U8Exception(TAG, "地址错误,请使用IM3U8UrlExtInfHandler处理你的url信息"), false); |
||||
return; |
||||
} |
||||
mWrapper.asM3U8().setUrls(mUrls); |
||||
if (isStop) { |
||||
mListener.onStop(mWrapper.getEntity().getCurrentProgress()); |
||||
} else if (isCancel) { |
||||
mListener.onCancel(); |
||||
} else { |
||||
mLoader.start(); |
||||
} |
||||
} |
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { |
||||
failDownload(e, needRetry); |
||||
} |
||||
}); |
||||
new Thread(thread).start(); |
||||
} |
||||
|
||||
private void failDownload(BaseException e, boolean needRetry) { |
||||
if (isStop || isCancel) { |
||||
return; |
||||
} |
||||
mListener.onFail(needRetry, e); |
||||
mLoader.onDestroy(); |
||||
} |
||||
} |
@ -1,36 +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; |
||||
|
||||
/** |
||||
* Created by lyy on 2017/6/3. |
||||
*/ |
||||
public abstract class AbsNormalTask<TASK_WRAPPER extends AbsTaskWrapper> |
||||
extends AbsTask<TASK_WRAPPER> { |
||||
|
||||
/** |
||||
* 最高优先级命令,最高优先级命令有以下属性 |
||||
* 1、在下载队列中,有且只有一个最高优先级任务 |
||||
* 2、最高优先级任务会一直存在,直到用户手动暂停或任务完成 |
||||
* 3、任务调度器不会暂停最高优先级任务 |
||||
* 4、用户手动暂停或任务完成后,第二次重新执行该任务,该命令将失效 |
||||
* 5、如果下载队列中已经满了,则会停止队尾的任务 |
||||
* 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务 |
||||
*/ |
||||
public void setHighestPriority(boolean isHighestPriority) { |
||||
isHeighestTask = isHighestPriority; |
||||
} |
||||
} |
@ -1,116 +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.upload.uploader; |
||||
|
||||
import com.arialyy.aria.core.common.CompleteInfo; |
||||
import com.arialyy.aria.core.common.IUtil; |
||||
import com.arialyy.aria.core.common.OnFileInfoCallback; |
||||
import com.arialyy.aria.core.inf.AbsEntity; |
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper; |
||||
import com.arialyy.aria.core.inf.IUploadListener; |
||||
import com.arialyy.aria.core.upload.UTaskWrapper; |
||||
import com.arialyy.aria.exception.BaseException; |
||||
import com.arialyy.aria.util.CheckUtil; |
||||
|
||||
/** |
||||
* Created by lyy on 2017/2/9. |
||||
* 简单的文件上传工具 |
||||
*/ |
||||
public class SimpleUploadUtil implements IUtil, Runnable { |
||||
private static final String TAG = "SimpleUploadUtil"; |
||||
|
||||
private UTaskWrapper mTaskWrapper; |
||||
private IUploadListener mListener; |
||||
private Uploader mUploader; |
||||
private boolean isStop = false, isCancel = false; |
||||
|
||||
public SimpleUploadUtil(UTaskWrapper taskWrapper, IUploadListener listener) { |
||||
mTaskWrapper = taskWrapper; |
||||
CheckUtil.checkTaskEntity(taskWrapper); |
||||
if (listener == null) { |
||||
throw new IllegalArgumentException("上传监听不能为空"); |
||||
} |
||||
mListener = listener; |
||||
mUploader = new Uploader(mListener, taskWrapper); |
||||
} |
||||
|
||||
@Override public void run() { |
||||
mListener.onPre(); |
||||
switch (mTaskWrapper.getRequestType()) { |
||||
case AbsTaskWrapper.U_FTP: |
||||
FtpFileInfoThread infoThread = |
||||
new FtpFileInfoThread(mTaskWrapper, new OnFileInfoCallback() { |
||||
@Override public void onComplete(String url, CompleteInfo info) { |
||||
if (info.code == FtpFileInfoThread.CODE_COMPLETE) { |
||||
mListener.onComplete(); |
||||
} else { |
||||
mUploader.start(); |
||||
} |
||||
} |
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { |
||||
failUpload(e, needRetry); |
||||
} |
||||
}); |
||||
new Thread(infoThread).start(); |
||||
break; |
||||
case AbsTaskWrapper.U_HTTP: |
||||
mUploader.start(); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
private void failUpload(BaseException e, boolean needRetry) { |
||||
if (isStop || isCancel) { |
||||
return; |
||||
} |
||||
mListener.onFail(needRetry, e); |
||||
mUploader.onDestroy(); |
||||
} |
||||
|
||||
@Override public String getKey() { |
||||
return mTaskWrapper.getKey(); |
||||
} |
||||
|
||||
@Override public long getFileSize() { |
||||
return mUploader.getFileSize(); |
||||
} |
||||
|
||||
@Override public long getCurrentLocation() { |
||||
return mUploader.getCurrentLocation(); |
||||
} |
||||
|
||||
@Override public boolean isRunning() { |
||||
return mUploader.isRunning(); |
||||
} |
||||
|
||||
@Override public void cancel() { |
||||
isCancel = true; |
||||
mUploader.cancel(); |
||||
} |
||||
|
||||
@Override public void stop() { |
||||
isStop = true; |
||||
mUploader.stop(); |
||||
} |
||||
|
||||
@Override public void start() { |
||||
if (isStop || isCancel) { |
||||
return; |
||||
} |
||||
new Thread(this).start(); |
||||
} |
||||
} |
@ -1,61 +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.upload.uploader; |
||||
|
||||
import com.arialyy.aria.core.AriaManager; |
||||
import com.arialyy.aria.core.common.AbsThreadTask; |
||||
import com.arialyy.aria.core.common.NormalFileer; |
||||
import com.arialyy.aria.core.common.SubThreadConfig; |
||||
import com.arialyy.aria.core.event.Event; |
||||
import com.arialyy.aria.core.event.SpeedEvent; |
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper; |
||||
import com.arialyy.aria.core.inf.IUploadListener; |
||||
import com.arialyy.aria.core.upload.UTaskWrapper; |
||||
import com.arialyy.aria.core.upload.UploadEntity; |
||||
import java.io.File; |
||||
|
||||
/** |
||||
* Created by Aria.Lao on 2017/7/27. |
||||
* 文件上传器 |
||||
*/ |
||||
class Uploader extends NormalFileer<UploadEntity, UTaskWrapper> { |
||||
|
||||
Uploader(IUploadListener listener, UTaskWrapper taskEntity) { |
||||
super(listener, taskEntity); |
||||
mTempFile = new File(mEntity.getFilePath()); |
||||
setUpdateInterval( |
||||
AriaManager.getInstance().getUploadConfig().getUpdateInterval()); |
||||
} |
||||
|
||||
@Override protected boolean handleNewTask() { |
||||
return true; |
||||
} |
||||
|
||||
@Override protected AbsThreadTask selectThreadTask(SubThreadConfig<UTaskWrapper> config) { |
||||
switch (mTaskWrapper.getRequestType()) { |
||||
case AbsTaskWrapper.U_FTP: |
||||
return new FtpThreadTask(config); |
||||
case AbsTaskWrapper.U_HTTP: |
||||
return new HttpThreadTask(config); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
@Event |
||||
public void setMaxSpeed(SpeedEvent event) { |
||||
setMaxSpeed(event.speed); |
||||
} |
||||
} |
@ -1,26 +0,0 @@ |
||||
package com.example.ariaftpcomponent; |
||||
|
||||
import android.content.Context; |
||||
import androidx.test.platform.app.InstrumentationRegistry; |
||||
import androidx.test.ext.junit.runners.AndroidJUnit4; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* Instrumented test, which will execute on an Android device. |
||||
* |
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
||||
*/ |
||||
@RunWith(AndroidJUnit4.class) |
||||
public class ExampleInstrumentedTest { |
||||
@Test |
||||
public void useAppContext() { |
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); |
||||
|
||||
assertEquals("com.example.ariaftpcomponent.test", appContext.getPackageName()); |
||||
} |
||||
} |
@ -1,4 +0,0 @@ |
||||
package com.arialyy.aria.ftpcomponent; |
||||
|
||||
public class bb { |
||||
} |
@ -1,17 +0,0 @@ |
||||
package com.example.ariaftpcomponent; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* Example local unit test, which will execute on the development machine (host). |
||||
* |
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
||||
*/ |
||||
public class ExampleUnitTest { |
||||
@Test |
||||
public void addition_isCorrect() { |
||||
assertEquals(4, 2 + 2); |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
apply plugin: 'com.android.library' |
||||
|
||||
android { |
||||
compileSdkVersion rootProject.ext.compileSdkVersion |
||||
buildToolsVersion rootProject.ext.buildToolsVersion |
||||
|
||||
defaultConfig { |
||||
minSdkVersion rootProject.ext.minSdkVersion |
||||
targetSdkVersion rootProject.ext.targetSdkVersion |
||||
versionCode rootProject.ext.versionCode |
||||
versionName rootProject.ext.versionName |
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" |
||||
consumerProguardFiles 'consumer-rules.pro' |
||||
} |
||||
|
||||
buildTypes { |
||||
release { |
||||
minifyEnabled false |
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' |
||||
} |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
implementation fileTree(dir: 'libs', include: ['*.jar']) |
||||
|
||||
implementation "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}" |
||||
|
||||
testImplementation 'junit:junit:4.12' |
||||
implementation project(path: ':AriaFtpPlug') |
||||
implementation project(path: ':PublicComponent') |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue