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

一、需求分析

  • 在日常使用计算机的过程中,看到喜欢的资源不可避免地想把它下载到我们的设备上保存下来,比如图片,音视频资源,文档资源等,基于这种应用场景,现在来看看在爱智设备上可以如何实现呢?
  • 因为是离线下载,所以爱智 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 接口,逐个解决小任务,最终将各个环节串联合并完成整个功能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

76-TCP协议,UDP协议以及区别

TCP协议,UDP协议,SCTP协议一.TCP协议1.什么是TCP协议2.TCP协议的特点3.TCP头部结构4.TCP状态转移5.TCP超时重传二.UDP协议1.什么是UDP协议2.UDP协议的特点三.TCP和UDP的区别一.TCP协议 1.什么是TCP协议 TCP(Transmission Control Protocol)协议即为传输控制协议,是一种面向连…

2023-04-12 面试中常见的数组题目

数组中的问题其实最常见 通过基础问题&#xff0c;掌握写出正确算法的“秘诀”巧妙使用双索引技术&#xff0c;解决复杂问题对撞指针- 滑动窗口 1 从二分查找法看如何写出正确的程序 本节学习重点&#xff1a;处理边界问题&#xff01; 1.确定边界范围方法&#xff0c;先用区…

微服务架构-服务网关(Gateway)-权限认证(分布式session替代方案)

权限认证-分布式session替代方案 前面我们了解了Gateway组件的过滤器&#xff0c;这一节我们就探讨一下Gateway在分布式环境中的一个具体用例-用户鉴权。 1、传统单应用的用户鉴权 从我们开始学JavaEE的时候&#xff0c;就被洗脑式灌输了一种权限验证的标准做法&#xff0c;…

Elasticsearch:集群管理的一些建议

在之前的文章 “Elasticsearch&#xff1a;集群管理” &#xff0c;我们对集群管理做了一些介绍。在今天的文章中&#xff0c;我们接着来聊一下有关配置的方面的问题。这在很大程度上取决于你的用例&#xff0c;是索引还是搜索繁重。 我们将在这里讨论在集群设置方面我们需要关…

Leetcode.130 被围绕的区域

题目链接 Leetcode.130 被围绕的区域 mid 题目描述 给你一个 m x n的矩阵 board&#xff0c;由若干字符 X和 O&#xff0c;找到所有被 X围绕的区域&#xff0c;并将这些区域里所有的 O用 X填充。 示例 1&#xff1a; 输入&#xff1a;board [[“X”,“X”,“X”,“X”],[“X…

「Cpolar」使用Typecho搭建个人博客网站【内网穿透实现公网访问】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后端的开发语言A…

在 Python 中计算两个数字之间的百分比

要计算两个数字之间的百分比&#xff0c;请将一个数字除以另一个数字&#xff0c;然后将结果乘以 100&#xff0c;例如 (30 / 75) * 100。这显示第一个数字占第二个数字的百分比。 在示例中&#xff0c;30 是 75 的 40%。 def is_what_percent_of(num_a, num_b):return (num_a…

基于SVG的HMI组件

人机界面是自动化领域不可或缺重要组成部分。人机界面系统的设计看上去并没有太大的技术门槛&#xff0c;但是设计一个HMI系统的工作量是巨大的&#xff0c;如果你没有足够的耐心和精力是难以完成一个通用HMI系统的。构建UI控件库就是一个似乎永远完不成的事情&#xff0c;用户…

Halo博客建站实战以及问题汇总

目录 简介 特性 快速开始 安装步骤 环境准备 Docker-compose方式部署 问题汇总 mac端无法访问页面 页面登录提示账号密码错误 重装注意点 资料 官方文档 简介 Halo 强大易用的开源建站工具 特性 代码开源 我们的所有代码开源在 GitHub 上且处于积极维护状态&…

《分解因数》:质因数分解

