【p2p、分布式,区块链笔记 Torrent】WebTorrent的add和seed函数

  • 在【p2p、分布式,区块链笔记 Torrent】WebTorrent的上传和下载界面的示例中,主要通过WebTorrent类的add和seed函数实现相关功能。这两个函数都返回一个Torrent类对象的实例。

seed函数

import createTorrent, { parseInput } from 'create-torrent' // "create-torrent": "^6.0.18"

  /**
   * Start seeding a new file/folder.
   * @param  {string|File|FileList|Buffer|Array.<string|File|Buffer>} input
   * @param  {Object=} opts
   * @param  {function=} onseed called when torrent is seeding
   */
  seed (input, opts, onseed) {
    if (this.destroyed) throw new Error('client is destroyed')
    if (typeof opts === 'function') [opts, onseed] = [{}, opts]

    this._debug('seed')
    opts = opts ? Object.assign({}, opts) : {}

    // no need to verify the hashes we create
    opts.skipVerify = true

    const isFilePath = typeof input === 'string'

    // When seeding from fs path, initialize store from that path to avoid a copy
    if (isFilePath) opts.path = path.dirname(input)
    if (!opts.createdBy) opts.createdBy = `WebTorrent/${VERSION_STR}`

    const onTorrent = torrent => {
      const tasks = [
        cb => {
          // when a filesystem path is specified or the store is preloaded, files are already in the FS store
          if (isFilePath || opts.preloadedStore) return cb()
          torrent.load(streams, cb)
        }
      ]
      if (this.dht) {
        tasks.push(cb => {
          torrent.once('dhtAnnounce', cb)
        })
      }
      parallel(tasks, err => {
        if (this.destroyed) return
        if (err) return torrent._destroy(err)
        _onseed(torrent)
      })
    }

    const _onseed = torrent => {
      this._debug('on seed')
      if (typeof onseed === 'function') onseed(torrent)
      torrent.emit('seed')
      this.emit('seed', torrent)
    }

    const torrent = this.add(null, opts, onTorrent)
    let streams

    if (isFileList(input)) input = Array.from(input)
    else if (!Array.isArray(input)) input = [input]

    parallel(input.map(item => async cb => {
      if (!opts.preloadedStore && isReadable(item)) {
        const chunks = []
        try {
          for await (const chunk of item) {
            chunks.push(chunk)
          }
        } catch (err) {
          return cb(err)
        }
        const buf = concat(chunks)
        buf.name = item.name
        cb(null, buf)
      } else {
        cb(null, item)
      }
    }), (err, input) => {
      if (this.destroyed) return
      if (err) return torrent._destroy(err)

      parseInput(input, opts, (err, files) => {
        if (this.destroyed) return
        if (err) return torrent._destroy(err)

        streams = files.map(file => file.getStream)

        createTorrent(input, opts, async (err, torrentBuf) => {
          if (this.destroyed) return
          if (err) return torrent._destroy(err)

          const existingTorrent = await this.get(torrentBuf)
          if (existingTorrent) {
            console.warn('A torrent with the same id is already being seeded')
            torrent._destroy()
            if (typeof onseed === 'function') onseed(existingTorrent)
          } else {
            torrent._onTorrentId(torrentBuf)
          }
        })
      })
    })

    return torrent
  }
  • 代码中的关键一句是:
const torrent = this.add(null, opts, onTorrent)
  • 函数最终返回生成的 torrent 对象,其由add函数创建(第一个参数为null),代表正在进行 seeding 的种子。
  • 这句代码实际上启动了种子(torrent)的创建和处理过程。它调用了 this.add() 方法,将 optsonTorrent 回调传递进去,这些回调负责在种子完成处理时执行进一步的操作。
  • 另一个关键的一句是
createTorrent(input, opts, async (err, torrentBuf) => {……})
  • 调用 createTorrent 生成种子文件,并通过 onTorrent 处理后续操作(如 DHT 发布广播等)

  • DHT 广播的过程发生在 onTorrent 回调中的这段代码部分:

