2013-10-25 17:19:00 +02:00
|
|
|
/*
|
2015-10-29 18:10:07 +01:00
|
|
|
* This is the source code of Telegram for Android v. 3.x.x.
|
2013-10-25 17:19:00 +02:00
|
|
|
* It is licensed under GNU GPL v. 2 or later.
|
|
|
|
* You should have received a copy of the license in this archive (see LICENSE).
|
|
|
|
*
|
2016-01-11 18:19:48 +01:00
|
|
|
* Copyright Nikolai Kudashov, 2013-2016.
|
2013-10-25 17:19:00 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
package org.telegram.messenger;
|
|
|
|
|
2015-09-24 22:52:02 +02:00
|
|
|
import org.telegram.tgnet.ConnectionsManager;
|
|
|
|
import org.telegram.tgnet.RequestDelegate;
|
|
|
|
import org.telegram.tgnet.TLObject;
|
|
|
|
import org.telegram.tgnet.TLRPC;
|
|
|
|
|
2013-10-25 17:19:00 +02:00
|
|
|
import java.io.RandomAccessFile;
|
|
|
|
import java.io.File;
|
2014-02-28 23:28:25 +01:00
|
|
|
import java.nio.channels.FileChannel;
|
2014-07-03 00:39:05 +02:00
|
|
|
import java.util.ArrayList;
|
2013-10-25 17:19:00 +02:00
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
|
|
public class FileLoadOperation {
|
2014-07-03 00:39:05 +02:00
|
|
|
|
|
|
|
private static class RequestInfo {
|
2016-01-11 18:19:48 +01:00
|
|
|
private int requestToken;
|
|
|
|
private int offset;
|
|
|
|
private TLRPC.TL_upload_file response;
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
|
2014-08-22 16:24:33 +02:00
|
|
|
private final static int stateIdle = 0;
|
|
|
|
private final static int stateDownloading = 1;
|
|
|
|
private final static int stateFailed = 2;
|
|
|
|
private final static int stateFinished = 3;
|
|
|
|
|
2014-07-03 00:39:05 +02:00
|
|
|
private final static int downloadChunkSize = 1024 * 32;
|
2015-07-22 20:56:37 +02:00
|
|
|
private final static int downloadChunkSizeBig = 1024 * 128;
|
2015-09-24 22:52:02 +02:00
|
|
|
private final static int maxDownloadRequests = 4;
|
|
|
|
private final static int maxDownloadRequestsBig = 2;
|
|
|
|
private final static int bigFileSizeFrom = 1024 * 1024;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
2014-08-22 16:24:33 +02:00
|
|
|
private int datacenter_id;
|
|
|
|
private TLRPC.InputFileLocation location;
|
|
|
|
private volatile int state = stateIdle;
|
2013-10-25 17:19:00 +02:00
|
|
|
private int downloadedBytes;
|
2014-08-22 16:24:33 +02:00
|
|
|
private int totalBytesCount;
|
|
|
|
private FileLoadOperationDelegate delegate;
|
2013-10-25 17:19:00 +02:00
|
|
|
private byte[] key;
|
|
|
|
private byte[] iv;
|
2015-07-22 20:56:37 +02:00
|
|
|
private int currentDownloadChunkSize;
|
2015-09-24 22:52:02 +02:00
|
|
|
private int currentMaxDownloadRequests;
|
|
|
|
private int requestsCount;
|
2015-12-09 19:27:52 +01:00
|
|
|
private int renameRetryCount;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
2016-01-11 18:19:48 +01:00
|
|
|
private int nextDownloadOffset;
|
2015-09-24 22:52:02 +02:00
|
|
|
private ArrayList<RequestInfo> requestInfos;
|
|
|
|
private ArrayList<RequestInfo> delayedRequestInfos;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
|
|
|
private File cacheFileTemp;
|
|
|
|
private File cacheFileFinal;
|
2013-12-20 20:25:49 +01:00
|
|
|
private File cacheIvTemp;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
2013-12-26 12:43:37 +01:00
|
|
|
private String ext;
|
2013-10-25 17:19:00 +02:00
|
|
|
private RandomAccessFile fileOutputStream;
|
2014-07-03 00:39:05 +02:00
|
|
|
private RandomAccessFile fiv;
|
2016-01-11 18:19:48 +01:00
|
|
|
private File storePath;
|
|
|
|
private File tempPath;
|
|
|
|
private boolean isForceRequest;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
2015-03-19 00:09:45 +01:00
|
|
|
public interface FileLoadOperationDelegate {
|
|
|
|
void didFinishLoadingFile(FileLoadOperation operation, File finalFile);
|
|
|
|
void didFailedLoadingFile(FileLoadOperation operation, int state);
|
|
|
|
void didChangedLoadProgress(FileLoadOperation operation, float progress);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
public FileLoadOperation(TLRPC.FileLocation photoLocation, String extension, int size) {
|
2014-08-22 16:24:33 +02:00
|
|
|
if (photoLocation instanceof TLRPC.TL_fileEncryptedLocation) {
|
2013-10-25 17:19:00 +02:00
|
|
|
location = new TLRPC.TL_inputEncryptedFileLocation();
|
2014-08-22 16:24:33 +02:00
|
|
|
location.id = photoLocation.volume_id;
|
|
|
|
location.volume_id = photoLocation.volume_id;
|
|
|
|
location.access_hash = photoLocation.secret;
|
|
|
|
location.local_id = photoLocation.local_id;
|
2013-10-25 17:19:00 +02:00
|
|
|
iv = new byte[32];
|
2014-08-22 16:24:33 +02:00
|
|
|
System.arraycopy(photoLocation.iv, 0, iv, 0, iv.length);
|
|
|
|
key = photoLocation.key;
|
|
|
|
datacenter_id = photoLocation.dc_id;
|
|
|
|
} else if (photoLocation instanceof TLRPC.TL_fileLocation) {
|
2013-10-25 17:19:00 +02:00
|
|
|
location = new TLRPC.TL_inputFileLocation();
|
2014-08-22 16:24:33 +02:00
|
|
|
location.volume_id = photoLocation.volume_id;
|
|
|
|
location.secret = photoLocation.secret;
|
|
|
|
location.local_id = photoLocation.local_id;
|
|
|
|
datacenter_id = photoLocation.dc_id;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
totalBytesCount = size;
|
2015-05-21 23:27:27 +02:00
|
|
|
ext = extension != null ? extension : "jpg";
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
|
2013-12-26 12:43:37 +01:00
|
|
|
public FileLoadOperation(TLRPC.Document documentLocation) {
|
2016-03-06 02:49:31 +01:00
|
|
|
try {
|
|
|
|
if (documentLocation instanceof TLRPC.TL_documentEncrypted) {
|
|
|
|
location = new TLRPC.TL_inputEncryptedFileLocation();
|
|
|
|
location.id = documentLocation.id;
|
|
|
|
location.access_hash = documentLocation.access_hash;
|
|
|
|
datacenter_id = documentLocation.dc_id;
|
|
|
|
iv = new byte[32];
|
|
|
|
System.arraycopy(documentLocation.iv, 0, iv, 0, iv.length);
|
|
|
|
key = documentLocation.key;
|
|
|
|
} else if (documentLocation instanceof TLRPC.TL_document) {
|
|
|
|
location = new TLRPC.TL_inputDocumentFileLocation();
|
|
|
|
location.id = documentLocation.id;
|
|
|
|
location.access_hash = documentLocation.access_hash;
|
|
|
|
datacenter_id = documentLocation.dc_id;
|
|
|
|
}
|
|
|
|
if (totalBytesCount <= 0) {
|
|
|
|
totalBytesCount = documentLocation.size;
|
|
|
|
}
|
2016-01-11 18:19:48 +01:00
|
|
|
ext = FileLoader.getDocumentFileName(documentLocation);
|
|
|
|
int idx;
|
|
|
|
if (ext == null || (idx = ext.lastIndexOf(".")) == -1) {
|
2013-12-26 12:43:37 +01:00
|
|
|
ext = "";
|
2016-01-11 18:19:48 +01:00
|
|
|
} else {
|
|
|
|
ext = ext.substring(idx);
|
2016-03-06 02:49:31 +01:00
|
|
|
}
|
|
|
|
if (ext.length() <= 1) {
|
|
|
|
if (documentLocation.mime_type != null) {
|
|
|
|
switch (documentLocation.mime_type) {
|
|
|
|
case "video/mp4":
|
|
|
|
ext = ".mp4";
|
|
|
|
break;
|
|
|
|
case "audio/ogg":
|
|
|
|
ext = ".ogg";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ext = "";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2016-01-11 18:19:48 +01:00
|
|
|
ext = "";
|
|
|
|
}
|
2013-12-26 12:43:37 +01:00
|
|
|
}
|
2016-03-06 02:49:31 +01:00
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
state = stateFailed;
|
|
|
|
cleanup();
|
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
|
|
|
}
|
|
|
|
});
|
2013-12-26 12:43:37 +01:00
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
|
2014-09-30 00:48:11 +02:00
|
|
|
public void setForceRequest(boolean forceRequest) {
|
|
|
|
isForceRequest = forceRequest;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isForceRequest() {
|
|
|
|
return isForceRequest;
|
|
|
|
}
|
|
|
|
|
2014-09-25 05:54:35 +02:00
|
|
|
public void setPaths(File store, File temp) {
|
|
|
|
storePath = store;
|
|
|
|
tempPath = temp;
|
|
|
|
}
|
|
|
|
|
2013-10-25 17:19:00 +02:00
|
|
|
public void start() {
|
2014-08-22 16:24:33 +02:00
|
|
|
if (state != stateIdle) {
|
2013-10-25 17:19:00 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-09-24 22:52:02 +02:00
|
|
|
currentDownloadChunkSize = totalBytesCount >= bigFileSizeFrom ? downloadChunkSizeBig : downloadChunkSize;
|
|
|
|
currentMaxDownloadRequests = totalBytesCount >= bigFileSizeFrom ? maxDownloadRequestsBig : maxDownloadRequests;
|
|
|
|
requestInfos = new ArrayList<>(currentMaxDownloadRequests);
|
|
|
|
delayedRequestInfos = new ArrayList<>(currentMaxDownloadRequests - 1);
|
2014-08-22 16:24:33 +02:00
|
|
|
state = stateDownloading;
|
|
|
|
if (location == null) {
|
2016-03-06 02:49:31 +01:00
|
|
|
cleanup();
|
2013-12-20 20:25:49 +01:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2013-12-20 20:25:49 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
String fileNameFinal;
|
|
|
|
String fileNameTemp;
|
2013-12-20 20:25:49 +01:00
|
|
|
String fileNameIv = null;
|
2014-08-22 16:24:33 +02:00
|
|
|
if (location.volume_id != 0 && location.local_id != 0) {
|
2015-12-09 19:27:52 +01:00
|
|
|
fileNameTemp = location.volume_id + "_" + location.local_id + ".temp";
|
2015-01-02 23:15:07 +01:00
|
|
|
fileNameFinal = location.volume_id + "_" + location.local_id + "." + ext;
|
2013-12-20 20:25:49 +01:00
|
|
|
if (key != null) {
|
|
|
|
fileNameIv = location.volume_id + "_" + location.local_id + ".iv";
|
|
|
|
}
|
2015-01-02 23:15:07 +01:00
|
|
|
if (datacenter_id == Integer.MIN_VALUE || location.volume_id == Integer.MIN_VALUE || datacenter_id == 0) {
|
2014-08-22 16:24:33 +02:00
|
|
|
cleanup();
|
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2014-08-22 16:24:33 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
} else {
|
2015-12-09 19:27:52 +01:00
|
|
|
fileNameTemp = datacenter_id + "_" + location.id + ".temp";
|
2013-12-26 12:43:37 +01:00
|
|
|
fileNameFinal = datacenter_id + "_" + location.id + ext;
|
2013-12-20 20:25:49 +01:00
|
|
|
if (key != null) {
|
|
|
|
fileNameIv = datacenter_id + "_" + location.id + ".iv";
|
|
|
|
}
|
2015-01-02 23:15:07 +01:00
|
|
|
if (datacenter_id == 0 || location.id == 0) {
|
|
|
|
cleanup();
|
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
|
2014-09-25 05:54:35 +02:00
|
|
|
cacheFileFinal = new File(storePath, fileNameFinal);
|
2014-08-22 16:24:33 +02:00
|
|
|
boolean exist = cacheFileFinal.exists();
|
|
|
|
if (exist && totalBytesCount != 0 && totalBytesCount != cacheFileFinal.length()) {
|
|
|
|
cacheFileFinal.delete();
|
2013-12-26 12:43:37 +01:00
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
|
2014-08-22 16:24:33 +02:00
|
|
|
if (!cacheFileFinal.exists()) {
|
2014-09-25 05:54:35 +02:00
|
|
|
cacheFileTemp = new File(tempPath, fileNameTemp);
|
2013-10-25 17:19:00 +02:00
|
|
|
if (cacheFileTemp.exists()) {
|
2015-12-09 19:27:52 +01:00
|
|
|
downloadedBytes = (int) cacheFileTemp.length();
|
2015-07-22 20:56:37 +02:00
|
|
|
nextDownloadOffset = downloadedBytes = downloadedBytes / currentDownloadChunkSize * currentDownloadChunkSize;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2015-08-13 11:23:31 +02:00
|
|
|
|
|
|
|
if (BuildVars.DEBUG_VERSION) {
|
|
|
|
FileLog.d("tmessages", "start loading file to temp = " + cacheFileTemp + " final = " + cacheFileFinal);
|
|
|
|
}
|
|
|
|
|
2013-12-20 20:25:49 +01:00
|
|
|
if (fileNameIv != null) {
|
2014-09-25 05:54:35 +02:00
|
|
|
cacheIvTemp = new File(tempPath, fileNameIv);
|
2013-12-20 20:25:49 +01:00
|
|
|
try {
|
|
|
|
fiv = new RandomAccessFile(cacheIvTemp, "rws");
|
|
|
|
long len = cacheIvTemp.length();
|
|
|
|
if (len > 0 && len % 32 == 0) {
|
|
|
|
fiv.read(iv, 0, 32);
|
|
|
|
} else {
|
|
|
|
downloadedBytes = 0;
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
downloadedBytes = 0;
|
|
|
|
}
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
try {
|
|
|
|
fileOutputStream = new RandomAccessFile(cacheFileTemp, "rws");
|
|
|
|
if (downloadedBytes != 0) {
|
|
|
|
fileOutputStream.seek(downloadedBytes);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
2013-12-20 20:25:49 +01:00
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
if (fileOutputStream == null) {
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
2013-10-25 17:19:00 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
});
|
2013-12-20 20:25:49 +01:00
|
|
|
return;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
if (totalBytesCount != 0 && downloadedBytes == totalBytesCount) {
|
|
|
|
try {
|
|
|
|
onFinishLoadingFile();
|
|
|
|
} catch (Exception e) {
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
} else {
|
|
|
|
startDownloadRequest();
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
onFinishLoadingFile();
|
|
|
|
} catch (Exception e) {
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void cancel() {
|
2014-07-03 00:39:05 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2014-08-22 16:24:33 +02:00
|
|
|
if (state == stateFinished || state == stateFailed) {
|
2014-07-03 00:39:05 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
state = stateFailed;
|
2014-07-03 00:39:05 +02:00
|
|
|
cleanup();
|
2015-09-24 22:52:02 +02:00
|
|
|
if (requestInfos != null) {
|
2016-03-06 02:49:31 +01:00
|
|
|
for (int a = 0; a < requestInfos.size(); a++) {
|
|
|
|
RequestInfo requestInfo = requestInfos.get(a);
|
2015-09-24 22:52:02 +02:00
|
|
|
if (requestInfo.requestToken != 0) {
|
|
|
|
ConnectionsManager.getInstance().cancelRequest(requestInfo.requestToken, true);
|
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
}
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 1);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
});
|
2013-12-20 20:25:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void cleanup() {
|
2014-08-22 16:24:33 +02:00
|
|
|
try {
|
|
|
|
if (fileOutputStream != null) {
|
2015-12-09 19:27:52 +01:00
|
|
|
try {
|
|
|
|
fileOutputStream.getChannel().close();
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
fileOutputStream.close();
|
|
|
|
fileOutputStream = null;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
2013-12-20 20:25:49 +01:00
|
|
|
|
2014-08-22 16:24:33 +02:00
|
|
|
try {
|
|
|
|
if (fiv != null) {
|
|
|
|
fiv.close();
|
|
|
|
fiv = null;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
2015-09-24 22:52:02 +02:00
|
|
|
if (delayedRequestInfos != null) {
|
2015-12-09 19:27:52 +01:00
|
|
|
for (int a = 0; a < delayedRequestInfos.size(); a++) {
|
|
|
|
RequestInfo requestInfo = delayedRequestInfos.get(a);
|
2015-09-24 22:52:02 +02:00
|
|
|
if (requestInfo.response != null) {
|
|
|
|
requestInfo.response.disableFree = false;
|
|
|
|
requestInfo.response.freeResources();
|
|
|
|
}
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
2015-09-24 22:52:02 +02:00
|
|
|
delayedRequestInfos.clear();
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onFinishLoadingFile() throws Exception {
|
2014-08-22 16:24:33 +02:00
|
|
|
if (state != stateDownloading) {
|
2013-10-25 17:19:00 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
state = stateFinished;
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
|
|
|
if (cacheIvTemp != null) {
|
|
|
|
cacheIvTemp.delete();
|
2015-12-09 19:27:52 +01:00
|
|
|
cacheIvTemp = null;
|
2013-12-20 20:25:49 +01:00
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
if (cacheFileTemp != null) {
|
2015-12-09 19:27:52 +01:00
|
|
|
boolean renameResult = cacheFileTemp.renameTo(cacheFileFinal);
|
|
|
|
if (!renameResult) {
|
2015-08-13 11:23:31 +02:00
|
|
|
if (BuildVars.DEBUG_VERSION) {
|
2015-12-09 19:27:52 +01:00
|
|
|
FileLog.e("tmessages", "unable to rename temp = " + cacheFileTemp + " to final = " + cacheFileFinal + " retry = " + renameRetryCount);
|
|
|
|
}
|
|
|
|
renameRetryCount++;
|
|
|
|
if (renameRetryCount < 3) {
|
|
|
|
state = stateDownloading;
|
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
try {
|
|
|
|
onFinishLoadingFile();
|
|
|
|
} catch (Exception e) {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, 200);
|
|
|
|
return;
|
2015-08-13 11:23:31 +02:00
|
|
|
}
|
2015-02-01 19:51:02 +01:00
|
|
|
cacheFileFinal = cacheFileTemp;
|
|
|
|
}
|
2014-08-06 01:17:40 +02:00
|
|
|
}
|
2015-08-13 11:23:31 +02:00
|
|
|
if (BuildVars.DEBUG_VERSION) {
|
|
|
|
FileLog.e("tmessages", "finished downloading file to " + cacheFileFinal);
|
|
|
|
}
|
2015-02-01 19:51:02 +01:00
|
|
|
delegate.didFinishLoadingFile(FileLoadOperation.this, cacheFileFinal);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
|
2014-07-03 00:39:05 +02:00
|
|
|
private void processRequestResult(RequestInfo requestInfo, TLRPC.TL_error error) {
|
|
|
|
requestInfos.remove(requestInfo);
|
2014-06-20 21:34:16 +02:00
|
|
|
if (error == null) {
|
|
|
|
try {
|
2014-07-03 00:39:05 +02:00
|
|
|
if (downloadedBytes != requestInfo.offset) {
|
2014-08-22 16:24:33 +02:00
|
|
|
if (state == stateDownloading) {
|
2014-07-04 00:41:59 +02:00
|
|
|
delayedRequestInfos.add(requestInfo);
|
|
|
|
requestInfo.response.disableFree = true;
|
|
|
|
}
|
2014-06-20 21:34:16 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-04 00:41:59 +02:00
|
|
|
if (requestInfo.response.bytes == null || requestInfo.response.bytes.limit() == 0) {
|
2014-06-20 21:34:16 +02:00
|
|
|
onFinishLoadingFile();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (key != null) {
|
2014-07-03 00:39:05 +02:00
|
|
|
Utilities.aesIgeEncryption(requestInfo.response.bytes.buffer, key, iv, false, true, 0, requestInfo.response.bytes.limit());
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
|
|
|
if (fileOutputStream != null) {
|
|
|
|
FileChannel channel = fileOutputStream.getChannel();
|
2014-07-03 00:39:05 +02:00
|
|
|
channel.write(requestInfo.response.bytes.buffer);
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
|
|
|
if (fiv != null) {
|
|
|
|
fiv.seek(0);
|
|
|
|
fiv.write(iv);
|
|
|
|
}
|
2015-02-01 19:51:02 +01:00
|
|
|
int currentBytesSize = requestInfo.response.bytes.limit();
|
|
|
|
downloadedBytes += currentBytesSize;
|
2014-08-22 16:24:33 +02:00
|
|
|
if (totalBytesCount > 0 && state == stateDownloading) {
|
2014-06-20 21:34:16 +02:00
|
|
|
delegate.didChangedLoadProgress(FileLoadOperation.this, Math.min(1.0f, (float)downloadedBytes / (float)totalBytesCount));
|
|
|
|
}
|
|
|
|
|
2014-07-03 00:39:05 +02:00
|
|
|
for (int a = 0; a < delayedRequestInfos.size(); a++) {
|
|
|
|
RequestInfo delayedRequestInfo = delayedRequestInfos.get(a);
|
|
|
|
if (downloadedBytes == delayedRequestInfo.offset) {
|
|
|
|
delayedRequestInfos.remove(a);
|
|
|
|
processRequestResult(delayedRequestInfo, null);
|
|
|
|
delayedRequestInfo.response.disableFree = false;
|
|
|
|
delayedRequestInfo.response.freeResources();
|
|
|
|
break;
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-22 20:56:37 +02:00
|
|
|
if (currentBytesSize != currentDownloadChunkSize) {
|
2014-06-20 21:34:16 +02:00
|
|
|
onFinishLoadingFile();
|
2015-02-01 19:51:02 +01:00
|
|
|
} else {
|
2015-07-22 20:56:37 +02:00
|
|
|
if (totalBytesCount != downloadedBytes && downloadedBytes % currentDownloadChunkSize == 0 || totalBytesCount > 0 && totalBytesCount > downloadedBytes) {
|
2015-02-01 19:51:02 +01:00
|
|
|
startDownloadRequest();
|
|
|
|
} else {
|
|
|
|
onFinishLoadingFile();
|
|
|
|
}
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
cleanup();
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2014-06-20 21:34:16 +02:00
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (error.text.contains("FILE_MIGRATE_")) {
|
|
|
|
String errorMsg = error.text.replace("FILE_MIGRATE_", "");
|
|
|
|
Scanner scanner = new Scanner(errorMsg);
|
|
|
|
scanner.useDelimiter("");
|
|
|
|
Integer val;
|
|
|
|
try {
|
|
|
|
val = scanner.nextInt();
|
|
|
|
} catch (Exception e) {
|
|
|
|
val = null;
|
|
|
|
}
|
|
|
|
if (val == null) {
|
|
|
|
cleanup();
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2014-06-20 21:34:16 +02:00
|
|
|
} else {
|
|
|
|
datacenter_id = val;
|
|
|
|
nextDownloadOffset = 0;
|
|
|
|
startDownloadRequest();
|
|
|
|
}
|
|
|
|
} else if (error.text.contains("OFFSET_INVALID")) {
|
2015-07-22 20:56:37 +02:00
|
|
|
if (downloadedBytes % currentDownloadChunkSize == 0) {
|
2013-10-25 17:19:00 +02:00
|
|
|
try {
|
2014-06-20 21:34:16 +02:00
|
|
|
onFinishLoadingFile();
|
2013-10-25 17:19:00 +02:00
|
|
|
} catch (Exception e) {
|
2014-06-20 21:34:16 +02:00
|
|
|
FileLog.e("tmessages", e);
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
} else {
|
2014-06-20 21:34:16 +02:00
|
|
|
cleanup();
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
2014-09-30 00:48:11 +02:00
|
|
|
} else if (error.text.contains("RETRY_LIMIT")) {
|
|
|
|
cleanup();
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 2);
|
2014-06-20 21:34:16 +02:00
|
|
|
} else {
|
|
|
|
if (location != null) {
|
2015-11-26 22:04:02 +01:00
|
|
|
FileLog.e("tmessages", "" + location + " id = " + location.id + " local_id = " + location.local_id + " access_hash = " + location.access_hash + " volume_id = " + location.volume_id + " secret = " + location.secret);
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
|
|
|
cleanup();
|
2014-09-30 00:48:11 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startDownloadRequest() {
|
2015-09-24 22:52:02 +02:00
|
|
|
if (state != stateDownloading || totalBytesCount > 0 && nextDownloadOffset >= totalBytesCount || requestInfos.size() + delayedRequestInfos.size() >= currentMaxDownloadRequests) {
|
2014-06-20 21:34:16 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
int count = 1;
|
|
|
|
if (totalBytesCount > 0) {
|
2015-09-24 22:52:02 +02:00
|
|
|
count = Math.max(0, currentMaxDownloadRequests - requestInfos.size() - delayedRequestInfos.size());
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
|
|
|
|
for (int a = 0; a < count; a++) {
|
2014-06-20 21:34:16 +02:00
|
|
|
if (totalBytesCount > 0 && nextDownloadOffset >= totalBytesCount) {
|
2014-07-03 00:39:05 +02:00
|
|
|
break;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2015-07-22 20:56:37 +02:00
|
|
|
boolean isLast = totalBytesCount <= 0 || a == count - 1 || totalBytesCount > 0 && nextDownloadOffset + currentDownloadChunkSize >= totalBytesCount;
|
2014-07-03 00:39:05 +02:00
|
|
|
TLRPC.TL_upload_getFile req = new TLRPC.TL_upload_getFile();
|
2014-06-20 21:34:16 +02:00
|
|
|
req.location = location;
|
|
|
|
req.offset = nextDownloadOffset;
|
2015-07-22 20:56:37 +02:00
|
|
|
req.limit = currentDownloadChunkSize;
|
|
|
|
nextDownloadOffset += currentDownloadChunkSize;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
|
|
|
final RequestInfo requestInfo = new RequestInfo();
|
|
|
|
requestInfos.add(requestInfo);
|
|
|
|
requestInfo.offset = req.offset;
|
2015-09-24 22:52:02 +02:00
|
|
|
requestInfo.requestToken = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
|
2014-06-20 21:34:16 +02:00
|
|
|
@Override
|
|
|
|
public void run(TLObject response, TLRPC.TL_error error) {
|
2014-07-03 00:39:05 +02:00
|
|
|
requestInfo.response = (TLRPC.TL_upload_file) response;
|
|
|
|
processRequestResult(requestInfo, error);
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
2015-09-24 22:52:02 +02:00
|
|
|
}, null, (isForceRequest ? ConnectionsManager.RequestFlagForceDownload : 0) | ConnectionsManager.RequestFlagFailOnServerErrors, datacenter_id, requestsCount % 2 == 0 ? ConnectionsManager.ConnectionTypeDownload : ConnectionsManager.ConnectionTypeDownload2, isLast);
|
|
|
|
requestsCount++;
|
2014-06-20 21:34:16 +02:00
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
|
|
|
|
public void setDelegate(FileLoadOperationDelegate delegate) {
|
|
|
|
this.delegate = delegate;
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|