爱智EdgerOS之深入解析离线下载任务

news2025/1/20 5:48:26

一、需求分析

  • 在日常使用计算机的过程中,看到喜欢的资源不可避免地想把它下载到我们的设备上保存下来,比如图片,音视频资源,文档资源等,基于这种应用场景,现在来看看在爱智设备上可以如何实现呢?
  • 因为是离线下载,所以爱智 APP Web 端向爱智 APP Server 端发送一个请求,爱智后端启动多任务线程完成下载任务,这时候前端就可以关闭了。
  • 需要将下载的进度实时返回到前端,使用 Socket.IO 将进度推送到前端,下载任务和 Socket.IO 之间需要异步通信,使用 SigSlot。

在这里插入图片描述

二、什么是 SigSlot?

  • SigSlot 是一个事件驱动的异步通信组件,支持多任务和多进程,这也是为什么选择使用 SigSlot 在 Task 中进行通信的原因,它继承自 EventEmitter,是一个典型的订阅和发布通信机制。
  • SigSlot 的功能还远不止于此,当应用申请开启 GSS 支持后,来自同一开发供应商的应用程序可以通过 GSS 的功能互相订阅和发布消息。在这里,只在同一应用中的多个线程中使用它的异步通信功能。

三、WebGet

  • WebGet 模块用于获取 http 数据,它支持分段请求数据,以及断点续传等,通过调用 WebGet 上的 file 方法来将数据保存到文件中,可以在选项中指定数据的起始位置、每段数据的大小以及并行请求的数量。
  • 如果文件存在并且设置了 reload 为 true,WebGet 对象将检查日志并启动断点恢复过程。

四、实现过程

① 前端实现

  • 前端部分是正常的发送请求,以及监听进度部分,这里给出大致的代码段:
// 前端以 vue3 为例实现
// home.jsx
import { defineComponent, ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { download } from '../apis/index'

export default defineComponent({
  name: 'Home',
  setup (props, ctx) {
    const router = useRouter()
    const downloadList = ref([])

    onMounted(() => {
      socketio.socket.on('progress', data => {
        downloadList.value.forEach(item => {
          if (item.hash === data.hash) {
            item.progress = data.data
            item.name = data.name
          }
        })
        if (data.data === 100) {
          console.log('>>>> download over <<<<')
        }
      })
    })
  }
})
  • 这里在 onMounted 的生命周期中接收 Socket.IO 传递过来的下载进度的数据,然后更新到对应的 DataView 中。

② Server 端实现

  • Server 端部分主要看三个部分的内容,router 中触发下载任务:
// routers/rest.js
const Router = require('webapp').Router;
const SigSlot = require('sigslot');
const fs = require('fs')

const sigslot = new SigSlot('download');

/* Create router */
const router = Router.create();

// download task
const task = new Task('./download-task.js', 'download-task', {
  directory: module.directory
})

// 下载文件接口
router.post('/download', function(req, res) {
  sigslot.emit('download', {
    url: req.body.url,
    hash: req.body.hash
  })
  res.json({
    code: 0,
    msg: 'success'
  })
});
// 获取下载文件的资源列表
router.get('/download-list', function(req, res) {
  res.json({
    code: 0,
    msg: 'ok',
    data: fs.dumpdir('./public/download')
  })
})

/* Export router */
module.exports = router;
  • 在路由一开始就将下载的线程运行了起来,在其内部监听一个 download 的 Sigslot 任务,路由这里接收到下载的请求后,就将参数通过 Sigslot 发送到了 Task 线程。
  • 接下来看一下 Task 线程中的内容:

// routers/download-task.js
const WebGet = require('webget');
const SigSlot = require('sigslot');
const fs = require('fs')

const sigslot = new SigSlot('download');
fs.mkdir('./public/download', 0o666, true)

// Subscribe
sigslot.slot('download', (msg) => {
  const url = msg.url;
  const fileNameArr = url.split('/')
  const fileName = fileNameArr[fileNameArr.length - 1]
  const path = `./public/download/${fileName}`;
  let totalSize = 0

  WebGet.file(url, path, {
    limits: 512,
    lines: 2,
    reload: true
  }, (loader) => {
    loader.on('response', (info) => {
      totalSize = info.requestSize;
      // console.log(`Download begin, original=${info.originalSize}, total=${totalSize}, loaded=${info.loadedSize}`);
    });

    loader.on('data', (chunk, info) => {
      const progress = info.completeSize / totalSize * 100;
      // console.log(`Recv data, size=${chunk.byteLength}, offset=${info.offset}, progress=${progress}%`);
      sigslot.emit('progress', {
        data: Math.round(progress),
        hash: msg.hash,
        name: fileName
      })
    });

    loader.on('end', () => {
      console.log(`Download finish, file: ${path}`);
    });

    loader.on('error', (e) => {
      console.log('Download error:', e.message);
    });
  })
});

require('iosched').forever();
  • Task 中只做一件事,外层 SigSlot 订阅下载任务,然后使用 WebGet.file 进行资源下载,按照需求配置分片以及断点续传等功能。WebGet.file 的回调函数返回 WebGet 对象,可以在 WebGet 对象的 data 事件中获取计算进度的数据,最后再通过 SigSlot 发布到 Socket.IO 的订阅事件中。
  • 最后看返回给前端的下载进度:

// main.js
/* Import system modules */
const WebApp = require('webapp');
const io = require('socket.io');
const SigSlot = require('sigslot');
const bodyParser = require('middleware').bodyParser;

const sigslot = new SigSlot('download');

/* Import routers */
const myRouter = require('./routers/rest');

/* Create App */
const app = WebApp.createApp();

/* Set static path */
app.use(WebApp.static('./public'));

// body parser
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded()); // for parsing application/x-www-form-urlencoded