if (this.dht) {// DHT 是否启用
  tasks.push(cb => { // 将一个任务推送到任务队列tasks 中
    torrent.once('dhtAnnounce', cb) // 监听torrent对象的dhtAnnounce事件。once意味着该事件处理器仅会触发一次,当dhtAnnounce事件发生时,执行回调 `cb`。
  })
}
  • 当种子(torrent)开始上传并与其他节点建立连接时,WebTorrent 会尝试将种子信息通过 DHT 广播出去,允许其他客户端在没有 Tracker 的情况下发现这个种子。
  • torrent.once('dhtAnnounce', cb) 监听的是这个广播完成后的通知,当种子成功通过 DHT 被宣布时,cb 被执行,表示广播成功。
parallel(tasks, err => {
  if (this.destroyed) return
  if (err) return torrent._destroy(err)
  _onseed(torrent)
})
  • parallel(tasks, cb) 用来并行执行所有任务,确保所有操作(如文件加载、DHT 广播等)都执行完毕后再继续。
  • 如果没有错误发生,_onseed(torrent) 会被调用,表示种子已经开始上传,并且相关事件会被触发。

add函数

/**
   * Start downloading a new torrent. Aliased as `client.download`.
   * @param {string|Buffer|Object} torrentId
   * @param {Object} opts torrent-specific options
   * @param {function=} ontorrent called when the torrent is ready (has metadata)
   */
  add (torrentId, opts = {}, ontorrent = () => {}) {
    if (this.destroyed) throw new Error('client is destroyed')
    if (typeof opts === 'function') [opts, ontorrent] = [{}, opts]

    const onInfoHash = () => {
      if (this.destroyed) return
      for (const t of this.torrents) {
        if (t.infoHash === torrent.infoHash && t !== torrent) {
          torrent._destroy(new Error(`Cannot add duplicate torrent ${torrent.infoHash}`))
          ontorrent(t)
          return
        }
      }
    }

    const onReady = () => {
      if (this.destroyed) return
      ontorrent(torrent)
      this.emit('torrent', torrent)
    }

    function onClose () {
      torrent.removeListener('_infoHash', onInfoHash)
      torrent.removeListener('ready', onReady)
      torrent.removeListener('close', onClose)
    }

    this._debug('add')
    opts = opts ? Object.assign({}, opts) : {}

    const torrent = new Torrent(torrentId, this, opts)  // Create a new Torrent instance using the provided torrentId, current client (`this`), and options (`opts`).
    this.torrents.push(torrent) //Add the new torrent to the list of active torrents.

    torrent.once('_infoHash', onInfoHash)  //监听 _infoHash 事件来检查是否存在重复的种子。
    torrent.once('ready', onReady)  // 监听 ready 事件,当种子准备好时执行回调。
    torrent.once('close', onClose)  // 监听 close 事件,清理资源和事件监听器。

    this.emit('add', torrent)
    return torrent
  }
  • 关键一句是:
const torrent = new Torrent(torrentId, this, opts)
  • 这行代码负责创建一个新的 Torrent 实例,并将其添加到当前 WebTorrent 客户端中,开始处理指定的种子。Torrent类定义在 lib\torrent.js中。相关接口与功能可见docs\api.md的Torrent部分
  • 以下是对 torrent 方法的简单总结,使用表格呈现:
方法名功能描述参数返回值
torrent.destroy([opts], [callback])删除种子,销毁与对等体的所有连接,并删除所有保存的文件元数据。
可以选择销毁存储的文件。
当完全销毁后调用 callback
opts (可选): 配置销毁选项,例如是否销毁存储。
callback (可选): 完成销毁后的回调。
torrent.addPeer(peer)向种子加入一个对等体。通常不需要手动调用,WebTorrent 会自动发现对等体。
手动添加时需确保 infoHash 事件已触发。
peer: 对等体地址(如 “12.34.56.78:4444”)或 simple-peer 实例(WebRTC对等体)。true(添加成功)或 false(被阻止,可能因黑名单)。
torrent.addWebSeed(urlOrConn)向种子加入一个 Web Seed。
Web Seed 是通过 HTTP(S) 提供种子数据的源。
支持 URL 或自定义连接对象。
urlOrConn: Web Seed URL 或自定义连接对象(实现 BitTorrent 协议的 Duplex 流,必须具有 connId)。
torrent.removePeer(peer)从种子中移除一个对等体。WebTorrent 会自动移除慢速或没有所需数据的对等体。
手动移除时指定对等体标识。
peer: 对等体地址(如 “ip:port”)、peer id(hex 字符串)或 simple-peer 实例。
torrent.select(start, end, [priority], [notify])选择一范围的数据块,优先下载该范围内的数据。
可以指定优先级和回调。
start, end: 数据块范围(包含)。
priority (可选): 优先级。
notify (可选): 更新时触发的回调。
torrent.deselect(start, end)取消选择一范围的数据块,从而降低优先级。start, end: 数据块范围(包含)。
torrent.critical(start, end)将一范围的数据块标记为关键优先级,要求尽快下载。start, end: 数据块范围(包含)。
torrent.pause()暂停连接新的对等体。
此操作不影响现有连接或流。
torrent.resume()恢复与新对等体的连接。恢复连接新的对等体,开始与更多对等体交换数据。
torrent.rescanFiles([callback])扫描文件并验证存储中的每个数据块的哈希值,更新已下载的有效数据块的位图。通常用于外部进程添加文件时,确保 WebTorrent 识别这些文件。
完成后会调用回调。
callback (可选): 扫描完成时的回调函数,callback(err)
torrent.on('infoHash', function () {})当种子的 infoHash 确定时触发该事件。
torrent.on('metadata', function () {})当种子的元数据(包括 .torrent 文件的内容)确定时触发该事件。
torrent.on('ready', function () {})当种子准备好使用时触发该事件,表示元数据已就绪且存储准备好。
torrent.on('warning', function (err) {})当种子遇到警告时触发该事件。此事件仅用于调试,不一定需要监听。err: 警告信息。
torrent.on('error', function (err) {})当种子遇到致命错误时触发该事件,种子会被自动销毁并从客户端移除。err: 错误信息。
torrent.on('done', function () {})当所有种子文件下载完成时触发该事件。当所有文件下载完毕时触发,通常用于通知用户下载完成。
torrent.on('download', function (bytes) {})当数据被下载时触发该事件,用于报告当前种子的下载进度。bytes: 本次下载的字节数。用于监控下载进度,返回已下载的字节数,并可查询总下载量、下载速度等。
torrent.on('upload', function (bytes) {})当数据被上传时触发该事件,用于报告当前种子的上传进度。bytes: 本次上传的字节数。用于监控上传进度,返回已上传的字节数。
torrent.on('wire', function (wire) {})每当一个新的对等体连接时触发该事件,wire 是一个 bittorrent-protocol 实现的 Duplex 流。可以使用它来扩展 BitTorrent 协议或进行其他自定义操作。wire: 与对等体连接的流对象。用于处理与对等体的通信,可扩展 BitTorrent 协议或处理自定义协议。
torrent.on('noPeers', function (announceType) {})每隔几秒当没有找到对等体时触发。announceType 指明了导致该事件触发的公告类型,可能是 'tracker''dht''lsd''ut_pex'。如果尝试通过多个方式发现对等体,如跟踪器、DHT、LSD 或 PEX,将会为每种公告分别触发此事件。announceType: 字符串,指示公告类型,可以是 'tracker''dht''lsd'、或 'ut_pex'当没有对等体可用且公告方式不同(例如 tracker、DHT、LSD 或 PEX)时触发此事件。
torrent.on('verified', function (index) {})每当一个数据块被验证时触发。事件的参数是被验证数据块的索引。index: 整数,表示被验证的块的索引。每次数据块的哈希值被验证时触发此事件。

torrent & wire

  • torrent.on(‘wire’, function (wire) {}) 是在 WebTorrent 客户端中,当一个新的对等体(peer)连接时,触发的事件。当这个事件被触发时,wire 会作为参数传递给回调函数。wire 是一个 bittorrent-protocol 的实例,这是一个用于实现 BitTorrent 协议的 duplex 流(双向流),允许客户端与远程对等体(peer)进行数据交换。

  • 以下是一个示例:

import MyExtension from './my-extension'

torrent1.on('wire', (wire, addr) => {
  console.log('connected to peer with address ' + addr)
  wire.use(MyExtension)
})
  • 实际上torrent中管理者相关的链接对象,如以下代码所示:
