webtorrent / webtorrent-hybrid

WebTorrent (with WebRTC support in Node.js)
https://webtorrent.io
MIT License
519 stars 98 forks source link

What am i missing? #113

Closed KilianKilmister closed 4 years ago

KilianKilmister commented 4 years ago

while looking for nodejs-torrent clients, i wantet to give webtorrent a try, and since i want to use it server-side, i followed the instructions to webtorrent-hybrid. And looking at this repo begs the question: Why is there a whole seperate package for 16 lines of code?

I'm sorry, and i'm really not trying to offend anybody, but i can't wrap my head around it. and most of the code consists of require-statements. Can someone please tell me what i'm missing here?

For your visualisation, this is all the code

bin/cmd.js

#!/usr/bin/env node

require('../lib/global')
require('webtorrent-cli/bin/cmd')

index.js

require('./lib/global')
module.exports = require('webtorrent')

lib/global.js

const createTorrent = require('create-torrent')
const wrtc = require('wrtc')

global.WEBTORRENT_ANNOUNCE = createTorrent.announceList
  .map(arr => arr[0])
  .filter(url => url.indexOf('wss://') === 0 || url.indexOf('ws://') === 0)

global.WRTC = wrtc
tudor-pop commented 4 years ago

Hey, welcome to the project! I was thinking the same but then I started to fork some related the projects today since I believe there is a bug if you iterate over an array of magnet links and call .add on each one of them....anyways...to answer your question, check out this constructor. So how I think it works, when using webtorrent-hybrid you set the global.WRTC variable then when you do require('webtorrent-hybrid') it loads up index.js that you specified above and in doing so, it also loads ./lib/global which initialises first of all global.WRTC = wrtc then it require('webtorrent') and by this time the constructor has the global.WRTC variable already set.

require('webtorrent-hybrid') -> global.WRTC=wrtc -> require('webtorrent') -> new Webtorrent(){ ....internally checks global.WRTC.....}

SilentBot1 commented 4 years ago

Hi @KilianKilmister

From my understanding, this package is separated out into a separate repository as it combines multiple existing components, into one new package which has a different use case and functionality, which could end up bloating the master package. e.g. your browser doesn't need to know how to create a command-line interface of the WebTorrent client.

These three files outline two use cases, one when the file is being used via the command line using the webtorrent-hybrid following the installation of webtorrent-hybrid globally e.g. npm i -g webtorrent-hybrid and the second when webtorrent-hybrid is used within a NodeJS application.

The key file here is the global.js, this sets up the special sauce which allows this client to speak with WebRTC peers. By default, NodeJS doesn't have an implementation of WebRTC, so we must require in an external implementation of called wrtc. In the main webtorrent repository, this is expected to run in browsers and thus uses the variable global.WRTC to determine if the client supports WebRTC, this is why we must set global.WRTC to our wrtc implementation.

The main webtorrent library also uses the global.WEBTORRENT_ANNOUNCE property to pull it's default announce list, the create-torrent library has a list of built-in list of trackers and this is why we pull this module to load our list of default trackers, as the module is already installed in the project by the dependencies.

The cmd.js file is run, first setting the values described above, then launching webtorrent-cli with the above values set while the application is run from the command line (use case 1) whereas the main webtorrent library is loaded after again, the global variables discussed above are set, to allow the application to be used programmatically (use case 2).

Again, the specific bloat that would come from this is the inclusion of packages like webtorrent-cli and wrtc within the main package and bundle, causing the file to be unnecessarily large for clients which either don't need or won't use the code mentioned.

@PopTudor, thank you very much for giving @KilianKilmister an explanation regarding this, hopefully with both of these put together he now has a full understanding of why this has been done.

As this is more of a question rather than an issue, I'm going to close this, but if you disagree with this or would like to continue to the discussion, please feel free to either re-open the issue or continue the conversation in the closed ticket respectively.

Many thanks Brad Marsden

tudor-pop commented 4 years ago

@SilentBot1 Thanks for the detailed explanation, it truly helps

KilianKilmister commented 4 years ago

@SilentBot1 @PopTudor Thanks for the elaboration. I didn't consider the global assignment. I think part of my confusion came from one of the listed features of the main package:

  • Torrent client for node.js & the browser (same npm package!)

It made me wonder why there was an additional package needed to make them interoperable. Before i posed the question i just finished a 20h programming session and i guess together with my surprise of how little code there was in hybrid made me not look carefully enough.

I see now that webtorrent-cli isn't actually bundled in the non-hybrid version and i didn't consider (or rather know enough about this stuff) that node doesn't have a WebRTC implementation and many node-users of webtorrent will probably not need it either.

just rambling from here on out

Man, all that browser stuff always confuses the hell out of me. I pretty much exclusively work at the backend, started working with JS/ES with node v13 and have only ever used native esm-modules because of how smooth they work and naturally integrate with TS-language-features. And that also meant I could use all the latest ES-features as I didn't have to worry about backwards compatibility.

And man, JS/ES in the browser can be total anarchy with all the globals being created and the load order sensitivity. This together with thinking about backward compatibility forcing me to use bundlers and transpilers, creating a layer of separation between me and the product.
The thing that made me fall in love with node in the first place is howhands-on, cross-compatible and flexible it is with the JIT-compilation and how with ESM i can carefully pick and choose exactly what I want where.

Every time i need to do something for the browser it ends up as some patchwork of code. Sure it works decently well, but it's just not the smooth symphony i'm used to from the backend that i cherish so much.

My apologies for this little rant, maybe someday i'll understand the browser environment.

anyways; thanks again for the detailed explanation

tudor-pop commented 4 years ago

@KilianKilmister yep I feel the same about JS in general. Also before using this module, this issue might be of interest in what you're trying to accomplish. I am also blocked by the issue but I'm trying to find a workaround.