use of lee.study.down.dispatch.HttpDownCallback in project proxyee-down by monkeyWie.
the class HttpDownInitializer method initChannel.
@Override
protected void initChannel(Channel ch) throws Exception {
if (bootstrap.getHttpDownInfo().getProxyConfig() != null) {
ch.pipeline().addLast(ProxyHandleFactory.build(bootstrap.getHttpDownInfo().getProxyConfig()));
}
if (isSsl) {
ch.pipeline().addLast(bootstrap.getClientSslContext().newHandler(ch.alloc()));
}
ch.pipeline().addLast("httpCodec", new HttpClientCodec());
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
private Closeable closeable;
private TaskInfo taskInfo = bootstrap.getHttpDownInfo().getTaskInfo();
private HttpDownCallback callback = bootstrap.getCallback();
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
if (msg instanceof HttpContent) {
if (!isSucc) {
return;
}
HttpContent httpContent = (HttpContent) msg;
ByteBuf byteBuf = httpContent.content();
synchronized (chunkInfo) {
Channel nowChannel = bootstrap.getChannel(chunkInfo);
if (chunkInfo.getStatus() == HttpDownStatus.RUNNING && nowChannel == ctx.channel()) {
int readableBytes = bootstrap.doFileWriter(chunkInfo, byteBuf.nioBuffer());
if (readableBytes > 0) {
// 最后一次下载时间
chunkInfo.setLastDownTime(System.currentTimeMillis());
// 文件已下载大小
chunkInfo.setDownSize(chunkInfo.getDownSize() + readableBytes);
taskInfo.setDownSize(taskInfo.getDownSize() + readableBytes);
if (callback != null) {
callback.onProgress(bootstrap.getHttpDownInfo(), chunkInfo);
}
}
} else {
safeClose(ctx.channel());
return;
}
}
if (isDone(chunkInfo.getDownSize(), httpContent)) {
LOGGER.debug("分段下载完成:channelId[" + ctx.channel().id() + "]\t" + chunkInfo);
bootstrap.close(chunkInfo, true);
// 分段下载完成回调
chunkInfo.setStatus(HttpDownStatus.DONE);
taskInfo.refresh(chunkInfo);
if (callback != null) {
callback.onChunkDone(bootstrap.getHttpDownInfo(), chunkInfo);
}
synchronized (taskInfo) {
if (taskInfo.getStatus() == HttpDownStatus.RUNNING && taskInfo.getChunkInfoList().stream().allMatch((chunk) -> chunk.getStatus() == HttpDownStatus.DONE)) {
if (!taskInfo.isSupportRange()) {
// chunked编码最后更新文件大小
taskInfo.setTotalSize(taskInfo.getDownSize());
taskInfo.getChunkInfoList().get(0).setTotalSize(taskInfo.getDownSize());
}
// 文件下载完成回调
taskInfo.setStatus(HttpDownStatus.DONE);
LOGGER.debug("下载完成:channelId[" + ctx.channel().id() + "]\t" + chunkInfo);
bootstrap.close(true);
if (callback != null) {
callback.onDone(bootstrap.getHttpDownInfo());
}
}
}
} else if (isContinue(chunkInfo.getDownSize())) {
// 百度响应做了手脚,会少一个字节
// 真实响应字节小于要下载的字节,在下载完成后要继续下载
LOGGER.debug("继续下载:channelId[" + ctx.channel().id() + "]\t" + chunkInfo);
bootstrap.retryChunkDown(chunkInfo, HttpDownStatus.CONNECTING_CONTINUE);
}
} else {
HttpResponse httpResponse = (HttpResponse) msg;
Integer responseCode = httpResponse.status().code();
if (responseCode.toString().indexOf("20") != 0) {
// 应对百度近期同一时段多个连接返回400的问题
LOGGER.debug("响应状态码异常:" + responseCode + "\t" + chunkInfo);
if (responseCode == 401 || responseCode == 403 || responseCode == 404) {
chunkInfo.setStatus(HttpDownStatus.ERROR_WAIT_CONNECT);
}
return;
}
realContentSize = HttpDownUtil.getDownContentSize(httpResponse.headers());
synchronized (chunkInfo) {
// 判断状态是否为连接中
if (chunkInfo.getStatus() == HttpDownStatus.CONNECTING_NORMAL || chunkInfo.getStatus() == HttpDownStatus.CONNECTING_FAIL || chunkInfo.getStatus() == HttpDownStatus.CONNECTING_CONTINUE) {
LOGGER.debug("下载响应:channelId[" + ctx.channel().id() + "]\t contentSize[" + realContentSize + "]" + chunkInfo);
chunkInfo.setDownSize(chunkInfo.getNowStartPosition() - chunkInfo.getOriStartPosition());
closeable = bootstrap.initFileWriter(chunkInfo);
chunkInfo.setStatus(HttpDownStatus.RUNNING);
if (callback != null) {
callback.onChunkConnected(bootstrap.getHttpDownInfo(), chunkInfo);
}
isSucc = true;
} else {
safeClose(ctx.channel());
}
}
}
} catch (Exception e) {
throw e;
} finally {
ReferenceCountUtil.release(msg);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
LOGGER.error("down onChunkError:", cause);
Channel nowChannel = bootstrap.getChannel(chunkInfo);
safeClose(ctx.channel());
if (nowChannel == ctx.channel()) {
if (callback != null) {
callback.onChunkError(bootstrap.getHttpDownInfo(), chunkInfo, cause);
}
bootstrap.retryChunkDown(chunkInfo);
}
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
super.channelUnregistered(ctx);
safeClose(ctx.channel());
}
private void safeClose(Channel channel) {
try {
HttpDownUtil.safeClose(channel, closeable);
} catch (IOException e) {
LOGGER.error("safeClose fail:", e);
}
}
private boolean isDone(long downSize, HttpContent content) {
return downSize == chunkInfo.getTotalSize() || (!taskInfo.isSupportRange() && content instanceof LastHttpContent);
}
private boolean isContinue(long downSize) {
long downChunkSize = downSize + chunkInfo.getOriStartPosition() - chunkInfo.getNowStartPosition();
return realContentSize == downChunkSize || (realContentSize - 1) == downChunkSize;
}
});
}
use of lee.study.down.dispatch.HttpDownCallback in project proxyee-down by monkeyWie.
the class HttpDownController method doUpdate.
@RequestMapping("/doUpdate")
public ResultInfo doUpdate() throws Exception {
ResultInfo resultInfo = new ResultInfo();
if (updateInfo == null) {
resultInfo.setStatus(ResultStatus.BAD.getCode()).setMsg("没有可用版本进行更新");
return resultInfo;
}
if (updateBootstrap != null) {
updateBootstrap.close();
updateBootstrap = null;
}
try {
updateBootstrap = updateService.update(updateInfo, new HttpDownCallback() {
@Override
public void onDone(HttpDownInfo httpDownInfo) throws Exception {
String zipPath = httpDownInfo.getTaskInfo().buildTaskFilePath();
String unzipDir = "proxyee-down-" + updateInfo.getVersionStr();
String unzipPath = unzipDir + "/main/proxyee-down-core.jar";
// 下载完解压
FileUtil.unzip(zipPath, null, unzipPath);
// 复制出来
Files.copy(Paths.get(httpDownInfo.getTaskInfo().getFilePath() + File.separator + unzipPath), Paths.get(httpDownInfo.getTaskInfo().getFilePath() + File.separator + "proxyee-down-core.jar.bak"));
// 删除临时的文件
FileUtil.deleteIfExists(zipPath);
FileUtil.deleteIfExists(httpDownInfo.getTaskInfo().getFilePath() + File.separator + unzipDir);
// 通知客户端
ContentManager.WS.sendMsg(new WsForm(WsDataType.UPDATE_PROGRESS, httpDownInfo.getTaskInfo()));
// 清空更新下载信息
updateBootstrap = null;
}
});
} catch (TimeoutException e) {
resultInfo.setStatus(ResultStatus.BAD.getCode()).setMsg("检测更新超时,请重试");
return resultInfo;
}
return resultInfo;
}
Aggregations