/* Set test rest */
app.use('/api', myRouter);

/* Rend test */
app.get('/temp.html', function (req, res) {
  res.render('temp', { time: Date.now() });
});

/* Start App */
app.start();

const socketio = io(app, {
  serveClient: false,
  pingInterval: 10000,
  pingTimeout: 5000
})

socketio.on('connection', socket => {
  console.log('>> socket connected <<')

  // Subscribe
  sigslot.slot('progress', (msg) => {
    // console.log('>> main download arrived:', msg.data);
    socket.emit('progress', msg)
  });

})

/* Event loop */
require('iosched').forever();
  • 在入口文件中建立 Socket 连接,在连接建立后,开始订阅在上一步的 Task 中发布的下载进度数据,再用 Socket 发布到前端。到这里,就已经将所有环节串联了起来,整个离线下载任务就基本上完成了,只需要发送下载请求,即可把任务交个爱智来完全掌握。

在这里插入图片描述

  • 还有很多不同的复杂场景,在解决问题之前,先将复杂的任务简单化,然后灵活运用 JSRE 提供的丰富的 API 接口,逐个解决小任务,最终将各个环节串联合并完成整个功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/434714.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

日撸 Java 三百行day33

文章目录 说明day33 图的广度优先遍历1.思路2.多个连通分量2 代码实现 说明 闵老师的文章链接&#xff1a; 日撸 Java 三百行&#xff08;总述&#xff09;_minfanphd的博客-CSDN博客 自己也把手敲的代码放在了github上维护&#xff1a;https://github.com/fulisha-ok/sampled…

82.qt qml-2D粒子系统、粒子方向、粒子项(一)