client.add(opts.magnetURI,torrent => {
				const wire = torrent.wires[0];
				wire.use(MyExtension());
				wire.MyExtension.on('hack_message', func);
			    })

client.seed(buf, torrent => {
	torrent.on('wire', (wire, addr) => {
	wire.use(MyExtension());
	wire.MyExtension.on('hack_message', func);
	}
})
  • wires 是一个数组,包含与该种子相关的所有 wire 对象。每个 wire 代表与一个对等体(peer)之间的连接。torrent.wires[0] 代表与第一个对等体(peer)建立的连接(wire)。

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

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

相关文章

LDO电路分析

一、LDO概述 在电压转换电路中&#xff0c;LDO和DC-DC电路是最常用的两种方式&#xff0c;本篇主要介绍LDO相关内容。 LDO是线性电源的一种&#xff0c;它可以实现电源电压的转换&#xff0c;不过主要用在降压领域。它的全称是Low Dropout Regulaor&#xff0c;就是低压差线性…

VirtualBox虚拟机扩容详解

VirtualBox虚拟机扩容详解 virtualbox 扩容找到虚拟机需要扩容的磁盘更改虚拟磁盘的大小 逻辑卷扩容1. 扩展物理卷2. 扩展逻辑卷3. 扩展文件系统 Ubuntu系统安转 minikube 集群后&#xff0c;提示文件系统要炸了&#xff0c;效果如下&#xff1a;可以明显看到 /dev/mapper/ubu…

第02章 MySQL环境搭建

一、MySQL的卸载 如果安装mysql时出现问题&#xff0c;则需要将mysql卸载干净再重新安装。如果卸载不干净&#xff0c;仍然会报错安装不成功。 步骤1&#xff1a;停止MySQL服务 在卸载之前&#xff0c;先停止MySQL8.0的服务。按键盘上的“Ctrl Alt Delete”组合键&#xff0…

HTML 基础概念:什么是 HTML ? HTML 的构成 与 HTML 基本文档结构

文章目录 什么是 HTML &#xff1f;HTML 的构成 &#xff1f;什么是 HTML 元素&#xff1f;HTML 元素的组成部分HTML 元素的特点 HTML 基本文档结构如何打开新建的 HTML 文件代码查看 什么是 HTML &#xff1f; HTML&#xff08;超文本标记语言&#xff0c;HyperText Markup L…

AI笔筒操作说明及应用场景

AI笔筒由来&#xff1a; 在快节奏的现代办公环境中&#xff0c;我们一直在寻找既能提升效率、增添便利&#xff0c;又能融入企业文化、展现个人品味的桌面伙伴。为此&#xff0c;我们特推出专为追求卓越、注重细节的您设计的AI笔筒礼品版&#xff0c;它集高科技与实用性于一身…

开源项目OpenVoice的本地部署

前言 本文介绍开源项目OpenVoice的本地部署&#xff0c;基于VsCode和Anaconda(提供python虚拟环境)&#xff0c;来进行部署的。下述不介绍Anaconda的安装流程&#xff0c;要自行安装。且只截图演示关键部分图文演示。 官方项目介绍&#xff1a;OpenVoice&#xff1a;多功能即时…

【Vue 全家桶】2、Vue 组件化编程

目录 模块与组件、模块化与组件化 component模块组件 非单文件组件单文件组件 .vue 模块与组件、模块化与组件化 component 模块 组件 局部功能代码和资源的集合 非单文件组件 // 1、创建组件 const school Vue.extend({data(){return {}} }) const student Vue.extend(…

11.6 校内模拟赛总结

打的很顺的一场 复盘 7:40 开题&#xff0c;看到题目名很interesting T1 看起来很典&#xff0c;中位数显然考虑二分&#xff0c;然后就是最大子段和&#xff1b;T2 构造&#xff1f;一看数据范围这么小&#xff0c;感觉不是很难做&#xff1b;T3 神秘数据结构&#xff1b;T…

nacos本地虚拟机搭建切换wiff问题

背景 在自己的电脑上搭建了vm虚拟机&#xff0c;安装上系统&#xff0c;设置网络连接。然后在vm的系统上安装了中间件nacos&#xff0c;mysql&#xff0c;redis等&#xff0c;后续用的中间件都是在虚拟机系统上安装的&#xff0c;开发在本地电脑上。 我本地启动项目总是请求到…

深入探讨钉钉与金蝶云星空的数据集成技术

钉钉报销数据集成到金蝶云星空的技术案例分享 在企业日常运营中&#xff0c;行政报销流程的高效管理至关重要。为了实现这一目标&#xff0c;我们采用了轻易云数据集成平台&#xff0c;将钉钉的行政报销数据无缝对接到金蝶云星空的付款单系统。本次案例将重点介绍如何通过API接…

Rust 力扣 - 3090. 每个字符最多出现两次的最长子字符串

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 本题使用滑动窗口进行求解&#xff0c;使用左指针和右指针分别表示窗口的左边界和窗口的右边界&#xff0c;使用哈希表记录窗口内的字符及其对应数量 我们首先向右移动右指针&#xff0c;将字符加入到哈希表中进…

Jekins篇(搭建/安装/配置)

目录 一、环境准备 1. Jenkins安装和持续集成环境配置 2. 服务器列表 3. 安装环境 Jekins 环境 4. JDK 环境 5. Maven环境 6. Git环境 方法一&#xff1a;yum安装 二、JenKins 安装 1. JenKins 访问 2. jenkins 初始化配置 三、Jenkins 配置 1. 镜像配置 四、Mave…

uniApp使用canvas制作签名板

插件市场大佬封装好的 组件 可以直接拿过去 <template><viewclass"whole canvas-autograph flexc"touchmove.prevent.stopwheel.prevent.stopv-show"modelValue"><canvasclass"scroll-view"id"mycanvas"canvas-id&quo…

解决Knife4j 接口界面UI中文乱码问题

1、查看乱码情况 2、修改 编码设置 3、删除 target 文件 项目重新启动 被坑死了

FFmpeg 4.3 音视频-多路H265监控录放C++开发八,使用SDLVSQT显示yuv文件 ,使用ffmpeg的AVFrame

一. AVFrame 核心回顾&#xff0c;uint8_t *data[AV_NUM_DATA_POINTERS] 和 int linesize[AV_NUM_DATA_POINTERS] AVFrame 存储的是解码后的数据&#xff0c;&#xff08;包括音频和视频&#xff09;例如&#xff1a;yuv数据&#xff0c;或者pcm数据&#xff0c;参考AVFrame结…

【算法】递归+深搜+哈希表:889.根据前序和后序遍历构造二叉树

目录 1、题目链接 相似题目: 2、题目 ​3、解法&#xff08;针对无重复值&#xff0c;哈希表递归&#xff09; 函数头-----找出重复子问题 函数体---解决子问题 4、代码 1、题目链接 889.根据前序和后序遍历构造二叉树&#xff08;LeetCode&#xff09; 相似题目: 105.…

基于SpringBoot的“乐校园二手书交易管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“乐校园二手书交易管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统首页界面图 用户注册界面图 二手…

“高效开发之路:用Spring MVC构建健壮的企业级应用”

一、SpringMVC框架概念&#xff1a; &#xff08;一&#xff09;概述 SpringMVC是Spring框架的一个模块&#xff0c;Spring和SpringMVC无需中间整合层整合。该模块是一个基于MVC的web框架。 作用&#xff1a;只要需要前后端通信&#xff0c;就需要springMVC帮我完成&#xff…

练习LabVIEW第四十一题

学习目标&#xff1a; 编写一个程序测试自己在程序前面板上输入一段文字“CSDN是一个优秀的网站”所用的时间。 开始编写&#xff1a; 前面板放置一个数值显示控件&#xff0c;程序框图添加顺序结构共三帧&#xff0c;第一帧放一个获取日期/时间&#xff08;秒&#xff09;函…

编程之路:蓝桥杯备赛指南

文章目录 一、蓝桥杯的起源与发展二、比赛的目的与意义三、比赛内容与形式四、比赛前的准备五、获奖与激励六、蓝桥杯的影响力七、蓝桥杯比赛注意事项详解使用Dev-C的注意事项 一、蓝桥杯的起源与发展 蓝桥杯全国软件和信息技术专业人才大赛&#xff0c;简称蓝桥杯&#xff0c…