2016-04-21 23:28:01 +00:00
|
|
|
package us.shandian.giga.get;
|
|
|
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
import java.io.FileNotFoundException;
|
2018-11-26 03:20:25 +00:00
|
|
|
import java.io.InputStream;
|
2016-04-21 23:28:01 +00:00
|
|
|
import java.io.RandomAccessFile;
|
|
|
|
import java.net.HttpURLConnection;
|
2018-09-23 18:12:23 +00:00
|
|
|
import java.nio.channels.ClosedByInterruptException;
|
2016-04-21 23:28:01 +00:00
|
|
|
|
|
|
|
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
|
|
|
|
2017-01-10 10:41:24 +00:00
|
|
|
/**
|
|
|
|
* Runnable to download blocks of a file until the file is completely downloaded,
|
|
|
|
* an error occurs or the process is stopped.
|
|
|
|
*/
|
2018-12-05 04:03:56 +00:00
|
|
|
public class DownloadRunnable extends Thread {
|
2017-06-28 05:27:32 +00:00
|
|
|
private static final String TAG = DownloadRunnable.class.getSimpleName();
|
|
|
|
|
|
|
|
private final DownloadMission mMission;
|
|
|
|
private final int mId;
|
|
|
|
|
2018-12-05 04:03:56 +00:00
|
|
|
private HttpURLConnection mConn;
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
DownloadRunnable(DownloadMission mission, int id) {
|
2017-06-28 05:27:32 +00:00
|
|
|
if (mission == null) throw new NullPointerException("mission is null");
|
|
|
|
mMission = mission;
|
|
|
|
mId = id;
|
2018-12-05 04:03:56 +00:00
|
|
|
mConn = null;
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
boolean retry = mMission.recovered;
|
2018-09-23 18:12:23 +00:00
|
|
|
long blockPosition = mMission.getBlockPosition(mId);
|
|
|
|
int retryCount = 0;
|
2017-06-28 05:27:32 +00:00
|
|
|
|
|
|
|
if (DEBUG) {
|
2018-09-23 18:12:23 +00:00
|
|
|
Log.d(TAG, mId + ":default pos " + blockPosition);
|
2017-06-28 05:27:32 +00:00
|
|
|
Log.d(TAG, mId + ":recovered: " + mMission.recovered);
|
|
|
|
}
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
RandomAccessFile f;
|
2018-11-26 03:20:25 +00:00
|
|
|
InputStream is = null;
|
2018-09-23 18:12:23 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
f = new RandomAccessFile(mMission.getDownloadedFile(), "rw");
|
|
|
|
} catch (FileNotFoundException e) {
|
|
|
|
mMission.notifyError(e);// this never should happen
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-05 04:03:56 +00:00
|
|
|
while (mMission.running && mMission.errCode == DownloadMission.ERROR_NOTHING && blockPosition < mMission.blocks) {
|
2017-06-28 05:27:32 +00:00
|
|
|
|
|
|
|
if (DEBUG && retry) {
|
2018-09-23 18:12:23 +00:00
|
|
|
Log.d(TAG, mId + ":retry is true. Resuming at " + blockPosition);
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for an unblocked position
|
2018-09-23 18:12:23 +00:00
|
|
|
while (!retry && blockPosition < mMission.blocks && mMission.isBlockPreserved(blockPosition)) {
|
2017-06-28 05:27:32 +00:00
|
|
|
|
|
|
|
if (DEBUG) {
|
2018-09-23 18:12:23 +00:00
|
|
|
Log.d(TAG, mId + ":position " + blockPosition + " preserved, passing");
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
blockPosition++;
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
retry = false;
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
if (blockPosition >= mMission.blocks) {
|
2017-06-28 05:27:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG) {
|
2018-09-23 18:12:23 +00:00
|
|
|
Log.d(TAG, mId + ":preserving position " + blockPosition);
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
mMission.preserveBlock(blockPosition);
|
|
|
|
mMission.setBlockPosition(mId, blockPosition);
|
2017-06-28 05:27:32 +00:00
|
|
|
|
2018-11-26 03:20:25 +00:00
|
|
|
long start = blockPosition * DownloadMission.BLOCK_SIZE;
|
2018-09-23 18:12:23 +00:00
|
|
|
long end = start + DownloadMission.BLOCK_SIZE - 1;
|
2018-12-05 04:03:56 +00:00
|
|
|
long offset = mMission.getThreadBytePosition(mId);
|
2017-06-28 05:27:32 +00:00
|
|
|
|
2018-12-05 04:03:56 +00:00
|
|
|
start += offset;
|
2018-11-26 03:20:25 +00:00
|
|
|
|
2017-06-28 05:27:32 +00:00
|
|
|
if (end >= mMission.length) {
|
|
|
|
end = mMission.length - 1;
|
|
|
|
}
|
|
|
|
|
2018-11-24 03:14:37 +00:00
|
|
|
long total = 0;
|
2017-06-28 05:27:32 +00:00
|
|
|
|
|
|
|
try {
|
2018-12-05 04:03:56 +00:00
|
|
|
mConn = mMission.openConnection(mId, start, end);
|
|
|
|
mMission.establishConnection(mId, mConn);
|
|
|
|
|
|
|
|
// check if the download can be resumed
|
|
|
|
if (mConn.getResponseCode() == 416 && offset > 0) {
|
|
|
|
retryCount--;
|
|
|
|
throw new DownloadMission.HttpError(416);
|
|
|
|
}
|
2017-06-28 05:27:32 +00:00
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
// The server may be ignoring the range request
|
2018-12-05 04:03:56 +00:00
|
|
|
if (mConn.getResponseCode() != 206) {
|
|
|
|
mMission.notifyError(new DownloadMission.HttpError(mConn.getResponseCode()));
|
2017-06-28 05:27:32 +00:00
|
|
|
|
|
|
|
if (DEBUG) {
|
2018-12-05 04:03:56 +00:00
|
|
|
Log.e(TAG, mId + ":Unsupported " + mConn.getResponseCode());
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
f.seek(mMission.offsets[mMission.current] + start);
|
|
|
|
|
2018-12-05 04:03:56 +00:00
|
|
|
is = mConn.getInputStream();
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
byte[] buf = new byte[DownloadMission.BUFFER_SIZE];
|
|
|
|
int len;
|
|
|
|
|
2018-11-26 03:20:25 +00:00
|
|
|
while (start < end && mMission.running && (len = is.read(buf, 0, buf.length)) != -1) {
|
2018-09-23 18:12:23 +00:00
|
|
|
f.write(buf, 0, len);
|
|
|
|
start += len;
|
|
|
|
total += len;
|
|
|
|
mMission.notifyProgress(len);
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG && mMission.running) {
|
2018-11-26 03:20:25 +00:00
|
|
|
Log.d(TAG, mId + ":position " + blockPosition + " finished, " + total + " bytes downloaded");
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
|
2018-12-05 04:03:56 +00:00
|
|
|
if (mMission.running)
|
|
|
|
mMission.setThreadBytePosition(mId, 0L);// clear byte position for next block
|
|
|
|
else
|
|
|
|
mMission.setThreadBytePosition(mId, total);// download paused, save progress for this block
|
|
|
|
|
2017-06-28 05:27:32 +00:00
|
|
|
} catch (Exception e) {
|
2018-09-23 18:12:23 +00:00
|
|
|
mMission.setThreadBytePosition(mId, total);
|
2017-06-28 05:27:32 +00:00
|
|
|
|
2018-12-05 04:03:56 +00:00
|
|
|
if (!mMission.running || e instanceof ClosedByInterruptException) break;
|
2018-09-23 18:12:23 +00:00
|
|
|
|
2018-11-26 03:20:25 +00:00
|
|
|
if (retryCount++ >= mMission.maxRetry) {
|
2018-09-23 18:12:23 +00:00
|
|
|
mMission.notifyError(e);
|
|
|
|
break;
|
|
|
|
}
|
2017-06-28 05:27:32 +00:00
|
|
|
|
|
|
|
if (DEBUG) {
|
2018-09-23 18:12:23 +00:00
|
|
|
Log.d(TAG, mId + ":position " + blockPosition + " retrying due exception", e);
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
2018-11-26 03:20:25 +00:00
|
|
|
|
|
|
|
retry = true;
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
try {
|
2018-12-05 04:03:56 +00:00
|
|
|
if (is != null) is.close();
|
2018-09-23 18:12:23 +00:00
|
|
|
} catch (Exception err) {
|
2018-12-05 04:03:56 +00:00
|
|
|
// nothing to do
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
try {
|
2018-12-05 04:03:56 +00:00
|
|
|
f.close();
|
2018-09-23 18:12:23 +00:00
|
|
|
} catch (Exception err) {
|
2018-12-05 04:03:56 +00:00
|
|
|
// ¿ejected media storage? ¿file deleted? ¿storage ran out of space?
|
2018-09-23 18:12:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "thread " + mId + " exited from main download loop");
|
|
|
|
}
|
2018-12-05 04:03:56 +00:00
|
|
|
|
2018-09-23 18:12:23 +00:00
|
|
|
if (mMission.errCode == DownloadMission.ERROR_NOTHING && mMission.running) {
|
2017-06-28 05:27:32 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "no error has happened, notifying");
|
|
|
|
}
|
2018-09-23 18:12:23 +00:00
|
|
|
mMission.notifyFinished();
|
2017-06-28 05:27:32 +00:00
|
|
|
}
|
2018-12-05 04:03:56 +00:00
|
|
|
|
2017-06-28 05:27:32 +00:00
|
|
|
if (DEBUG && !mMission.running) {
|
|
|
|
Log.d(TAG, "The mission has been paused. Passing.");
|
|
|
|
}
|
|
|
|
}
|
2018-12-05 04:03:56 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void interrupt() {
|
|
|
|
super.interrupt();
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (mConn != null) mConn.disconnect();
|
|
|
|
} catch (Exception e) {
|
|
|
|
// nothing to do
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-21 23:28:01 +00:00
|
|
|
}
|