Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Commit

Permalink
move webtorrent to the browser process
Browse files Browse the repository at this point in the history
  • Loading branch information
dcposch committed Nov 9, 2016
1 parent 0904d89 commit b0de397
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 42 deletions.
102 changes: 102 additions & 0 deletions app/browser/webtorrent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
const electron = require('electron')
const ipc = electron.ipcMain
const messages = require('../../js/constants/messages')
const WebTorrent = require('webtorrent')

var DEBUG_IPC = false // Set to see communication between WebTorrent and torrent viewer tabs
var ANNOUNCE = [
'wss://tracker.btorrent.xyz',
'wss://tracker.openwebtorrent.com',
'wss://tracker.fastcast.nz'
]

var client = null
var channels = {}

ipc.on(messages.TORRENT_MESSAGE, function (e, msg) {
if (DEBUG_IPC) console.log('Received IPC: ' + JSON.stringify(msg))
channels[msg.channelID] = e.sender
handleMessage(msg)
})

function handleMessage (msg) {
switch (msg.type) {
case 'add':
return handleAdd(msg)
default:
// Sanity check. Is there a better way to do error logging in the browser process?
console.error('Ignoring unknown action ' + msg.type + ', channel ' + msg.channelID)
}
}

function handleAdd (msg) {
var torrent = lazyClient().add(msg.torrentID, {
announce: ANNOUNCE
})
if (torrent.channelID) throw new Error('torrent already has a channelID')
// TODO: handle the case where two different tabs (two different channels)
// both open the same infohash
torrent.channelID = msg.channelID
addTorrentEvents(torrent)
}

function addClientEvents () {
client.on('error', function (err) {
sendToAllChannels({errorMessage: err.message})
})
}

function addTorrentEvents (torrent) {
torrent.on('infohash', () => sendInfo(torrent))
torrent.on('metadata', () => sendInfo(torrent))
torrent.on('progress', () => sendProgress(torrent))
torrent.on('done', () => sendProgress(torrent))
}

function sendProgress (torrent) {
send({
type: 'progress',
channelID: torrent.channelID,
progress: torrent.progress
})
}

function sendInfo (torrent) {
var msg = {
type: 'info',
channelID: torrent.channelID,
torrent: {
name: torrent.name,
infohash: torrent.infohash,
progress: torrent.progress,
files: []
}
}
if (torrent.files) {
msg.torrent.files = torrent.files.map(function (file) {
return {
name: file.name
}
})
}
send(msg)
}

function send (msg) {
if (DEBUG_IPC) console.log('Sending IPC: ' + JSON.stringify(msg))
channels[msg.channelID].send(messages.TORRENT_MESSAGE, msg)
}

function sendToAllChannels (msg) {
for (var channelID in channels) {
var channelMsg = Object.assign({}, msg, {channelID})
send(channelMsg)
}
}

function lazyClient () {
if (client) return client
client = new WebTorrent()
addClientEvents()
return client
}
1 change: 1 addition & 0 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const basicAuth = require('./browser/basicAuth')
const async = require('async')
const tabs = require('./browser/tabs')
const settings = require('../js/constants/settings')
require('./browser/webtorrent')

// temporary fix for #4517, #4518 and #4472
app.commandLine.appendSwitch('enable-use-zoom-for-dsf', 'false')
Expand Down
21 changes: 21 additions & 0 deletions js/components/frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -881,10 +881,31 @@ class Frame extends ImmutableComponent {
method = (currentDetail, originalDetail) =>
windowActions.setAutofillCreditCardDetail(currentDetail, originalDetail)
break
case messages.TORRENT_MESSAGE:
// Relay torrent IPC from the webview to a browser process
method = (message) => {
if (typeof message.channelID !== 'string') {
throw new Error('Invalid or missing channelID: ' + JSON.stringify(message))
}
if (this.torrentChannelID && this.torrentChannelID !== message.channelID) {
throw new Error('ChannelID changed, expected ' + this.torrentChannelID +
': ' + JSON.stringify(message))
}
this.torrentChannelID = message.channelID
ipc.send(messages.TORRENT_MESSAGE, message)
}
break
}
method.apply(this, e.args)
})

// Relay torrent IPC from the browser process back to the webview
ipc.on(messages.TORRENT_MESSAGE, (e, obj) => {
// Ignore the message if it's for a different tab
if (obj.channelID !== this.torrentChannelID) return
this.webview.send(messages.TORRENT_MESSAGE, obj)
})

