Search in sources :

Example 16 with TaskInfo

use of lee.study.down.model.TaskInfo 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;
        }
    });
}
Also used : Closeable(java.io.Closeable) Channel(io.netty.channel.Channel) HttpResponse(io.netty.handler.codec.http.HttpResponse) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) IOException(java.io.IOException) HttpClientCodec(io.netty.handler.codec.http.HttpClientCodec) ByteBuf(io.netty.buffer.ByteBuf) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) IOException(java.io.IOException) TaskInfo(lee.study.down.model.TaskInfo) HttpDownCallback(lee.study.down.dispatch.HttpDownCallback) HttpContent(io.netty.handler.codec.http.HttpContent) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) ChannelInboundHandlerAdapter(io.netty.channel.ChannelInboundHandlerAdapter)

Example 17 with TaskInfo

use of lee.study.down.model.TaskInfo in project proxyee-down by monkeyWie.

the class DownContent method putBoot.

public void putBoot(HttpDownInfo httpDownInfo) {
    AbstractHttpDownBootstrap bootstrap = HttpDownBootstrapFactory.create(httpDownInfo, ContentManager.CONFIG.get().getRetryCount(), HttpDownConstant.clientSslContext, HttpDownConstant.clientLoopGroup, HttpDownConstant.httpDownCallback);
    TaskInfo taskInfo = bootstrap.getHttpDownInfo().getTaskInfo();
    if (taskInfo.isSupportRange()) {
        taskInfo.setConnections(ContentManager.CONFIG.get().getConnections());
    }
    taskInfo.setFilePath(ContentManager.CONFIG.get().getLastPath());
    putBoot(bootstrap);
}
Also used : TaskInfo(lee.study.down.model.TaskInfo) AbstractHttpDownBootstrap(lee.study.down.boot.AbstractHttpDownBootstrap)

Example 18 with TaskInfo

use of lee.study.down.model.TaskInfo in project proxyee-down by monkeyWie.

the class DownContent method buildWsForm.

public WsForm buildWsForm(String taskId) {
    List<TaskInfo> list = new ArrayList<>();
    TaskInfo taskInfo = getTaskInfo(taskId);
    if (taskInfo == null) {
        return null;
    } else {
        list.add(taskInfo);
        return new WsForm(WsDataType.TASK_LIST, setUrl(list));
    }
}
Also used : TaskInfo(lee.study.down.model.TaskInfo) ArrayList(java.util.ArrayList) WsForm(lee.study.down.mvc.form.WsForm)

Example 19 with TaskInfo

use of lee.study.down.model.TaskInfo in project proxyee-down by monkeyWie.

the class HttpDownHandleCallback method onDone.

@Override
public void onDone(HttpDownInfo httpDownInfo) throws Exception {
    TaskInfo taskInfo = httpDownInfo.getTaskInfo();
    // 更改任务下载状态为已完成
    ContentManager.DOWN.save();
    // 删除任务进度记录文件
    synchronized (taskInfo) {
        FileUtil.deleteIfExists(taskInfo.buildTaskRecordFilePath());
        FileUtil.deleteIfExists(taskInfo.buildTaskRecordBakFilePath());
    }
    sendTask(httpDownInfo.getTaskInfo().getId());
    NewTaskForm taskForm = NewTaskForm.parse(httpDownInfo);
    if (taskForm.isUnzip()) {
        if (BdyZip.isBdyZip(taskInfo.buildTaskFilePath())) {
            WsForm wsForm = new WsForm(WsDataType.UNZIP_NEW, new HashMap<String, String>() {

                {
                    put("filePath", taskInfo.buildTaskFilePath());
                    put("toPath", taskForm.getUnzipPath());
                }
            });
            ContentManager.WS.sendMsg(wsForm);
        }
    }
}
Also used : TaskInfo(lee.study.down.model.TaskInfo) NewTaskForm(lee.study.down.mvc.form.NewTaskForm) WsForm(lee.study.down.mvc.form.WsForm)

Example 20 with TaskInfo

use of lee.study.down.model.TaskInfo in project proxyee-down by monkeyWie.

the class HttpDownController method commonStartTask.

