package com.xiaomi.xms.sales.request; import com.xiaomi.xms.sales.ShopApp; import com.xiaomi.xms.sales.util.Coder; import com.xiaomi.xms.sales.util.LogUtil; import com.xiaomi.xms.sales.util.Utils; import com.xiaomi.xms.sales.xmsf.account.LoginManager; import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpGet; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.SocketTimeoutException; public class RequestStream extends Request { private static final String TAG = "RequestStream"; private static final int BUFFER_SIZE = 1024; private static final String TEMP_DOWNLOADED_FILE_NAME_FORMAT = "%s_temp_downloaded"; private static final String CONN_RANGE_VALUE_FORMAT = "bytes=%d-"; private static final String CONN_RANGE_PROPERTY = "RANGE"; public RequestStream(String url) { super(url); setHttpMethod(HttpGet.METHOD_NAME); } public int requestStream(OutputStream outPutStream) { if (outPutStream == null) { return STATUS_PARAM_ERROR; } if (!Utils.Network.isNetWorkConnected(ShopApp.getContext())) { return STATUS_NETWORK_UNAVAILABLE; } int status = STATUS_CLIENT_ERROR; HttpURLConnection conn = null; InputStream inputStream = null; ByteArrayOutputStream baos = null; try { conn = super.getConn(); if (conn != null) { baos = null; // getTempDownloadData(); // 如果该文件下载过,那么进行断点下载,从已下载文件的末尾继续下载 if (baos != null) { conn.addRequestProperty(CONN_RANGE_PROPERTY, String.format(CONN_RANGE_VALUE_FORMAT, baos.size())); } else { baos = new ByteArrayOutputStream(); } conn.connect(); int responseCode = conn.getResponseCode(); LogUtil.d(TAG, "The response code is:" + responseCode); if (responseCode == HttpStatus.SC_OK || responseCode == HttpStatus.SC_PARTIAL_CONTENT) { inputStream = conn.getInputStream(); byte[] buff = new byte[BUFFER_SIZE]; int len = 0; while ((len = inputStream.read(buff)) != -1) { baos.write(buff, 0, len); } outPutStream.write(baos.toByteArray()); status = STATUS_OK; } else if (isServerError(responseCode)) { if (responseCode == HttpStatus.SC_UNAUTHORIZED) { LoginManager.getInstance().invalidAuthToken(); status = STATUS_AUTH_ERROR; } else { status = STATUS_SERVER_ERROR; } } else { status = STATUS_UNKNOWN_ERROR; } } } catch (SocketTimeoutException e) { e.printStackTrace(); status = STATUS_SERVICE_UNAVAILABLE; } catch (IOException e) { e.printStackTrace(); if (!Utils.Network.isNetWorkConnected(ShopApp.getContext())) { status = STATUS_NETWORK_UNAVAILABLE; } } finally { if (conn != null) { conn.disconnect(); } if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (status != STATUS_OK && baos != null && baos.size() > 0) { saveTemporaryDownloadedData(baos); } if (baos != null) { try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } } return status; } /** * 将已经下载的文件存储到Cache中供再次下载使用。文件名以File的SHA1命名。 */ private void saveTemporaryDownloadedData(ByteArrayOutputStream out) { FileOutputStream outputStream = null; try { outputStream = new FileOutputStream(ShopApp.getContext().getCacheDir() + File.separator + String.format(TEMP_DOWNLOADED_FILE_NAME_FORMAT, Coder.encodeSHA(getRequestUrl()))); outputStream.write(out.toByteArray()); outputStream.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 检查Cache中是否存在待下载文件的临时文件,该文件可能是某次下载已完成的部分,以文件的SHA1命名。 * 这个文件用来支持断点续传。为了减少Cache的占用,每次读取后删除该文件。 */ private ByteArrayOutputStream getTempDownloadData() { File file = new File(ShopApp.getContext().getCacheDir() + File.separator + String.format(TEMP_DOWNLOADED_FILE_NAME_FORMAT, Coder.encodeSHA(getRequestUrl()))); ByteArrayOutputStream outputStream = null; InputStream inputStream = null; if (file.exists()) { try { inputStream = new FileInputStream(file); outputStream = new ByteArrayOutputStream(); byte[] buff = new byte[BUFFER_SIZE]; int len = 0; while ((len = inputStream.read(buff)) != -1) { outputStream.write(buff, 0, len); } outputStream.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } // 删除临时文件 file.delete(); } } return outputStream; } }