package cn.rongcloud.im.server.network.http;
import android.text.TextUtils;
import android.util.Log;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import cn.rongcloud.im.server.utils.MD5;
public class BreakpointHttpResponseHandler extends AsyncHttpResponseHandler {
private final String tag = BreakpointHttpResponseHandler.class.getSimpleName();
/** 临时文件后缀 **/
private static final String TEMP_SUFFIX = ".download";
/** 请求url **/
private String url;
/** 临时文件,上一次保存的数据 **/
private File tempFile;
/** 最后目标文件 **/
private File targetFile;
/** 文件保存目录 **/
private File baseDirFile;
/** 上一次保存文件的大小 **/
private long previousFileSize;
/** 文件总大小 **/
private long totalSize;
/** 已经下载文件的大小 **/
private long downloadSize;
/** 是否暂停标识 **/
private boolean interrupt = false;
/** RandomAccessFile **/
private RandomAccessFile randomAccessFile;
/**
* 构造方法
*/
public BreakpointHttpResponseHandler(String url, String rootFile) {
this.url = url;
String fileName = getFileName(url);
this.baseDirFile = new File(rootFile);
this.targetFile = new File(rootFile, fileName);
this.tempFile = new File(rootFile, fileName + TEMP_SUFFIX);
if (!this.baseDirFile.exists()) {
this.baseDirFile.mkdirs();
}
}
/**
* 根据url得到文件名
* @param url
* @return
*/
public String getFileName(String url) {
StringBuilder fileName = new StringBuilder(MD5.encrypt(url));
if (!TextUtils.isEmpty(url)) {
if (url.indexOf(".") > 0) {
int index = url.lastIndexOf(".");
fileName.append(url.substring(index, url.length()));
}
}
return fileName.toString();
}
public void onSuccess(File file) {
}
public void onSuccess(int statusCode, File file) {
onSuccess(file);
}
public void onSuccess(int statusCode, Header[] headers, File file) {
onSuccess(statusCode, file);
}
@SuppressWarnings("deprecation")
public void onFailure(Throwable e, File response) {
onFailure(e);
}
public void onFailure(int statusCode, Throwable e, File response) {
onFailure(e, response);
}
public void onFailure(int statusCode, Header[] headers, Throwable e, File response) {
onFailure(statusCode, e, response);
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
onFailure(statusCode, headers, error, getTargetFile());
}
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
onSuccess(statusCode, headers, getTargetFile());
}
@Override
public void sendResponseMessage(HttpResponse response) {
if (!Thread.currentThread().isInterrupted() && !interrupt) {
Throwable error = null;
InputStream instream = null;
StatusLine status = response.getStatusLine();
HttpEntity entity = response.getEntity();
try {
if (entity == null) {
throw new IOException("Fail download. entity is null.");
}
// 处理contentLength
long contentLength = entity.getContentLength();
if (contentLength == -1) {
contentLength = entity.getContent().available();
}
//如果临时文件存在,得到之前下载的大小
if (tempFile.exists()) {
previousFileSize = tempFile.length();
}
// 得到总大小,包括之前已经下载的
totalSize = contentLength + previousFileSize;
if (targetFile.exists() && totalSize == targetFile.length()) {
Log.e(tag, "Output file already exists. Skipping download.");
sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), "success".getBytes());
return;
}
//获取当前下载文件流
instream = entity.getContent();
if (instream == null) {
throw new IOException("Fail download. instream is null.");
}
randomAccessFile = new RandomAccessFile(tempFile, "rw");
randomAccessFile.seek(randomAccessFile.length());
byte[] buffer = new byte[BUFFER_SIZE];
int length, count = 0;
while ((length = instream.read(buffer)) != -1 && !Thread.currentThread().isInterrupted() && !interrupt) {
count += length;
downloadSize = count + previousFileSize;
randomAccessFile.write(buffer, 0, length);
sendProgressMessage((int)downloadSize, (int)totalSize);
}
//判断下载大小与总大小不一致
if (!Thread.currentThread().isInterrupted() && !interrupt) {
if (downloadSize != totalSize && totalSize != -1) {
throw new IOException("Fail download. totalSize not eq downloadSize.");
}
}
} catch (IllegalStateException e) {
e.printStackTrace();
error = e;
} catch (FileNotFoundException e) {
e.printStackTrace();
error = e;
} catch (IOException e) {
e.printStackTrace();
error = e;
} finally {
try {
if (instream != null) instream.close();
if (randomAccessFile != null) randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
error = e;
}
}
// additional cancellation check as getResponseData() can take non-zero time to process
if (!Thread.currentThread().isInterrupted() && !interrupt) {
if (status.getStatusCode() >= 300 || error != null) {
sendFailureMessage(status.getStatusCode(),
response.getAllHeaders(), error.getMessage().getBytes(),
new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()));
} else {
tempFile.renameTo(targetFile);
sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), "success".getBytes());
}
}
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public void setTempFile(File tempFile) {
this.tempFile = tempFile;
}
public File getTempFile() {
return tempFile;
}
public File getTargetFile() {
return targetFile;
}
public void setTargetFile(File targetFile) {
this.targetFile = targetFile;
}
public long getPreviousFileSize() {
return previousFileSize;
}
public void setPreviousFileSize(long previousFileSize) {
this.previousFileSize = previousFileSize;
}
public boolean isInterrupt() {
return interrupt;
}
public void setInterrupt(boolean interrupt) {
this.interrupt = interrupt;
}
}