This commit is contained in:
AriaLyy
2017-10-10 09:50:40 +08:00
132 changed files with 16174 additions and 16696 deletions

View File

@@ -23,7 +23,8 @@ dependencies {
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile project(':AriaAnnotations')
compile 'com.arialyy.aria:aria-ftp-plug:1.0.0'
compile 'com.arialyy.aria:aria-ftp-plug:1.0.3'
// compile project(':AriaFtpPlug')
}

View File

@@ -31,7 +31,7 @@ public class TaskManager {
private static volatile TaskManager INSTANCE = null;
private Map<String, AbsTask> map = new ConcurrentHashMap<>();
public TaskManager getInstance() {
public static TaskManager getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new TaskManager();

View File

@@ -16,10 +16,13 @@
package com.arialyy.aria.core.command.normal;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.util.NetUtils;
/**
* Created by lyy on 2017/6/2.
@@ -43,6 +46,10 @@ final class HighestPriorityCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T>
@Override public void executeCmd() {
if (!canExeCmd) return;
if (!NetUtils.isConnected(AriaManager.APP)){
Log.w(TAG, "启动任务失败,网络未连接");
return;
}
DownloadTask task = (DownloadTask) getTask();
if (task == null) {
task = (DownloadTask) createTask();

View File

@@ -28,39 +28,39 @@ public class NormalCmdFactory extends AbsCmdFactory<AbsTaskEntity, AbsNormalCmd>
/**
* 创建任务
*/
public static final int TASK_CREATE = 0x122;
public static final int TASK_CREATE = 0xb1;
/**
* 启动任务
*/
public static final int TASK_START = 0x123;
public static final int TASK_START = 0xb2;
/**
* 恢复任务
*/
public static final int TASK_RESUME = 0x127;
public static final int TASK_RESUME = 0xb3;
/**
* 取消任务
*/
public static final int TASK_CANCEL = 0x124;
public static final int TASK_CANCEL = 0xb4;
/**
* 停止任务
*/
public static final int TASK_STOP = 0x125;
public static final int TASK_STOP = 0xb5;
/**
* 设置任务为最高优先级
*/
public static final int TASK_HIGHEST_PRIORITY = 0x128;
public static final int TASK_HIGHEST_PRIORITY = 0xb6;
/**
* 停止所有任务
*/
public static final int TASK_STOP_ALL = 0x129;
public static final int TASK_STOP_ALL = 0xb7;
/**
* 恢复所有停止的任务
*/
public static final int TASK_RESUME_ALL = 0x130;
public static final int TASK_RESUME_ALL = 0xb8;
/**
* 删除所有任务,
*/
public static final int TASK_CANCEL_ALL = 0x131;
public static final int TASK_CANCEL_ALL = 0xb9;
private static volatile NormalCmdFactory INSTANCE = null;
private NormalCmdFactory() {

View File

@@ -1,5 +1,7 @@
package com.arialyy.aria.core.command.normal;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
@@ -9,6 +11,7 @@ import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.NetUtils;
import java.util.List;
/**
@@ -26,6 +29,10 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
}
@Override public void executeCmd() {
if (!NetUtils.isConnected(AriaManager.APP)) {
Log.w(TAG, "恢复任务失败,网络未连接");
return;
}
if (isDownloadCmd) {
resumeDownload();
} else {
@@ -41,18 +48,22 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
DbEntity.findDatas(DownloadTaskEntity.class, "isGroupTask=?", "false");
if (dTaskEntity != null && !dTaskEntity.isEmpty()) {
for (DownloadTaskEntity te : dTaskEntity) {
if (te == null || te.getEntity() == null) continue;
int state = te.getState();
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue;
resumeEntity(te);
if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
resumeEntity(te);
}
}
}
List<DownloadGroupTaskEntity> groupTask = DbEntity.findAllData(DownloadGroupTaskEntity.class);
if (groupTask != null && !groupTask.isEmpty()) {
for (DownloadGroupTaskEntity te : groupTask) {
if (te == null || te.getEntity() == null) continue;
int state = te.getState();
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue;
resumeEntity(te);
if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
resumeEntity(te);
}
}
}
}
@@ -65,9 +76,11 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
DbEntity.findDatas(UploadTaskEntity.class, "isGroupTask=?", "false");
if (dTaskEntity != null && !dTaskEntity.isEmpty()) {
for (UploadTaskEntity te : dTaskEntity) {
if (te == null || te.getEntity() == null) continue;
int state = te.getState();
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue;
resumeEntity(te);
if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
resumeEntity(te);
}
}
}
}

View File

@@ -17,11 +17,13 @@
package com.arialyy.aria.core.command.normal;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.QueueMod;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.util.NetUtils;
/**
* Created by lyy on 2016/8/22.
@@ -36,6 +38,10 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
@Override public void executeCmd() {
if (!canExeCmd) return;
if (!NetUtils.isConnected(AriaManager.APP)) {
Log.w(TAG, "启动任务失败,网络未连接");
return;
}
String mod;
int maxTaskNum;
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
@@ -64,7 +70,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
}
}
} else {
// 任务不存在时,根据配置不同,对任务执行操作
if (!task.isRunning()) {
startTask();
}

View File

@@ -85,6 +85,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
}
@Override public void run() {
if (mConstance.isRunning) {
return;
}
startFlow();
}
@@ -92,12 +95,11 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 开始下载流程
*/
private void startFlow() {
mConstance.resetState();
checkTask();
if (mListener instanceof IDownloadListener) {
((IDownloadListener) mListener).onPostPre(mEntity.getFileSize());
}
mConstance.cleanState();
mConstance.isRunning = true;
if (!mTaskEntity.isSupportBP) {
mThreadNum = 1;
mConstance.THREAD_NUM = mThreadNum;
@@ -125,7 +127,10 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mTimer = new Timer(true);
mTimer.schedule(new TimerTask() {
@Override public void run() {
if (mConstance.isComplete() || !mConstance.isRunning) {
if (mConstance.isComplete()
|| mConstance.isStop()
|| mConstance.isCancel()
|| !mConstance.isRunning) {
closeTimer();
} else if (mConstance.CURRENT_LOCATION >= 0) {
mListener.onProgress(mConstance.CURRENT_LOCATION);
@@ -179,9 +184,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
@Override public void stop() {
closeTimer();
if (mConstance.isComplete()) return;
mConstance.isStop = true;
mConstance.isRunning = false;
mConstance.isStop = true;
if (mConstance.isComplete()) return;
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
@@ -393,5 +398,4 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 选择单任务线程的类型
*/
protected abstract AbsThreadTask selectThreadTask(SubThreadConfig<TASK_ENTITY> config);
}

View File

@@ -0,0 +1,198 @@
/*
* 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 android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by Aria.Lao on 2017/7/25.
* 获取ftp文件夹信息
*/
public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable {
private final String TAG = "AbsFtpInfoThread";
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
private int mConnectTimeOut;
protected OnFileInfoCallback mCallback;
protected long mSize = 0;
protected String mServerIp, mPort;
protected String charSet = "UTF-8";
private boolean isUpload = false;
public AbsFtpInfoThread(TASK_ENTITY taskEntity, OnFileInfoCallback callback) {
mTaskEntity = taskEntity;
mEntity = taskEntity.getEntity();
mConnectTimeOut =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
mCallback = callback;
if (mEntity instanceof UploadEntity) {
isUpload = true;
}
}
/**
* 设置请求的远程文件路径
*
* @return 远程文件路径
*/
protected abstract String setRemotePath();
@Override public void run() {
FTPClient client = null;
try {
client = createFtpClient();
if (client == null) return;
String remotePath =
new String(setRemotePath().getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
FTPFile[] files = client.listFiles(remotePath);
mSize = getFileSize(files, client, remotePath);
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
if (isUpload) {
//服务器上没有该文件路径,表示该任务为新的上传任务
mTaskEntity.isNewTask = true;
} else {
client.disconnect();
failDownload("获取文件信息错误,错误码为:" + reply);
return;
}
}
mTaskEntity.code = reply;
if (mSize != 0 && !isUpload) {
mEntity.setFileSize(mSize);
}
mEntity.update();
mTaskEntity.update();
onPreComplete(reply);
} catch (IOException e) {
failDownload(e.getMessage());
} finally {
if (client != null) {
try {
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void start() {
new Thread(this).start();
}
protected void onPreComplete(int code) {
}
/**
* 创建FTP客户端
*/
private FTPClient createFtpClient() throws IOException {
String url = "";
if (mEntity instanceof DownloadEntity) {
url = ((DownloadEntity) mEntity).getUrl();
} else if (mEntity instanceof UploadEntity) {
url = ((UploadEntity) mEntity).getUrl();
} else if (mEntity instanceof DownloadGroupEntity) {
url = mEntity.getKey();
} else {
failDownload("未知实体");
Log.e(TAG, "未知实体");
return null;
}
String[] pp = url.split("/")[2].split(":");
mServerIp = pp[0];
mPort = pp[1];
FTPClient client = new FTPClient();
// 连接服务器
client.connect(mServerIp, Integer.parseInt(mPort));
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload("无法连接到ftp服务器错误码为" + reply);
return null;
}
// 开启服务器对UTF-8的支持如果服务器支持就用UTF-8编码
charSet = "UTF-8";
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(10 * 1000);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(5);
return client;
}
/**
* 遍历FTP服务器上对应文件或文件夹大小
*
* @throws IOException 字符串编码转换错误
*/
private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
long size = 0;
String path = dirName + "/";
for (FTPFile file : files) {
if (file.isFile()) {
size += file.getSize();
handleFile(path + file.getName(), file);
} else {
String remotePath =
new String((path + file.getName()).getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
size += getFileSize(client.listFiles(remotePath), client, path + file.getName());
}
}
return size;
}
/**
* 处理FTP文件信息
*
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
protected void handleFile(String remotePath, FTPFile ftpFile) {
}
private void failDownload(String errorMsg) {
Log.e(TAG, errorMsg);
if (mCallback != null) {
mCallback.onFail(mEntity.getKey(), errorMsg);
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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 android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by lyy on 2017/9/26.
* FTP单任务父类
*/
public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
extends AbsThreadTask<ENTITY, TASK_ENTITY> {
protected String charSet, serverIp, port;
/**
* FTP 服务器编码
*/
public static String SERVER_CHARSET = "ISO-8859-1";
protected AbsFtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<TASK_ENTITY> info) {
super(constance, listener, info);
}
/**
* 构建FTP客户端
*/
protected FTPClient createClient() throws IOException {
String url = mEntity.getUrl();
String[] pp = url.split("/")[2].split(":");
serverIp = pp[0];
port = pp[1];
FTPClient client = new FTPClient();
// 连接服务器
client.connect(serverIp, Integer.parseInt(port));
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器错误码为" + reply, null);
return null;
}
// 开启服务器对UTF-8的支持如果服务器支持就用UTF-8编码
charSet = "UTF-8";
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(STATE.READ_TIME_OUT);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setBufferSize(mBufSize);
client.setControlKeepAliveTimeout(5);
//client.setCopyStreamListener();
return client;
}
}

View File

@@ -19,12 +19,13 @@ import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ErrorHelp;
import com.arialyy.aria.util.NetUtils;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
@@ -36,7 +37,7 @@ import java.util.TimerTask;
* Created by lyy on 2017/1/18.
* 任务线程
*/
public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable {
/**
* 线程重试次数
@@ -55,10 +56,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
protected SubThreadConfig<TASK_ENTITY> mConfig;
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
/**
* FTP 服务器编码
*/
public static String SERVER_CHARSET = "ISO-8859-1";
private int mFailNum = 0;
private String mTaskType;
private Timer mFailTimer;
@@ -73,9 +70,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
mConfig = info;
mTaskEntity = mConfig.TASK_ENTITY;
mEntity = mTaskEntity.getEntity();
if (mConfig.SUPPORT_BP) {
mConfigFPath = info.CONFIG_FILE_PATH;
}
mConfigFPath = info.CONFIG_FILE_PATH;
mBufSize = manager.getDownloadConfig().getBuffSize();
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed());
mTaskType = getTaskType();
@@ -104,14 +99,15 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
synchronized (AriaManager.LOCK) {
try {
if (mConfig.SUPPORT_BP) {
final long currentTemp = mChildCurrentLocation;
STATE.STOP_NUM++;
Log.d(TAG, "任务【"
+ mConfig.TEMP_FILE.getName()
+ "】thread__"
+ mConfig.THREAD_ID
+ "__停止, stop location ==> "
+ mChildCurrentLocation);
writeConfig(false, mChildCurrentLocation);
+ currentTemp);
writeConfig(false, currentTemp);
if (STATE.isStop()) {
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
STATE.isRunning = false;
@@ -169,12 +165,9 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
/**
* 任务失败
*/
protected void fail(long currentLocation, String msg, Exception ex) {
protected void fail(final long currentLocation, String msg, Exception ex) {
synchronized (AriaManager.LOCK) {
try {
//STATE.FAIL_NUM++;
//STATE.isRunning = false;
//STATE.isStop = true;
if (ex != null) {
Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
} else {
@@ -182,11 +175,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
}
if (mConfig.SUPPORT_BP) {
writeConfig(false, currentLocation);
//if (STATE.isFail()) {
// Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
// mListener.onFail(true);
//}
retryThis(true);
retryThis(STATE.THREAD_NUM != 1);
} else {
Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
mListener.onFail(true);
@@ -204,7 +193,11 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
* @param needRetry 是否可以重试
*/
private void retryThis(boolean needRetry) {
if (mFailNum < RETRY_NUM && needRetry) {
if (!NetUtils.isConnected(AriaManager.APP)) {
Log.w(TAG,
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__重试失败网络未连接");
}
if (mFailNum < RETRY_NUM && needRetry && NetUtils.isConnected(AriaManager.APP)) {
if (mFailTimer != null) {
mFailTimer.purge();
mFailTimer.cancel();
@@ -215,23 +208,26 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
mFailNum++;
Log.w(TAG,
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__正在重试");
mConfig.START_LOCATION = mChildCurrentLocation;
final long retryLocation = mChildCurrentLocation;
mConfig.START_LOCATION = retryLocation;
AbsThreadTask.this.run();
}
}, RETRY_INTERVAL);
} else {
STATE.FAIL_NUM++;
STATE.isRunning = false;
STATE.isStop = true;
Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
mListener.onFail(true);
if (STATE.isFail()) {
STATE.isRunning = false;
STATE.isStop = true;
Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
mListener.onFail(true);
}
}
}
/**
* 将记录写入到配置文件
*/
protected void writeConfig(boolean isComplete, long record) throws IOException {
protected void writeConfig(boolean isComplete, final long record) throws IOException {
synchronized (AriaManager.LOCK) {
String key = null, value = null;
if (0 < record && record < mConfig.END_LOCATION) {

View File

@@ -1,6 +1,6 @@
package com.arialyy.aria.core.download.downloader;
package com.arialyy.aria.core.common;
interface OnFileInfoCallback {
public interface OnFileInfoCallback {
/**
* 处理完成
*

View File

@@ -35,7 +35,7 @@ public class StateConstance {
public StateConstance() {
}
public void cleanState() {
public void resetState() {
isCancel = false;
isStop = false;
isRunning = true;
@@ -56,7 +56,7 @@ public class StateConstance {
* 所有子线程是否都已经下载失败
*/
public boolean isFail() {
return FAIL_NUM == THREAD_NUM;
return FAIL_NUM + COMPLETE_THREAD_NUM >= THREAD_NUM;
}
/**

View File

@@ -31,12 +31,14 @@ import java.lang.ref.WeakReference;
class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
implements IDownloadListener {
protected WeakReference<Handler> outHandler;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastLen = 0; //上一次发送长度
private boolean isFirst = true;
protected ENTITY mEntity;
protected TASK mTask;
private boolean isConvertSpeed = false;
boolean isWait = false;
private long mLastSaveTime;
BaseDListener(TASK task, Handler outHandler) {
this.outHandler = new WeakReference<>(outHandler);
@@ -45,6 +47,7 @@ class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
final AriaManager manager = AriaManager.getInstance(AriaManager.APP);
isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
mLastLen = mEntity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
}
@Override public void onPre() {
@@ -82,6 +85,11 @@ class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
}
handleSpeed(speed);
sendInState2Target(ISchedulers.RUNNING);
if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL){
saveData(IEntity.STATE_RUNNING, currentLocation);
mLastSaveTime = System.currentTimeMillis();
}
mLastLen = currentLocation;
}

View File

@@ -17,6 +17,7 @@ package com.arialyy.aria.core.download;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.downloader.AbsGroupUtil;
@@ -56,23 +57,23 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity, Dow
}
@Override public void start() {
mUtil.start();
if (mUtil.isRunning()) {
Log.d(TAG, "任务正在下载");
} else {
mUtil.start();
}
}
@Override public void stop() {
if (!mUtil.isRunning()) {
if (mOutHandler != null) {
mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget();
}
mListener.onStop(mEntity.getCurrentProgress());
}
mUtil.stop();
}
@Override public void cancel() {
if (!mUtil.isRunning()) {
if (mOutHandler != null) {
mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget();
}
mListener.onCancel();
}
mUtil.cancel();
}

View File

@@ -128,11 +128,7 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity> {
if (mUtil.isRunning()) {
mUtil.stop();
} else {
mEntity.setState(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
mEntity.update();
if (mOutHandler != null) {
mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget();
}
mListener.onStop(mEntity.getCurrentProgress());
}
}
@@ -141,9 +137,7 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity> {
*/
@Override public void cancel() {
if (!mUtil.isRunning()) {
if (mOutHandler != null) {
mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget();
}
mListener.onCancel();
}
mUtil.cancel();
}

View File

@@ -1,155 +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 android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by Aria.Lao on 2017/7/25.
* 获取ftp文件夹信息
*/
abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable {
private final String TAG = "HttpFileInfoThread";
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
private int mConnectTimeOut;
private OnFileInfoCallback mCallback;
protected long mSize = 0;
AbsFtpInfoThread(TASK_ENTITY taskEntity, OnFileInfoCallback callback) {
mTaskEntity = taskEntity;
mEntity = taskEntity.getEntity();
mConnectTimeOut =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
mCallback = callback;
}
@Override public void run() {
FTPClient client = null;
try {
String url = mTaskEntity.getEntity().getKey();
String[] pp = url.split("/")[2].split(":");
String serverIp = pp[0];
int port = Integer.parseInt(pp[1]);
String remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
client = new FTPClient();
client.connect(serverIp, port);
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload("无法连接到ftp服务器错误码为" + reply);
return;
}
client.setDataTimeout(mConnectTimeOut);
String charSet = "UTF-8";
// 开启服务器对UTF-8的支持如果服务器支持就用UTF-8编码
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
FTPFile[] files =
client.listFiles(new String(remotePath.getBytes(charSet), AbsThreadTask.SERVER_CHARSET));
mSize = getFileSize(files, client, remotePath);
reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload("获取文件信息错误,错误码为:" + reply);
return;
}
mTaskEntity.code = reply;
onPreComplete();
mEntity.update();
mTaskEntity.update();
mCallback.onComplete(mEntity.getKey(), reply);
} catch (IOException e) {
failDownload(e.getMessage());
} finally {
if (client != null) {
try {
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
void start() {
new Thread(this).start();
}
protected void onPreComplete() {
}
/**
* 遍历FTP服务器上对应文件或文件夹大小
*
* @throws IOException
*/
private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
long size = 0;
String path = dirName + "/";
for (FTPFile file : files) {
if (file.isFile()) {
size += file.getSize();
handleFile(path + file.getName(), file);
} else {
size += getFileSize(client.listFiles(
CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client,
path + file.getName());
}
}
return size;
}
/**
* 处理FTP文件信息
*
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
void handleFile(String remotePath, FTPFile ftpFile) {
}
private void failDownload(String errorMsg) {
Log.e(TAG, errorMsg);
if (mCallback != null) {
mCallback.onFail(mEntity.getKey(), errorMsg);
}
}
}

View File

@@ -25,6 +25,7 @@ import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.NetUtils;
import java.io.File;
import java.util.HashMap;
import java.util.List;
@@ -42,23 +43,15 @@ import java.util.concurrent.Executors;
public abstract class AbsGroupUtil implements IUtil {
private final String TAG = "AbsGroupUtil";
/**
* 任务组所有任务总大小
* 任务组所有任务总长度
*/
long mTotalSize = 0;
long mTotalLen = 0;
long mCurrentLocation = 0;
private ExecutorService mExePool;
protected IDownloadGroupListener mListener;
protected DownloadGroupTaskEntity mTaskEntity;
private boolean isRunning = false;
private Timer mTimer;
/**
* 初始化完成的任务书数
*/
int mInitNum = 0;
/**
* 初始化失败的任务数
*/
int mInitFailNum = 0;
/**
* 保存所有没有下载完成的任务key为下载地址
*/
@@ -78,18 +71,26 @@ public abstract class AbsGroupUtil implements IUtil {
* 该任务组对应的所有任务
*/
private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>();
/**
* 是否需要读取文件长度,{@code true}需要
*/
boolean isNeedLoadFileSize = true;
//已经完成的任务数
private int mCompleteNum = 0;
//失败的任务数
private int mFailNum = 0;
//停止的任务数
private int mStopNum = 0;
//实际的下载任务数
int mActualTaskNum = 0;
/**
* 是否需要读取文件长度,{@code true}需要
*/
boolean isNeedLoadFileSize = true;
//初始化完成的任务数
int mInitNum = 0;
// 初始化失败的任务数
int mInitFailNum = 0;
//任务组大小
int mGroupSize = 0;
AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
mListener = listener;
@@ -104,14 +105,13 @@ public abstract class AbsGroupUtil implements IUtil {
mTasksMap.put(te.getEntity().getUrl(), te);
}
}
mTotalSize = taskEntity.getEntity().getFileSize();
isNeedLoadFileSize = mTotalSize <= 1;
mGroupSize = mTaskEntity.entity.getSubTask().size();
mTotalLen = taskEntity.getEntity().getFileSize();
isNeedLoadFileSize = mTotalLen <= 1;
for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) {
File file = new File(entity.getDownloadPath());
if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) {
mCompleteNum++;
mInitNum++;
mStopNum++;
mCurrentLocation += entity.getFileSize();
} else {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
@@ -119,7 +119,7 @@ public abstract class AbsGroupUtil implements IUtil {
mActualTaskNum++;
}
if (isNeedLoadFileSize) {
mTotalSize += entity.getFileSize();
mTotalLen += entity.getFileSize();
}
}
updateFileSize();
@@ -127,7 +127,7 @@ public abstract class AbsGroupUtil implements IUtil {
void updateFileSize() {
if (isNeedLoadFileSize) {
mTaskEntity.getEntity().setFileSize(mTotalSize);
mTaskEntity.getEntity().setFileSize(mTotalLen);
mTaskEntity.getEntity().update();
}
}
@@ -211,7 +211,7 @@ public abstract class AbsGroupUtil implements IUtil {
}
@Override public long getFileSize() {
return mTotalSize;
return mTotalLen;
}
@Override public long getCurrentLocation() {
@@ -271,7 +271,6 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void stop() {
closeTimer(false);
mListener.onStop(mCurrentLocation);
onStop();
if (!mExePool.isShutdown()) {
mExePool.shutdown();
@@ -324,7 +323,7 @@ public abstract class AbsGroupUtil implements IUtil {
*/
void startRunningFlow() {
closeTimer(true);
mListener.onPostPre(mTotalSize);
mListener.onPostPre(mTotalLen);
mListener.onStart(mCurrentLocation);
startTimer();
}
@@ -405,14 +404,16 @@ public abstract class AbsGroupUtil implements IUtil {
DownloadTaskEntity taskEntity;
DownloadEntity entity;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastSaveTime;
long lastLen = 0;
ChildDownloadListener(DownloadTaskEntity entity) {
this.taskEntity = entity;
this.entity = taskEntity.getEntity();
lastLen = this.entity.getCurrentProgress();
this.entity.setFailNum(0);
lastLen = this.entity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
}
@Override public void onPre() {
@@ -444,6 +445,10 @@ public abstract class AbsGroupUtil implements IUtil {
entity.setCurrentProgress(currentLocation);
handleSpeed(speed);
mListener.onSubRunning(entity);
if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL) {
saveData(IEntity.STATE_RUNNING, currentLocation);
mLastSaveTime = System.currentTimeMillis();
}
lastLen = currentLocation;
}
@@ -451,10 +456,12 @@ public abstract class AbsGroupUtil implements IUtil {
saveData(IEntity.STATE_STOP, stopLocation);
handleSpeed(0);
mListener.onSubStop(entity);
mStopNum++;
if (mStopNum + mCompleteNum >= mInitNum) {
closeTimer(false);
mListener.onStop(mCurrentLocation);
synchronized (AbsGroupUtil.class) {
mStopNum++;
if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) {
closeTimer(false);
mListener.onStop(mCurrentLocation);
}
}
}
@@ -466,16 +473,19 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void onComplete() {
saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
mCompleteNum++;
handleSpeed(0);
mListener.onSubComplete(entity);
//如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
if (mCompleteNum >= mTaskEntity.getEntity().getSubTask().size()) {
closeTimer(false);
mListener.onComplete();
} else if (mCompleteNum + mFailNum >= mActualTaskNum) {
//如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
closeTimer(false);
synchronized (AbsGroupUtil.class) {
mCompleteNum++;
//如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
if (mCompleteNum >= mGroupSize) {
closeTimer(false);
mListener.onComplete();
} else if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) {
//如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
closeTimer(false);
mListener.onStop(mCurrentLocation);
}
}
}
@@ -491,7 +501,8 @@ public abstract class AbsGroupUtil implements IUtil {
*/
private void reTry(boolean needRetry) {
synchronized (AriaManager.LOCK) {
if (entity.getFailNum() < 5 && isRunning && needRetry) {
if (entity.getFailNum() < 5 && isRunning && needRetry && NetUtils.isConnected(
AriaManager.APP)) {
reStartTask();
} else {
mFailNum++;

View File

@@ -17,6 +17,7 @@ package com.arialyy.aria.core.download.downloader;
import android.util.SparseArray;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
@@ -73,7 +74,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
}
}
if (i != 0 && i == mExeMap.size()) startRunningFlow();
if (mCurrentLocation == mTotalSize) {
if (mCurrentLocation == mTotalLen) {
mListener.onComplete();
}
}
@@ -92,7 +93,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
DownloadTaskEntity te = mExeMap.get(url);
if (te != null) {
if (isNeedLoadFileSize) {
mTotalSize += te.getEntity().getFileSize();
mTotalLen += te.getEntity().getFileSize();
}
createChildDownload(te);
}

View File

@@ -16,7 +16,6 @@
package com.arialyy.aria.core.download.downloader;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsFileer;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.SubThreadConfig;
@@ -43,10 +42,7 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
}
@Override protected void checkTask() {
mConfigFile = new File(mContext.getFilesDir().getPath()
+ AriaManager.DOWNLOAD_TEMP_DIR
+ mEntity.getFileName()
+ ".properties");
mConfigFile = new File(CommonUtil.getFileConfigPath(true, mEntity.getFileName()));
mTempFile = new File(mEntity.getDownloadPath());
if (!mTaskEntity.isSupportBP) {
isNewTask = true;

View File

@@ -15,6 +15,7 @@
*/
package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
@@ -42,6 +43,8 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
}
mActualTaskNum = mTaskEntity.entity.getSubTask().size();
mGroupSize = mActualTaskNum;
mTotalLen = mTaskEntity.entity.getFileSize();
startDownload();
}
}

View File

@@ -15,6 +15,8 @@
*/
package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
@@ -33,14 +35,20 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
super(taskEntity, callback);
}
@Override void handleFile(String remotePath, FTPFile ftpFile) {
@Override protected String setRemotePath() {
String url = mEntity.getKey();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length());
}
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
addEntity(remotePath, ftpFile);
}
@Override protected void onPreComplete() {
super.onPreComplete();
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
mEntity.setFileSize(mSize);
mCallback.onComplete(mEntity.getKey(), code);
}
private void addEntity(String remotePath, FTPFile ftpFile) {

View File

@@ -15,6 +15,8 @@
*/
package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
@@ -28,11 +30,17 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEnt
super(taskEntity, callback);
}
@Override protected void onPreComplete() {
super.onPreComplete();
@Override protected String setRemotePath() {
String url = mEntity.getUrl();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length());
}
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
if (mSize != mTaskEntity.getEntity().getFileSize()) {
mTaskEntity.isNewTask = true;
}
mEntity.setFileSize(mSize);
mCallback.onComplete(mEntity.getUrl(), code);
}
}

View File

@@ -15,9 +15,8 @@
*/
package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.AbsFtpThreadTask;
import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.download.DownloadEntity;
@@ -27,7 +26,6 @@ import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
@@ -35,7 +33,7 @@ import org.apache.commons.net.ftp.FTPReply;
* Created by Aria.Lao on 2017/7/24.
* Ftp下载任务
*/
class FtpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> {
class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "FtpThreadTask";
FtpThreadTask(StateConstance constance, IDownloadListener listener,
@@ -57,40 +55,16 @@ class FtpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> {
+ ",结束位置:"
+ mConfig.END_LOCATION
+ "");
client = createClient();
if (client == null) return;
String url = mEntity.getUrl();
String[] pp = url.split("/")[2].split(":");
String serverIp = pp[0];
int port = Integer.parseInt(pp[1]);
String remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
client = new FTPClient();
client.connect(serverIp, port);
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器错误码为" + reply, null);
return;
}
String charSet = "UTF-8";
// 开启服务器对UTF-8的支持如果服务器支持就用UTF-8编码
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(STATE.READ_TIME_OUT);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
String remotePath = new String(
url.substring(url.indexOf(port) + port.length(), url.length()).getBytes(charSet),
SERVER_CHARSET);
client.setRestartOffset(mConfig.START_LOCATION);
client.allocate(mBufSize);
is = client.retrieveFileStream(
new String(remotePath.getBytes(charSet), SERVER_CHARSET));
is = client.retrieveFileStream(remotePath);
//发送第二次指令时,还需要再做一次判断
reply = client.getReplyCode();
int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply)) {
client.disconnect();
fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply, null);

View File

@@ -18,6 +18,7 @@ package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.CommonUtil;

View File

@@ -17,6 +17,7 @@
package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;

View File

@@ -19,6 +19,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore;
import java.util.LinkedList;
import java.util.List;
/**
* Created by AriaL on 2017/6/29.

View File

@@ -19,10 +19,13 @@ import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.CancelCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -199,6 +202,16 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
.exe();
}
/**
* 重试下载
*/
public void reTry() {
List<ICmd> cmds = new ArrayList<>();
cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP));
cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START));
AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe();
}
/**
* 删除任务
*
@@ -206,8 +219,8 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
* {@code false}如果任务已经完成,只删除任务数据库记录,
*/
public void cancel(boolean removeFile) {
CancelCmd cancelCmd =
(CancelCmd) CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL);
CancelCmd cancelCmd = (CancelCmd) CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
NormalCmdFactory.TASK_CANCEL);
cancelCmd.removeFile = removeFile;
AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe();
}

View File

@@ -17,13 +17,13 @@ package com.arialyy.aria.core.inf;
import android.content.Context;
import android.os.Handler;
import com.arialyy.aria.orm.Ignore;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by AriaL on 2017/6/29.
*/
public abstract class AbsTask<ENTITY extends AbsEntity> implements ITask<ENTITY> {
/**
* 是否需要重试默认为true
*/

View File

@@ -21,6 +21,7 @@ import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTask;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.util.regex.Pattern;
/**
@@ -39,6 +40,7 @@ public abstract class AbsUploadTarget<TARGET extends AbsUploadTarget, ENTITY ext
CheckUtil.checkDownloadUrl(uploadUrl);
if (mEntity.getUrl().equals(uploadUrl)) return (TARGET) this;
mEntity.setUrl(uploadUrl);
//mEntity.setUrl(CommonUtil.convertUrl(uploadUrl));
mEntity.update();
return (TARGET) this;
}

View File

@@ -18,18 +18,13 @@ package com.arialyy.aria.core.queue;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import java.security.Key;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.arialyy.aria.util.NetUtils;
/**
* Created by lyy on 2017/2/23.
@@ -187,7 +182,11 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
@Override public void reTryStart(TASK task) {
if (task == null) {
Log.w(TAG, "重试下载失败task 为null");
Log.w(TAG, "重试失败task 为null");
return;
}
if (!NetUtils.isConnected(AriaManager.APP)){
Log.w(TAG, "重试失败,网络未连接");
return;
}
if (!task.isRunning()) {

View File

@@ -20,9 +20,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.util.CommonUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
@@ -90,16 +88,18 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
* @param maxNum 下载数
*/
public void setMaxNum(int maxNum) {
try {
ArrayBlockingQueue<TASK> temp = new ArrayBlockingQueue<>(maxNum);
TASK task;
while ((task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS)) != null) {
temp.offer(task);
synchronized (AriaManager.LOCK) {
try {
ArrayBlockingQueue<TASK> temp = new ArrayBlockingQueue<>(maxNum);
TASK task;
while ((task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS)) != null) {
temp.offer(task);
}
mExecuteQueue = temp;
mSize = maxNum;
} catch (InterruptedException e) {
e.printStackTrace();
}
mExecuteQueue = temp;
mSize = maxNum;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@@ -109,33 +109,37 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
* @param newTask 新任务
*/
boolean putNewTask(TASK newTask) {
String url = newTask.getKey();
boolean s = mExecuteQueue.offer(newTask);
Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + ""));
if (s) {
mExecuteMap.put(CommonUtil.keyToHashKey(url), newTask);
synchronized (AriaManager.LOCK) {
String url = newTask.getKey();
boolean s = mExecuteQueue.offer(newTask);
Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + ""));
if (s) {
mExecuteMap.put(CommonUtil.keyToHashKey(url), newTask);
}
return s;
}
return s;
}
/**
* 队列满时,将移除下载队列中的第一个任务
*/
boolean pollFirstTask() {
try {
TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (oldTask == null) {
Log.e(TAG, "移除任务失败");
synchronized (AriaManager.LOCK) {
try {
TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (oldTask == null) {
Log.e(TAG, "移除任务失败");
return false;
}
oldTask.stop();
String key = CommonUtil.keyToHashKey(oldTask.getKey());
mExecuteMap.remove(key);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
oldTask.stop();
String key = CommonUtil.keyToHashKey(oldTask.getKey());
mExecuteMap.remove(key);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
return true;
}
return true;
}
@Override public TASK pollTask() {
@@ -185,8 +189,14 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
}
String convertKey = CommonUtil.keyToHashKey(key);
TASK task = mExecuteMap.get(convertKey);
mExecuteMap.remove(convertKey);
return mExecuteQueue.remove(task);
final int oldQueueSize = mExecuteQueue.size();
boolean isSuccess = mExecuteQueue.remove(task);
final int newQueueSize = mExecuteQueue.size();
if (isSuccess && newQueueSize != oldQueueSize) {
mExecuteMap.remove(convertKey);
return true;
}
return false;
}
}

View File

@@ -41,20 +41,11 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
implements ISchedulers<TASK> {
private final String TAG = "AbsSchedulers";
static final int DOWNLOAD = 0xa1;
static final int UPLOAD = 0xa2;
static final int DOWNLOAD_GROUP = 0xa3;
protected QUEUE mQueue;
private Map<String, AbsSchedulerListener<TASK, AbsNormalEntity>> mObservers =
new ConcurrentHashMap<>();
/**
* 设置调度器类型
*/
abstract int getSchedulerType();
/**
* 设置代理类后缀名
*/
@@ -282,7 +273,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
/**
* 启动下一个任务,条件:任务停止,取消下载,任务完成
*/
protected void startNextTask() {
private void startNextTask() {
TASK newTask = mQueue.getNextTask();
if (newTask == null) {
Log.w(TAG, "没有下一任务");
@@ -292,20 +283,4 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
mQueue.startTask(newTask);
}
}
/**
* 是否有下一任务
*
* @return {@code true} 有,{@code false} 无
*/
boolean hasNextTask() {
return mQueue.getCurrentCachePoolNum() > 0;
}
/**
* 获取正在执行的队列数
*/
int getExeTaskNum() {
return mQueue.getCurrentExePoolNum();
}
}

View File

@@ -43,10 +43,6 @@ public class DownloadGroupSchedulers extends
return INSTANCE;
}
@Override int getSchedulerType() {
return DOWNLOAD_GROUP;
}
@Override String getProxySuffix() {
return "$$DownloadGroupListenerProxy";
}

View File

@@ -45,10 +45,6 @@ public class DownloadSchedulers
return INSTANCE;
}
@Override int getSchedulerType() {
return DOWNLOAD;
}
@Override String getProxySuffix() {
return "$$DownloadListenerProxy";
}

View File

@@ -44,10 +44,6 @@ public class UploadSchedulers
return INSTANCE;
}
@Override int getSchedulerType() {
return UPLOAD;
}
@Override String getProxySuffix() {
return "$$UploadListenerProxy";
}

View File

@@ -31,12 +31,14 @@ import java.lang.ref.WeakReference;
class BaseUListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
implements IUploadListener {
private WeakReference<Handler> outHandler;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastLen = 0; //上一次发送长度
private boolean isFirst = true;
protected ENTITY mEntity;
protected TASK mTask;
private boolean isConvertSpeed = false;
boolean isWait = false;
private long mLastSaveTime;
BaseUListener(TASK task, Handler outHandler) {
this.outHandler = new WeakReference<>(outHandler);
@@ -45,6 +47,7 @@ class BaseUListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
final AriaManager manager = AriaManager.getInstance(AriaManager.APP);
isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
mLastLen = mEntity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
}
@Override public void onPre() {
@@ -71,6 +74,10 @@ class BaseUListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
}
handleSpeed(speed);
sendInState2Target(ISchedulers.RUNNING);
if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL) {
saveData(IEntity.STATE_RUNNING, currentLocation);
mLastSaveTime = System.currentTimeMillis();
}
mLastLen = currentLocation;
}

View File

@@ -45,6 +45,9 @@ public class FtpUploadTarget
File file = new File(filePath);
mEntity.setFileName(file.getName());
mEntity.setFileSize(file.length());
//暂时不支持断点续传上传
//mTaskEntity.isSupportBP = false;
}
/**

View File

@@ -0,0 +1,74 @@
/*
* 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 android.support.annotation.NonNull;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by lyy on 2017/9/26.
* BufferedRandomAccessFile 转 InputStream 适配器
*/
final class FtpFISAdapter extends InputStream {
private BufferedRandomAccessFile mIs;
private ProgressCallback mCallback;
private int count;
interface ProgressCallback {
void onProgressCallback(byte[] buffer, int byteOffset, int byteCount) throws IOException;
}
FtpFISAdapter(@NonNull BufferedRandomAccessFile is, @NonNull ProgressCallback callback) {
mIs = is;
mCallback = callback;
}
FtpFISAdapter(@NonNull BufferedRandomAccessFile is) {
mIs = is;
}
@Override public void close() throws IOException {
mIs.close();
}
@Override public int read() throws IOException {
return mIs.read();
}
@Override public int read(@NonNull byte[] buffer) throws IOException {
count = mIs.read(buffer);
if (mCallback != null) {
mCallback.onProgressCallback(buffer, 0, count);
}
return count;
}
@Override public int read(@NonNull byte[] buffer, int byteOffset, int byteCount)
throws IOException {
count = mIs.read(buffer, byteOffset, byteCount);
if (mCallback != null) {
mCallback.onProgressCallback(buffer, byteOffset, byteCount);
}
return count;
}
@Override public long skip(long byteCount) throws IOException {
return mIs.skipBytes((int) byteCount);
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.Properties;
import org.apache.commons.net.ftp.FTPFile;
/**
* Created by Aria.Lao on 2017/9/26.
* 单任务远程服务器文件信息
*/
class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity> {
static final int CODE_COMPLETE = 0xab1;
private boolean isComplete = false;
FtpFileInfoThread(UploadTaskEntity taskEntity, OnFileInfoCallback callback) {
super(taskEntity, callback);
}
@Override protected String setRemotePath() {
String url = mEntity.getUrl();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length())
+ "/"
+ mEntity.getFileName();
}
/**
* 如果服务器的文件长度和本地上传文件的文件长度一致,则任务任务已完成。
* 否则重新修改保存的停止位置这是因为outputStream是读不到服务器是否成功写入的。
* 而threadTask的保存的停止位置是File的InputStream的所有就会导致两端停止位置不一致
*
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
if (ftpFile != null) {
//远程文件已完成
if (ftpFile.getSize() == mEntity.getFileSize()) {
isComplete = true;
} else {
File configFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
Properties pro = CommonUtil.loadConfig(configFile);
String key = mEntity.getFileName() + "_record_" + 0;
long oldRecord = Long.parseLong(pro.getProperty(key, "0"));
if (oldRecord != 0) {
//修改本地保存的停止地址为服务器上的真实地址
pro.setProperty(key, ftpFile.getSize() + "");
CommonUtil.saveConfig(configFile, pro);
}
}
}
}
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
mCallback.onComplete(mEntity.getKey(), isComplete ? CODE_COMPLETE : code);
}
}

View File

@@ -15,9 +15,8 @@
*/
package com.arialyy.aria.core.upload.uploader;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.AbsFtpThreadTask;
import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.inf.IEventListener;
@@ -26,29 +25,26 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.commons.net.ftp.FTP;
import java.io.UnsupportedEncodingException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.OnFtpInputStreamListener;
/**
* Created by Aria.Lao on 2017/7/28.
* FTP 单线程上传任务需要FTP 服务器给用户打开删除和读入IO的权限
*/
class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
private final String TAG = "FtpThreadTask";
private String dir, remotePath, charSet;
private String dir, remotePath;
FtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<UploadTaskEntity> info) {
super(constance, listener, info);
}
@Override public void run() {
FTPClient client = null;
OutputStream os = null;
BufferedRandomAccessFile file = null;
try {
Log.d(TAG, "任务【"
@@ -64,22 +60,16 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
mChildCurrentLocation = mConfig.START_LOCATION;
client = createClient();
if (client == null) return;
initPath();
client.makeDirectory(dir);
client.changeWorkingDirectory(dir);
client.setRestartOffset(mConfig.START_LOCATION);
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
file.seek(mConfig.START_LOCATION);
if (!isRemoteComplete(client)) {
os = client.storeFileStream(new String(remotePath.getBytes(charSet), SERVER_CHARSET));
//发送第二次指令时,还需要再做一次判断
int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply)) {
client.disconnect();
fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply, null);
return;
}
upload(file, os);
if (mConfig.START_LOCATION != 0) {
//file.skipBytes((int) mConfig.START_LOCATION);
file.seek(mConfig.START_LOCATION);
}
upload(client, file);
if (STATE.isCancel || STATE.isStop) return;
Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__上传完毕");
writeConfig(true, 1);
@@ -101,9 +91,6 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
if (file != null) {
file.close();
}
if (os != null) {
os.close();
}
if (client != null && client.isConnected()) {
client.disconnect();
}
@@ -113,78 +100,52 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
}
}
/**
* 远程文件是否已经玩飞车
*
* @return true 任务已经完成
*/
private boolean isRemoteComplete(FTPClient client) throws IOException {
FTPFile[] files = client.listFiles(new String(remotePath.getBytes(charSet), SERVER_CHARSET));
return files.length != 0 && files[0].getSize() == mEntity.getFileSize();
private void initPath() throws UnsupportedEncodingException {
String url = mEntity.getUrl();
String temp = url.substring(url.indexOf(port) + port.length(), url.length());
dir = new String(temp.getBytes(charSet), SERVER_CHARSET);
remotePath = new String((temp + "/" + mEntity.getFileName()).getBytes(charSet), SERVER_CHARSET);
}
/**
* 执行上传操作
*/
private void upload(BufferedRandomAccessFile file, OutputStream os)
throws IOException, InterruptedException {
int len;
byte[] buffer = new byte[mBufSize];
while ((len = file.read(buffer)) != -1) {
if (STATE.isCancel) break;
if (STATE.isStop) break;
if (mSleepTime > 0) Thread.sleep(mSleepTime);
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation);
os.write(buffer, 0, len);
progress(len);
break;
private void upload(final FTPClient client, final BufferedRandomAccessFile bis)
throws IOException {
try {
client.storeFile(remotePath, new FtpFISAdapter(bis), new OnFtpInputStreamListener() {
boolean isStoped = false;
@Override public void onFtpInputStream(FTPClient client, long totalBytesTransferred,
int bytesTransferred, long streamSize) {
if ((STATE.isCancel || STATE.isStop) && !isStoped) {
try {
isStoped = true;
client.abor();
} catch (IOException e) {
e.printStackTrace();
}
}
progress(bytesTransferred);
}
});
} catch (IOException e) {
if (e.getMessage().contains("IOException caught while copying")) {
e.printStackTrace();
} else {
os.write(buffer, 0, len);
progress(len);
fail(mChildCurrentLocation, "上传失败", e);
}
}
}
/**
* 构建FTP客户端
*/
private FTPClient createClient() throws IOException {
String url = mEntity.getUrl();
String[] pp = url.split("/")[2].split(":");
String serverIp = pp[0];
int port = Integer.parseInt(pp[1]);
dir = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
remotePath = dir + "/" + mEntity.getFileName();
FTPClient client = new FTPClient();
client.connect(serverIp, port);
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器错误码为" + reply, null);
return null;
if (client.isConnected()) {
client.disconnect();
}
if (reply == FTPReply.TRANSFER_ABORTED) return;
fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply, null);
}
charSet = "UTF-8";
// 开启服务器对UTF-8的支持如果服务器支持就用UTF-8编码
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(STATE.READ_TIME_OUT);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.allocate(mBufSize);
return client;
}
@Override protected String getTaskType() {
return "FTP_UPLOAD";
}
}

View File

@@ -16,6 +16,7 @@
package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.inf.IUploadListener;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
@@ -46,7 +47,19 @@ public class SimpleUploadUtil implements IUtil, Runnable {
@Override public void run() {
mListener.onPre();
mUploader.start();
new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) {
if (code == FtpFileInfoThread.CODE_COMPLETE) {
mListener.onComplete();
} else {
mUploader.start();
}
}
@Override public void onFail(String url, String errorMsg) {
mListener.onFail(true);
}
}).start();
}
@Override public long getFileSize() {

View File

@@ -15,7 +15,6 @@
*/
package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsFileer;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.SubThreadConfig;
@@ -47,10 +46,7 @@ class Uploader extends AbsFileer<UploadEntity, UploadTaskEntity> {
* 5、不支持断点则是新任务
*/
protected void checkTask() {
mConfigFile = new File(mContext.getFilesDir().getPath()
+ AriaManager.UPLOAD_TEMP_DIR
+ mEntity.getFileName()
+ ".properties");
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
if (!mTaskEntity.isSupportBP) {
isNewTask = true;
return;

View File

@@ -230,7 +230,7 @@ final class SqlHelper extends SQLiteOpenHelper {
}
/**
* 遍历所有数据
* 查找表的所有数据
*/
static synchronized <T extends DbEntity> List<T> findAllData(SQLiteDatabase db, Class<T> clazz) {
db = checkDb(db);

View File

@@ -266,7 +266,7 @@ public class CommonUtil {
file.delete();
}
}
File config = new File(getFileConfig(false, uEntity.getFileName()));
File config = new File(getFileConfigPath(false, uEntity.getFileName()));
if (config.exists()) {
config.delete();
}
@@ -296,7 +296,7 @@ public class CommonUtil {
}
}
File config = new File(getFileConfig(true, dEntity.getFileName()));
File config = new File(getFileConfigPath(true, dEntity.getFileName()));
if (config.exists()) {
config.delete();
}
@@ -705,6 +705,7 @@ public class CommonUtil {
* 设置打印的异常格式
*/
public static String getPrintException(Throwable ex) {
if (ex == null) return "";
StringBuilder err = new StringBuilder();
err.append("ExceptionDetailed:\n");
err.append("====================Exception Info====================\n");
@@ -729,11 +730,11 @@ public class CommonUtil {
}
/**
* 通过文件名获取下载配置文件
* 通过文件名获取下载配置文件路径
*
* @param fileName 文件名
*/
public static String getFileConfig(boolean isDownload, String fileName) {
public static String getFileConfigPath(boolean isDownload, String fileName) {
return AriaManager.APP.getFilesDir().getPath() + (isDownload ? AriaManager.DOWNLOAD_TEMP_DIR
: AriaManager.UPLOAD_TEMP_DIR) + fileName + ".properties";
}
@@ -764,8 +765,8 @@ public class CommonUtil {
private static void renameConfig(boolean isDownload, String oldName, String newName) {
if (oldName.equals(newName)) return;
File oldFile = new File(getFileConfig(isDownload, oldName));
File newFile = new File(getFileConfig(isDownload, oldName));
File oldFile = new File(getFileConfigPath(isDownload, oldName));
File newFile = new File(getFileConfigPath(isDownload, oldName));
if (!oldFile.exists()) {
createFile(newFile.getPath());
} else {

View File

@@ -0,0 +1,136 @@
/*
* 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.util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
/**
* 跟网络相关的工具类
*/
public class NetUtils {
/**
* 没有网络
*/
public static final int NETWORK_TYPE_INVALID = 0;
/**
* wap网络
*/
public static final int NETWORK_TYPE_WAP = 1;
/**
* 2G网络
*/
public static final int NETWORK_TYPE_2G = 2;
/**
* 3G和3G以上网络或统称为快速网络
*/
public static final int NETWORK_TYPE_3G = 3;
/**
* wifi网络
*/
public static final int NETWORK_TYPE_WIFI = 4;
/**
* 判断网络是否连接
*/
public static boolean isConnected(Context context) {
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
return ni != null && ni.isConnectedOrConnecting();
}
/**
* 判断是否是wifi连接
*/
public static boolean isWifi(Context context) {
return getNetWorkType(context) == NETWORK_TYPE_WIFI;
}
/**
* 获取网络状态wifi,wap,2g,3g.
*
* @param context 上下文
* @return int 网络状态 {@link #NETWORK_TYPE_2G},{@link #NETWORK_TYPE_3G},
* {@link #NETWORK_TYPE_INVALID},{@link #NETWORK_TYPE_WAP},{@link #NETWORK_TYPE_WIFI}
*/
public static int getNetWorkType(Context context) {
int netWorkType = -1;
ConnectivityManager manager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
String type = networkInfo.getTypeName();
if (type.equalsIgnoreCase("WIFI")) {
netWorkType = NETWORK_TYPE_WIFI;
} else if (type.equalsIgnoreCase("MOBILE")) {
String proxyHost = android.net.Proxy.getDefaultHost();
netWorkType = TextUtils.isEmpty(proxyHost) ? (isFastMobileNetwork(context) ? NETWORK_TYPE_3G
: NETWORK_TYPE_2G) : NETWORK_TYPE_WAP;
}
} else {
netWorkType = NETWORK_TYPE_INVALID;
}
return netWorkType;
}
private static boolean isFastMobileNetwork(Context context) {
TelephonyManager telephonyManager =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
switch (telephonyManager.getNetworkType()) {
case TelephonyManager.NETWORK_TYPE_1xRTT:
return false; // ~ 50-100 kbps
case TelephonyManager.NETWORK_TYPE_CDMA:
return false; // ~ 14-64 kbps
case TelephonyManager.NETWORK_TYPE_EDGE:
return false; // ~ 50-100 kbps
case TelephonyManager.NETWORK_TYPE_EVDO_0:
return true; // ~ 400-1000 kbps
case TelephonyManager.NETWORK_TYPE_EVDO_A:
return true; // ~ 600-1400 kbps
case TelephonyManager.NETWORK_TYPE_GPRS:
return false; // ~ 100 kbps
case TelephonyManager.NETWORK_TYPE_HSDPA:
return true; // ~ 2-14 Mbps
case TelephonyManager.NETWORK_TYPE_HSPA:
return true; // ~ 700-1700 kbps
case TelephonyManager.NETWORK_TYPE_HSUPA:
return true; // ~ 1-23 Mbps
case TelephonyManager.NETWORK_TYPE_UMTS:
return true; // ~ 400-7000 kbps
case TelephonyManager.NETWORK_TYPE_EHRPD:
return true; // ~ 1-2 Mbps
case TelephonyManager.NETWORK_TYPE_EVDO_B:
return true; // ~ 5 Mbps
case TelephonyManager.NETWORK_TYPE_HSPAP:
return true; // ~ 10-20 Mbps
case TelephonyManager.NETWORK_TYPE_IDEN:
return false; // ~25 kbps
case TelephonyManager.NETWORK_TYPE_LTE:
return true; // ~ 10+ Mbps
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
return false;
default:
return false;
}
}
}