package com.wm.remusic.proxy.utils;
import android.content.Context;
import android.util.Log;
import com.wm.remusic.proxy.db.CacheFileInfoDao;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.SocketException;
import java.net.URISyntaxException;
public class RequestDealThread extends Thread {
private static final String LOG_TAG = RequestDealThread.class.getSimpleName();
Socket client;
HttpURLConnection request;
ProxyFileUtils fileUtils;
/**
* MediaPlayer发出的原始请求Range Start
*/
private int originRangeStart;
/**
* 和本地缓存判断后,需要发出的请求Range Start
*/
private long realRangeStart;
CacheFileInfoDao cacheDao;
Context mContext;
public RequestDealThread(Context context, HttpURLConnection request, Socket client) {
this.request = request;
this.client = client;
cacheDao = CacheFileInfoDao.getInstance();
mContext = context;
}
@Override
public void run() {
try {
fileUtils = ProxyFileUtils.getInstance(mContext, request.getURL().toURI(), true);
processRequest(request, client);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
private int getRangeStart(HttpURLConnection request) {
String value = request.getRequestProperty(Constants.RANGE);
// Header rangeHeader = request.getFirstHeader(Constants.RANGE);
if (value != null) {
return Integer.valueOf(value.substring(value.indexOf("bytes=") + 6, value.indexOf("-")));
}
return 0;
}
/**
* 伪造Response Header,发送缓存内容
*
* @param rangeStart 数据起始位置(如果从头开始则为0)
* @param rangeEnd 数据截止位置(一般为缓存长度-1)
* @param fileLength 缓存文件长度
* @param audioCache 缓存内容
* @throws IOException
*/
private void sendLocalHeaderAndCache(int rangeStart, int rangeEnd, int fileLength, byte[] audioCache)
throws IOException {
// 返回MediaPlayer Header信息
String httpString = HttpUtils.genResponseHeader(rangeStart, rangeEnd, fileLength);
byte[] httpHeader = httpString.toString().getBytes();
client.getOutputStream().write(httpHeader, 0, httpHeader.length);
// 返回Content
if (audioCache != null && audioCache.length > 0) {
client.getOutputStream().write(audioCache, 0, audioCache.length);
}
}
private void processRequest(HttpURLConnection request, Socket client) throws IllegalStateException, IOException {
if (request == null) {
return;
}
try {
byte[] audioCache = null;
// 得到MediaPlayer原始请求Range起始
originRangeStart = getRangeStart(request);
Log.i(LOG_TAG, "原始请求Range起始值:" + originRangeStart + " 本地缓存长度:" + fileUtils.getLength());
// 缓存的文件大小
int cacheFileSize = cacheDao.getFileSize(fileUtils.getFileName());
/*
* 如果缓存完成,无需发送请求,本地缓存返回MediaPlayer。
*/
if (fileUtils.isEnable() && fileUtils.getLength() == cacheFileSize) {
audioCache = fileUtils.read(originRangeStart, Constants.AUDIO_BUFFER_MAX_LENGTH);
sendLocalHeaderAndCache(originRangeStart, cacheFileSize - 1, cacheFileSize, audioCache);
return;
}
// TODO 这里可能需要网络判断
/*
* 请求Range起始值和本地缓存比对。如果有缓存,得到缓存内容,修改Range。 如果没有缓存,则Range不变。
*/
if (fileUtils.isEnable() && originRangeStart < fileUtils.getLength()) {
audioCache = fileUtils.read(originRangeStart, Constants.AUDIO_BUFFER_MAX_LENGTH);
Log.i(LOG_TAG, "本地已缓存长度(跳过):" + audioCache.length);
// 得到需要发送请求Range Start(本地缓存结尾位置+1=缓存长度)
realRangeStart = fileUtils.getLength();
// 替换请求Header
request.setRequestProperty(Constants.RANGE, Constants.RANGE_PARAMS + realRangeStart + "-");
// request.removeHeaders(Constants.RANGE);
// request.addHeader(Constants.RANGE, Constants.RANGE_PARAMS + realRangeStart + "-");
} else {
realRangeStart = originRangeStart;
}
// 缓存是否已经到最大值(如果缓存已经到最大值,则只需要返回缓存)
boolean isCacheEnough = (audioCache != null && audioCache.length == Constants.AUDIO_BUFFER_MAX_LENGTH) ? true
: false;
/*
* 如果缓存足够,且本地有文件长度,则直接发送缓存,不发送请求。。。。。。。。。。。。。。。。。。。
* 如果缓存足够,本地没有文件长度,则发送请求,使用ResponseHeader,返回缓存,!不接收ResponseContent
* 如果缓存不足,则发送请求,使用ResponseHeader,返回缓存,!返回Response Content
*/
// 缓存足够&&有文件大小
if (isCacheEnough && cacheFileSize > 0) {
sendLocalHeaderAndCache(originRangeStart, cacheFileSize - 1, cacheFileSize, audioCache);
}
// 缓存不够。或者数据库没有文件大小
else {
HttpURLConnection realResponse = null;
/*
* 返回Header和Cache
*/
// 如果数据库没有存文件大小,则获取(处理数据库没有文件大小的情况)
if (cacheFileSize <= 0) {
Log.d(LOG_TAG, "数据库未包含文件大小,发送请求");
realResponse = HttpUtils.send(request);
if (realResponse == null) {
return;
}
cacheFileSize = getContentLength(realResponse);
}
sendLocalHeaderAndCache(originRangeStart, cacheFileSize - 1, cacheFileSize, audioCache);
// 如果缓存不足,返回Response Content(处理缓存不足的情况)
if (realResponse == null) {
Log.d(LOG_TAG, "缓存不足,发送请求");
realResponse = HttpUtils.send(request);
if (realResponse == null) {
return;
}
}
Log.d(LOG_TAG, "接收ResponseContent");
InputStream data = realResponse.getInputStream();
if (!isCacheEnough) {
byte[] buff = new byte[1024 * 40];
boolean isPrint = true;
int fileLength = 0;
int readBytes;
while (Thread.currentThread() == MediaPlayerProxy.downloadThread
&& (readBytes = data.read(buff, 0, buff.length)) != -1) {
long fileBufferLocation = fileLength + realRangeStart;
fileLength += readBytes;
long fileBufferEndLocation = fileLength + realRangeStart;
// 保存文件
if (fileUtils.getLength() == fileBufferLocation) {
fileUtils.write(buff, readBytes);
}
// 打印缓存大小
if (System.currentTimeMillis() / 1000 % 2 == 0) {
if (isPrint) {
Log.d(LOG_TAG, "Cache Size:" + readBytes + " File Start:" + fileBufferLocation
+ "File End:" + fileBufferEndLocation);
isPrint = false;
}
} else {
isPrint = true;
}
client.getOutputStream().write(buff, 0, readBytes);
}
}
}
} catch (SocketException e) {
Log.i(LOG_TAG, "连接被终止", e);
} catch (Exception e) {
Log.e(LOG_TAG, e.getMessage(), e);
} finally {
client.close();
Log.i(LOG_TAG, "代理关闭");
}
}
/**
* 得到Content大小
*
* @param response
* @return
*/
private int getContentLength(HttpURLConnection response) {
int contentLength = 0;
String range = request.getHeaderField(Constants.RANGE);
if (range != null) {
contentLength = Integer.valueOf(range.substring(range.indexOf("-") + 1, range.indexOf("/"))) + 1;
} else {
contentLength = request.getContentLength();
}
if (contentLength != 0) {
cacheDao.insertOrUpdate(fileUtils.getFileName(), contentLength);
}
return contentLength;
}
}