public static ResultInfo commonStartTask(NewTaskForm taskForm) throws Exception {
    ResultInfo resultInfo = new ResultInfo();
    AbstractHttpDownBootstrap bootstrap = ContentManager.DOWN.getBoot(taskForm.getId());
    HttpDownInfo httpDownInfo = bootstrap.getHttpDownInfo();
    // 覆盖下载
    if (!StringUtils.isEmpty(taskForm.getOldId())) {
        AbstractHttpDownBootstrap oldBootstrap = ContentManager.DOWN.getBoot(taskForm.getOldId());
        if (oldBootstrap == null) {
            resultInfo.setStatus(ResultStatus.BAD.getCode()).setMsg("任务不存在");
            return resultInfo;
        } else {
            // 暂停之前的下载任务
            oldBootstrap.pauseDown();
            // 修改request
            oldBootstrap.getHttpDownInfo().setRequest(httpDownInfo.getRequest());
            oldBootstrap.getHttpDownInfo().setProxyConfig(httpDownInfo.getProxyConfig());
            Map<String, Object> attr = oldBootstrap.getHttpDownInfo().getAttrs();
            if (attr == null) {
                attr = new HashMap<>();
                oldBootstrap.getHttpDownInfo().setAttrs(attr);
            }
            attr.put(NewTaskForm.KEY_UNZIP_FLAG, taskForm.isUnzip());
            attr.put(NewTaskForm.KEY_UNZIP_PATH, taskForm.getUnzipPath());
            // 移除新的下载任务
            ContentManager.DOWN.removeBoot(taskForm.getId());
            // 持久化
            ContentManager.DOWN.save();
            // 用新链接继续下载
            oldBootstrap.continueDown();
        }
    } else {
        if (StringUtils.isEmpty(taskForm.getFileName())) {
            resultInfo.setStatus(ResultStatus.BAD.getCode()).setMsg("文件名不能为空");
            return resultInfo;
        }
        if (StringUtils.isEmpty(taskForm.getFilePath())) {
            resultInfo.setStatus(ResultStatus.BAD.getCode()).setMsg("路径不能为空");
            return resultInfo;
        }
        buildDefaultValues(taskForm);
        TaskInfo taskInfo = httpDownInfo.getTaskInfo();
        synchronized (taskInfo) {
            if (taskInfo.getStatus() != HttpDownStatus.WAIT) {
                resultInfo.setStatus(ResultStatus.BAD.getCode()).setMsg("任务已添加至下载列表");
            }
            taskInfo.setFileName(taskForm.getFileName());
            taskInfo.setFilePath(taskForm.getFilePath());
            Map<String, Object> attr = httpDownInfo.getAttrs();
            if (attr == null) {
                attr = new HashMap<>();
                httpDownInfo.setAttrs(attr);
            }
            attr.put(NewTaskForm.KEY_UNZIP_FLAG, taskForm.isUnzip());
            attr.put(NewTaskForm.KEY_UNZIP_PATH, taskForm.getUnzipPath());
            if (taskInfo.isSupportRange()) {
                taskInfo.setConnections(taskForm.getConnections());
            } else {
                taskInfo.setConnections(1);
            }
            try {
                bootstrap.startDown();
            } catch (BootstrapException e) {
                resultInfo.setStatus(ResultStatus.BAD.getCode()).setMsg(e.getMessage());
                return resultInfo;
            }
            // 记录存储路径
            String lastPath = ContentManager.CONFIG.get().getLastPath();
            if (!taskForm.getFilePath().equalsIgnoreCase(lastPath)) {
                ContentManager.CONFIG.get().setLastPath(taskForm.getFilePath());
                ContentManager.CONFIG.save();
            }
        }
    }
    return resultInfo;
}
Also used : TaskInfo(lee.study.down.model.TaskInfo) AbstractHttpDownBootstrap(lee.study.down.boot.AbstractHttpDownBootstrap) BootstrapException(lee.study.down.exception.BootstrapException) ResultInfo(lee.study.down.model.ResultInfo) HttpDownInfo(lee.study.down.model.HttpDownInfo)

Aggregations

TaskInfo (lee.study.down.model.TaskInfo)21 HttpDownInfo (lee.study.down.model.HttpDownInfo)6 ResultInfo (lee.study.down.model.ResultInfo)6 AbstractHttpDownBootstrap (lee.study.down.boot.AbstractHttpDownBootstrap)5 ChunkInfo (lee.study.down.model.ChunkInfo)5 HttpRequestInfo (lee.study.down.model.HttpRequestInfo)5 IOException (java.io.IOException)4 BootstrapException (lee.study.down.exception.BootstrapException)4 WsForm (lee.study.down.mvc.form.WsForm)4 RequestMapping (org.springframework.web.bind.annotation.RequestMapping)4 HttpResponse (io.netty.handler.codec.http.HttpResponse)3 File (java.io.File)3 ArrayList (java.util.ArrayList)3 Channel (io.netty.channel.Channel)2 HttpContent (io.netty.handler.codec.http.HttpContent)2 MalformedURLException (java.net.MalformedURLException)2 LinkedHashMap (java.util.LinkedHashMap)2 List (java.util.List)2 TimeoutException (java.util.concurrent.TimeoutException)2 HttpDownCallback (lee.study.down.dispatch.HttpDownCallback)2