目录 一、题目&#xff1a; 二、思路&#xff1a; 三、代码&#xff1a; 一、题目&#xff1a; 分解因数 《分解因数》题目链接 所谓因子分解&#xff0c;就是把给定的正整数a&#xff0c;分解成若干个素数的乘积&#xff0c;即 a a1 a2 a3 ... an,并且 1 < a1…

HCIA第二次笔记

目录 OSI/RM七层参考模型——开放式的系统互联参考模型 核心——分层 TCP/IP模型——TCP/IP协议簇 应用层 应用层协议 封装与解封装 传输层 TCP协议和UDP协议的区别 TCP的报文 TCP的三次握手 TCP的四次挥手 TCP的四种可靠传输机制 OSI/RM七层参考模型——开放式的系…

[目标识别-论文笔记]Object Detection in Videos by Short and Long Range Object Linking

文章标题&#xff1a;2018_Cite13_Tang——Object Detection in Videos by Short and Long Range Object Linking 这篇论文也被叫做“2019_Cite91_TPAMI_Tang——Object Detection in Videos by High Quality Object Linking” 如果这篇博客对你有帮助&#xff0c;希望你 点赞…

学生信息管理系统【GUI/Swing+MySQL】(Java课设)

系统类型 Swing窗口类型Mysql数据库存储数据 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 本系统源码地址&#xff1a;https://download.csdn.net/download/qq_50954361/87673902 更多系统资源库…

【设计模式】如何在业务开发中使用适配器模式?

文章目录前言适配器模式定义通用代码实现适用场景案例场景分析一坨坨代码实现适配器模式重构总结前言 适配器模式&#xff08;Adapter Pattern&#xff09;&#xff1a;将一个类的接口变换成客户端所期待的另一种接口&#xff0c;从而使原本因接口不匹配而无法在一起工作的两个…

高速Serdes技术(FPGA领域应用)

目录引入一、Serdes&#xff08;概念-历程&#xff09;1、概念2、技术现状3、发展历程二、Serdes结构三、在FPGA领域中的运用四、Serdes跟Lvds的关系五、Xilinx 有关 serdes的文档六、参考文献引入 回顾接口技术发展历史&#xff0c;其实数据的传输最开始是低速的串行接口&…

OSI七层网络模型与TCP/IP四层模型

一、OSI七层网络模型 OSI 七层模型 是国际标准化组织提出一个网络分层模型&#xff0c;其大体结构以及每一层提供的功能如下图所示&#xff1a; 但由于各方面原因&#xff0c;OSI 七层模型并没有被广泛应用&#xff0c;更多的是作为网络分层的一种基础理论模型。 二、TCP/IP…

NumPy 基础知识 :1~5

原文&#xff1a;Numpy Essentials 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 一、NumPy 简介 “我宁愿使用通用语言进行数学运算&#xff0c;也不愿尝试使用数学语言进行通用编程。” – John D Cook 在过去的十年中&#xff0c;Python 已成为科学计算中最受欢迎…

MVCC

MVCC基本概念 当前读 当前读 : 读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁. 对于我们日常的操作. 如 : select....lock in share mode(共享锁) , select * for update , update ,insert,delete(排他锁) 都是一种当前读. 快…

Java对象模型

介绍 Java是一种面向对象的语言&#xff0c;而Java对象在JVM中存储是由一定结构的。而这个 Java对象自身的存储模型称之为Java对象模型HotSpot虚拟机中&#xff0c;设计了一个OOP-Klass Model.OOP指的是普通对象指针&#xff0c;而Klass用来描述对象的具体类型。如下图所示是一…

文章生成器写出来的原创文章

文章生成机器人 文章生成机器人是一种基于人工智能技术和自然语言处理算法的程序&#xff0c;可以自动地生成高质量、原创的文章。 文章生成机器人的优点如下&#xff1a; 提高工作效率&#xff1a;文章生成机器人能够在较短的时间内自动帮助用户生成大量的文章&#xff0c;提…