由于粒子系统相关的类比较多, 所以本章参考自QmlBook in chinese的粒子章节配合学习: 由于QmlBook in chinese翻译过来的文字有些比较难理解,所以本章在它的基础上做些个人理解,建议学习的小伙伴最好配合QmlBook in chinese一起学习。 1.介绍 粒子模拟的核心是粒子系统(Partic…

ResNet残差网络

ResNet 目的 Resnet网络是为了解决深度网络中的退化问题&#xff0c;即网络层数越深时&#xff0c;在数据集上表现的性能却越差。 原理 ResNet的单元结构如下&#xff1a; 类似动态规划的选择性继承&#xff0c;同时会在训练过程中逐渐增大&#xff08;/缩小&#xff09;该…

数字图像基础【7】应用线性回归最小二乘法(矩阵版本)求解几何变换(仿射、透视)

这一章主要讲图像几何变换模型&#xff0c;可能很多同学会想几何变换还不简单嚒&#xff1f;平移缩放旋转。在传统的或者说在同一维度上的基础变换确实是这三个&#xff0c;但是今天学习的是2d图像转投到3d拼接的基础变换过程。总共包含五个变换——平移、刚性、相似、仿射、透…

尚融宝10-Excel数据批量导入

目录 一、数据字典 &#xff08;一&#xff09;、什么是数据字典 &#xff08;二&#xff09;、数据字典的设计 二、Excel数据批量导入 &#xff08;一&#xff09;后端接口 1、添加依赖 2、创建Excel实体类 3、创建监听器 4、Mapper层批量插入 5、Service层创建监听…

2023年,想要靠做软件测试获得高薪,我还有机会吗?

时间过得很快&#xff0c;一眨眼&#xff0c;马上就要进入2023年了&#xff0c;到了年底&#xff0c;最近后台不免又出现了经常被同学问道这几个问题&#xff1a;2023年还能转行软件测试吗&#xff1f;零基础转行可行吗&#xff1f; 本期小编就“2023年&#xff0c;入行软件测…

一文解决nltk安装问题ModuleNotFoundError: No module named ‘nltk‘,保姆级教程

目录 问题一&#xff1a;No module named ‘nltk‘ 问题二&#xff1a;Please use the NLTK Downloader to obtain the resource 下载科学上网工具 问题三&#xff1a;套娃报错 如果会科学上网&#xff0c;可以直接看问题三 问题一&#xff1a;No module named ‘nltk‘ Mo…

【微服务笔记16】微服务组件之Gateway服务网关基础环境搭建

这篇文章&#xff0c;主要介绍微服务组件之Gateway服务网关基础环境搭建。 目录 一、Gateway服务网关 1.1、什么是Gateway 1.2、Gateway基础环境搭建 &#xff08;1&#xff09;基础环境介绍 &#xff08;2&#xff09;引入依赖 &#xff08;3&#xff09;添加路由配置信…

软件测试工程师的进阶之旅

很多人对测试工程师都有一些刻板印象&#xff0c;比如觉得测试“入门门槛低&#xff0c;没有技术含量”、“对公司不重要”、“操作简单工作枯燥”“一百个开发&#xff0c;一个测试”等等。 会产生这种负面评论&#xff0c;是因为很多人对测试的了解&#xff0c;还停留在几年…

Lesson12 udptcp协议

netstat命令->查看网络状态 n 拒绝显示别名&#xff0c;能显示数字的全部转化成数字l 仅列出有在 Listen (监听) 的服務状态p 显示建立相关链接的程序名t (tcp)仅显示tcp相关选项u (udp)仅显示udp相关选项a (all)显示所有选项&#xff0c;默认不显示LISTEN相关 pidof命令-&…

SQL select详解(基于选课系统)

表详情&#xff1a; 学生表&#xff1a; 学院表&#xff1a; 学生选课记录表&#xff1a; 课程表&#xff1a; 教师表&#xff1a; 查询&#xff1a; 1. 查全表 -- 01. 查询所有学生的所有信息 -- 方法一&#xff1a;会更复杂&#xff0c;进行了两次查询&#xff0c;第一…

机器学习笔记之正则化(六)批标准化(BatchNormalization)

机器学习笔记之正则化——批标准化[Batch Normalization] 引言引子&#xff1a;梯度消失梯度消失的处理方式批标准化 ( Batch Normalization ) (\text{Batch Normalization}) (Batch Normalization)场景构建梯度信息比例不平衡批标准化对于梯度比例不平衡的处理方式 ICS \text{…

《抄送列表》:过滤次要文件,优先处理重要文件

目录 一、题目 二、思路 1、查找字符/字符串方法&#xff1a;str1.indexOf( ) 2、字符串截取方法&#xff1a;str1.substring( ) 三、代码 详细注释版&#xff1a; 简化注释版&#xff1a; 一、题目 题目&#xff1a;抄送列表 题目链接&#xff1a;抄送列表 …

Java[集合] Map 和 Set

哈喽&#xff0c;大家好~ 我是保护小周ღ&#xff0c;本期为大家带来的是 Java Map 和 Set 集合详细介绍了两个集合的概念及其常用方法&#xff0c;感兴趣的朋友可以来学习一下。更多精彩敬请期待&#xff1a;保护小周ღ *★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* ‘ 一、…

JVM知识汇总

1、JVM架构图 2、Java编译器 Java编译器做的事情很简单&#xff0c;其实就是就是将Java的源文件转换为字节码文件。 1. 源文件存储的是高级语言的命令&#xff0c;JVM只认识"机器码"&#xff1b; 2. 因此将源文件转换为字节码文件&#xff0c;即是JVM看得懂的"…

Node.js—Buffer(缓冲器)

文章目录 1、概念2.、特点3、创建Buffer3.1 Buffer.alloc3.2 Buffer.allocUnsafe3.3 Buffer.from 4、操作Buffer4.1 Buffer 与字符串的转化4.2 Buffer 的读写 参考 1、概念 Buffer 是一个类似于数组的对象 &#xff0c;用于表示固定长度的字节序列。Buffer 本质是一段内存空间…

视觉学习(四) --- 基于yolov5进行数据集制作和模型训练

环境信息 Jetson Xavier NX&#xff1a;Jetpack 4.4.1 Ubuntu&#xff1a;18.04 CUDA: 10.2.89 OpenCV: 4.5.1 cuDNN&#xff1a;8.0.0.180一.yolov5 项目代码整体架构介绍 1. yolov5官网下载地址&#xff1a; GitHub: https://github.com/ultralytics/yolov5/tree/v5.0 2. …

单元测试中的独立运行

单元测试中的独立运行 单元测试是针对代码单元的独立测试。要测试代码单元&#xff0c;首先要其使能够独立运行。项目中的代码具有依赖关系&#xff0c;例如&#xff0c;一个源文件可能直接或间接包含大量头文件&#xff0c;并调用众多其他源文件的代码&#xff0c;抽取其中的一…

论文阅读:Unsupervised Manifold Linearizing and Clustering

Author: Tianjiao Ding, Shengbang Tong, Kwan Ho Ryan Chan, Xili Dai, Yi Ma, Benjamin D. Haeffele Abstract 在本文中&#xff0c;我们建议同时执行聚类并通过最大编码率降低来学习子空间联合表示。 对合成和现实数据集的实验表明&#xff0c;所提出的方法实现了与最先进的…

limit、排序、分组单表查询(三)MySQL数据库(头歌实践教学平台)

文章目的初衷是希望学习笔记分享给更多的伙伴&#xff0c;并无盈利目的&#xff0c;尊重版权&#xff0c;如有侵犯&#xff0c;请官方工作人员联系博主谢谢。 目录 第1关&#xff1a;对查询结果进行排序 任务描述 相关知识 对查询结果排序 指定排序方向 编程要求 第2关&a…