const interceptFlash = (stopCurrentLoad, adobeUrl, redirectUrl) => {
if (!this.origin) {
return
Expand Down
4 changes: 3 additions & 1 deletion js/constants/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ const messages = {
LEDGER_UPDATED: _,
LEDGER_CREATE_WALLET: _,
CHECK_BITCOIN_HANDLER: _,
ADD_FUNDS_CLOSED: _
ADD_FUNDS_CLOSED: _,
// Torrent
TORRENT_MESSAGE: _
}

module.exports = mapValuesByKeys(messages)
84 changes: 43 additions & 41 deletions js/webtorrent/entry.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,63 @@
const ReactDOM = require('react-dom')
const magnetURI = require('magnet-uri')
const Button = require('../components/button')
const messages = require('../constants/messages')
const uuid = require('uuid')

/**
* TODO: Once WebTorrent is running in it's own process, replace the window
* globals with require() calls. Delete ext/webtorrent.min.js.
*/
const WebTorrent = window.WebTorrent // require('webtorrent')

/**
* TODO: Replace hard-coded list of community trackers with latest list from
* create-torrent package, similar to how WebTorrent Desktop does it here:
* https://github.com/feross/webtorrent-desktop/blob/4bb2056bc9c1a421815b97d03ffed512575dfde0/src/renderer/webtorrent.js#L29-L31
*/
window.WEBTORRENT_ANNOUNCE = [
'wss://tracker.btorrent.xyz',
'wss://tracker.openwebtorrent.com',
'wss://tracker.fastcast.nz'
]

var state = {
torrentId: window.location.hash.substring(1),
require('../../less/webtorrent.less')

// Set window.state for easier debugging
var state = window.state = {
torrentID: window.location.hash.substring(1),
torrent: null,
progress: 0,
files: [],
dn: '',
errorMessage: '',
isFileLoaded: false
}

require('../../less/webtorrent.less')

// Start downloading the torrent
var client = window.client = new WebTorrent()
client.on('error', onError)

// Show download progress
setInterval(render, 1000)
render()

// Talk to the webtorrent process
var CHANNEL_ID = uuid.v4()
var ipc = window.chrome.ipc
ipc.on(messages.TORRENT_MESSAGE, function (e, msg) {
switch (msg.type) {
case 'info':
return handleInfo(msg)
case 'progress':
return handleProgress(msg)
case 'error':
return handleError(msg)
}
})

function handleInfo (msg) {
state.torrent = msg.torrent
}

function handleProgress (msg) {
if (state.torrent) state.torrent.progress = msg.progress
}

function handleError (msg) {
state.errorMessage = msg.errorMessage
}

function start () {
state.torrent = client.add(state.torrentId)
ipc.sendToHost(messages.TORRENT_MESSAGE, {
channelID: CHANNEL_ID,
type: 'add',
torrentID: state.torrentID
})
}

function render () {
var torrent = state.torrent
var id = state.torrentId
var id = state.torrentID

// TODO: right now, we only support magnet links as the torrentId
// TODO: right now, we only support magnet links as the torrentID
// Eventually, we need to support .torrent files as well, prob using parse-torrent
if (!state.magnetInfo && id.startsWith('magnet:?')) {
state.magnetInfo = magnetURI(id)
Expand Down Expand Up @@ -94,18 +104,14 @@ function render () {
</div>
)
} else if (state.magnetInfo && state.magnetInfo.ix != null) {
// TODO: load over HTTP, either into an <iframe>
// ... or pick <video> / <audio> / <img> etc based on filetype
// var ix = Number(state.magnetInfo.ix)
content = (
<div className='content'>
<div id='fileContainer' />
</div>
)

var ix = Number(state.magnetInfo.ix)
if (torrent && torrent.files && torrent.files[ix] && !state.isFileLoaded) {
var file = state.torrent.files[ix]
file.appendTo(document.querySelector('#fileContainer'))
state.isFileLoaded = true
}
} else {
var fileElems = torrent.files.map((file, i) => {
return (
Expand Down Expand Up @@ -154,7 +160,3 @@ function render () {
)
ReactDOM.render(elem, document.querySelector('#appContainer'))
}

function onError (err) {
state.errorMessage = err.message
}

0 comments on commit b0de397

Please sign in to comment.