diff --git a/client/index.js b/client/index.js index 9bad6898..12abe95f 100644 --- a/client/index.js +++ b/client/index.js @@ -1,222 +1,26 @@ -/* global URL, Blob */ +var createElement = require('virtual-dom/create-element') +var diff = require('virtual-dom/diff') +var patch = require('virtual-dom/patch') -var createTorrent = require('create-torrent') -var debug = require('debug')('instant.io') -var dragDrop = require('drag-drop') -// var listify = require('listify') -var path = require('path') -var prettyBytes = require('pretty-bytes') -var throttle = require('throttleit') -var thunky = require('thunky') -var uploadElement = require('upload-element') -var WebTorrent = require('webtorrent') -var xhr = require('xhr') -var torrentPoster = require('./torrent-poster') +var App = require('./views/app') -var util = require('./util') - -global.WEBTORRENT_ANNOUNCE = createTorrent.announceList - .map(function (arr) { - return arr[0] - }) - .filter(function (url) { - return url.indexOf('wss://') === 0 || url.indexOf('ws://') === 0 - }) - -var getClient = thunky(function (cb) { - getRtcConfig('https://instant.io/rtcConfig', function (err, rtcConfig) { - if (err) util.error(err) - createClient(rtcConfig) - }) - - function createClient (rtcConfig) { - var client = window.client = new WebTorrent({ rtcConfig: rtcConfig }) - client.on('warning', util.warning) - client.on('error', util.error) - cb(null, client) - } -}) - -// For performance, create the client immediately -getClient(function () {}) - -// Seed via upload input element -var upload = document.querySelector('input[name=upload]') -uploadElement(upload, function (err, files) { - if (err) return util.error(err) - files = files.map(function (file) { return file.file }) - onFiles(files) -}) - -// Seed via drag-and-drop -dragDrop('body', onFiles) - -// Download via input element -document.querySelector('form').addEventListener('submit', function (e) { - e.preventDefault() - downloadTorrent(document.querySelector('form input[name=torrentId]').value.trim()) -}) - -// Download by URL hash -onHashChange() -window.addEventListener('hashchange', onHashChange) -function onHashChange () { - var hash = decodeURIComponent(window.location.hash.substring(1)).trim() - if (hash !== '') downloadTorrent(hash) +var state = { + count: 0 } -// Warn when leaving and there are no other peers -// window.addEventListener('beforeunload', onBeforeUnload) +// Init app +var currentVDom = App(state) +var rootElement = createElement(currentVDom) +document.body.appendChild(rootElement) -// Register a protocol handler for "magnet:" (will prompt the user) -// navigator.registerProtocolHandler('magnet', window.location.origin + '#%s', 'Instant.io') - -function getRtcConfig (url, cb) { - xhr(url, function (err, res) { - if (err || res.statusCode !== 200) { - cb(new Error('Could not get WebRTC config from server. Using default (without TURN).')) - } else { - var rtcConfig - try { - rtcConfig = JSON.parse(res.body) - } catch (err) { - return cb(new Error('Got invalid WebRTC config from server: ' + res.body)) - } - debug('got rtc config: %o', rtcConfig) - cb(null, rtcConfig) - } - }) +function update () { + var newVDom = App(state) + var patches = diff(currentVDom, newVDom) + rootElement = patch(rootElement, patches) + currentVDom = newVDom } -function onFiles (files) { - debug('got files:') - files.forEach(function (file) { - debug(' - %s (%s bytes)', file.name, file.size) - }) - - // .torrent file = start downloading the torrent - files.filter(isTorrentFile).forEach(downloadTorrentFile) - - // everything else = seed these files - seed(files.filter(isNotTorrentFile)) -} - -function isTorrentFile (file) { - var extname = path.extname(file.name).toLowerCase() - return extname === '.torrent' -} - -function isNotTorrentFile (file) { - return !isTorrentFile(file) -} - -function downloadTorrent (torrentId) { - util.log('Downloading torrent from ' + torrentId) - getClient(function (err, client) { - if (err) return util.error(err) - client.add(torrentId, onTorrent) - }) -} - -function downloadTorrentFile (file) { - util.log('Downloading torrent from ' + file.name + '') - getClient(function (err, client) { - if (err) return util.error(err) - client.add(file, onTorrent) - }) -} - -function seed (files) { - if (files.length === 0) return - util.log('Seeding ' + files.length + ' files') - - // Seed from WebTorrent - getClient(function (err, client) { - if (err) return util.error(err) - client.seed(files, onTorrent) - }) -} - -function onTorrent (torrent) { - upload.value = upload.defaultValue // reset upload element - - var torrentFileName = path.basename(torrent.name, path.extname(torrent.name)) + '.torrent' - - util.log('"' + torrentFileName + '" contains ' + torrent.files.length + ' files:') - torrent.files.forEach(function (file) { - util.log(' - ' + file.name + ' (' + prettyBytes(file.length) + ')') - }) - - util.log( - 'Torrent info hash: ' + torrent.infoHash + ' ' + - '[Share link] ' + - '[Magnet URI] ' + - '[Download .torrent]' - ) - - function updateSpeed () { - var progress = (100 * torrent.progress).toFixed(1) - util.updateSpeed( - 'Peers: ' + torrent.swarm.wires.length + ' ' + - 'Progress: ' + progress + '% ' + - 'Download speed: ' + prettyBytes(window.client.downloadSpeed) + '/s ' + - 'Upload speed: ' + prettyBytes(window.client.uploadSpeed) + '/s' - ) - } - - torrent.on('download', throttle(updateSpeed, 250)) - torrent.on('upload', throttle(updateSpeed, 250)) - setInterval(updateSpeed, 5000) - updateSpeed() - - torrentPoster(torrent, function (err, buf) { - if (err) return util.error(err) - var img = document.createElement('img') - img.src = URL.createObjectURL(new Blob([ buf ], { type: 'image/png' })) - document.body.appendChild(img) - }) - - // TODO: play torrent when user clicks button - // torrent.files.forEach(function (file) { - // // append file - // file.appendTo(util.logElem, function (err, elem) { - // if (err) return util.error(err) - // }) - - // // append download link - // file.getBlobURL(function (err, url) { - // if (err) return util.error(err) - - // var a = document.createElement('a') - // a.target = '_blank' - // a.download = file.name - // a.href = url - // a.textContent = 'Download ' + file.name - // util.log(a) - // }) - // }) -} - -// function onBeforeUnload (e) { -// if (!e) e = window.event - -// if (!window.client || window.client.torrents.length === 0) return - -// var isLoneSeeder = window.client.torrents.some(function (torrent) { -// return torrent.swarm && torrent.swarm.numPeers === 0 && torrent.progress === 1 -// }) -// if (!isLoneSeeder) return - -// var names = listify(window.client.torrents.map(function (torrent) { -// return '"' + (torrent.name || torrent.infoHash) + '"' -// })) - -// var theseTorrents = window.client.torrents.length >= 2 -// ? 'these torrents' -// : 'this torrent' -// var message = 'You are the only person sharing ' + names + '. ' + -// 'Consider leaving this page open to continue sharing ' + theseTorrents + '.' - -// if (e) e.returnValue = message // IE, Firefox -// return message // Safari, Chrome -// } +setInterval(function () { + state.count += 1 + update() +}, 1000) diff --git a/client/views/app.js b/client/views/app.js new file mode 100644 index 00000000..484987bc --- /dev/null +++ b/client/views/app.js @@ -0,0 +1,16 @@ +module.exports = App + +var h = require('virtual-dom/h') + +function App (state) { + var count = state.count + return h('div', { + style: { + textAlign: 'center', + lineHeight: (100 + count) + 'px', + border: '1px solid red', + width: (100 + count) + 'px', + height: (100 + count) + 'px' + } + }, [ String(count) ]) +} diff --git a/client/webtorrent.js b/client/webtorrent.js new file mode 100644 index 00000000..5811b7a2 --- /dev/null +++ b/client/webtorrent.js @@ -0,0 +1,194 @@ +/* global URL, Blob */ + +var createTorrent = require('create-torrent') +var debug = require('debug')('instant.io') +var dragDrop = require('drag-drop') +var path = require('path') +var prettyBytes = require('pretty-bytes') +var throttle = require('throttleit') +var thunky = require('thunky') +var torrentPoster = require('./torrent-poster') +var uploadElement = require('upload-element') +var WebTorrent = require('webtorrent') +var xhr = require('xhr') + +var util = require('./util') + +global.WEBTORRENT_ANNOUNCE = createTorrent.announceList + .map(function (arr) { + return arr[0] + }) + .filter(function (url) { + return url.indexOf('wss://') === 0 || url.indexOf('ws://') === 0 + }) + +var getClient = thunky(function (cb) { + getRtcConfig('https://instant.io/rtcConfig', function (err, rtcConfig) { + if (err) util.error(err) + createClient(rtcConfig) + }) + + function createClient (rtcConfig) { + var client = window.client = new WebTorrent({ rtcConfig: rtcConfig }) + client.on('warning', util.warning) + client.on('error', util.error) + cb(null, client) + } +}) + +// For performance, create the client immediately +getClient(function () {}) + +// Seed via upload input element +var upload = document.querySelector('input[name=upload]') +uploadElement(upload, function (err, files) { + if (err) return util.error(err) + files = files.map(function (file) { return file.file }) + onFiles(files) +}) + +// Seed via drag-and-drop +dragDrop('body', onFiles) + +// Download via input element +document.querySelector('form').addEventListener('submit', function (e) { + e.preventDefault() + downloadTorrent(document.querySelector('form input[name=torrentId]').value.trim()) +}) + +// Download by URL hash +onHashChange() +window.addEventListener('hashchange', onHashChange) +function onHashChange () { + var hash = decodeURIComponent(window.location.hash.substring(1)).trim() + if (hash !== '') downloadTorrent(hash) +} + +// Register a protocol handler for "magnet:" (will prompt the user) +// navigator.registerProtocolHandler('magnet', window.location.origin + '#%s', 'Instant.io') + +function getRtcConfig (url, cb) { + xhr(url, function (err, res) { + if (err || res.statusCode !== 200) { + cb(new Error('Could not get WebRTC config from server. Using default (without TURN).')) + } else { + var rtcConfig + try { + rtcConfig = JSON.parse(res.body) + } catch (err) { + return cb(new Error('Got invalid WebRTC config from server: ' + res.body)) + } + debug('got rtc config: %o', rtcConfig) + cb(null, rtcConfig) + } + }) +} + +function onFiles (files) { + debug('got files:') + files.forEach(function (file) { + debug(' - %s (%s bytes)', file.name, file.size) + }) + + // .torrent file = start downloading the torrent + files.filter(isTorrentFile).forEach(downloadTorrentFile) + + // everything else = seed these files + seed(files.filter(isNotTorrentFile)) +} + +function isTorrentFile (file) { + var extname = path.extname(file.name).toLowerCase() + return extname === '.torrent' +} + +function isNotTorrentFile (file) { + return !isTorrentFile(file) +} + +function downloadTorrent (torrentId) { + util.log('Downloading torrent from ' + torrentId) + getClient(function (err, client) { + if (err) return util.error(err) + client.add(torrentId, onTorrent) + }) +} + +function downloadTorrentFile (file) { + util.log('Downloading torrent from ' + file.name + '') + getClient(function (err, client) { + if (err) return util.error(err) + client.add(file, onTorrent) + }) +} + +function seed (files) { + if (files.length === 0) return + util.log('Seeding ' + files.length + ' files') + + // Seed from WebTorrent + getClient(function (err, client) { + if (err) return util.error(err) + client.seed(files, onTorrent) + }) +} + +function onTorrent (torrent) { + upload.value = upload.defaultValue // reset upload element + + var torrentFileName = path.basename(torrent.name, path.extname(torrent.name)) + '.torrent' + + util.log('"' + torrentFileName + '" contains ' + torrent.files.length + ' files:') + torrent.files.forEach(function (file) { + util.log(' - ' + file.name + ' (' + prettyBytes(file.length) + ')') + }) + + util.log( + 'Torrent info hash: ' + torrent.infoHash + ' ' + + '[Share link] ' + + '[Magnet URI] ' + + '[Download .torrent]' + ) + + function updateSpeed () { + var progress = (100 * torrent.progress).toFixed(1) + util.updateSpeed( + 'Peers: ' + torrent.swarm.wires.length + ' ' + + 'Progress: ' + progress + '% ' + + 'Download speed: ' + prettyBytes(window.client.downloadSpeed) + '/s ' + + 'Upload speed: ' + prettyBytes(window.client.uploadSpeed) + '/s' + ) + } + + torrent.on('download', throttle(updateSpeed, 250)) + torrent.on('upload', throttle(updateSpeed, 250)) + setInterval(updateSpeed, 5000) + updateSpeed() + + torrentPoster(torrent, function (err, buf) { + if (err) return util.error(err) + var img = document.createElement('img') + img.src = URL.createObjectURL(new Blob([ buf ], { type: 'image/png' })) + document.body.appendChild(img) + }) + + // TODO: play torrent when user clicks button + // torrent.files.forEach(function (file) { + // // append file + // file.appendTo(util.logElem, function (err, elem) { + // if (err) return util.error(err) + // }) + + // // append download link + // file.getBlobURL(function (err, url) { + // if (err) return util.error(err) + + // var a = document.createElement('a') + // a.target = '_blank' + // a.download = file.name + // a.href = url + // a.textContent = 'Download ' + file.name + // util.log(a) + // }) + // }) +} diff --git a/index.html b/index.html index e44ff831..0befe45f 100644 --- a/index.html +++ b/index.html @@ -1,35 +1,35 @@ -
- -