git ssb

5+

Matt McKegg / ferment



Tree: 7b78a80338b818ed7a5a94ed61ba8cbfe4c9fdd5

Files: 7b78a80338b818ed7a5a94ed61ba8cbfe4c9fdd5 / background-window.js

7984 bytesRaw
1var WebTorrent = require('webtorrent')
2var electron = require('electron')
3var parseTorrent = require('parse-torrent')
4var Path = require('path')
5var getExt = require('path').extname
6var fs = require('fs')
7var ipc = electron.ipcRenderer
8var watchEvent = require('./lib/watch-event')
9var rimraf = require('rimraf')
10var MutantDict = require('@mmckegg/mutant/dict')
11
12console.log = electron.remote.getGlobal('console').log
13process.exit = electron.remote.app.quit
14// redirect errors to stderr
15window.addEventListener('error', function (e) {
16 e.preventDefault()
17 console.error(e.error.stack || 'Uncaught ' + e.error)
18})
19
20module.exports = function (client, config) {
21 var announce = config.webtorrent.announceList
22 var torrentClient = new WebTorrent()
23 var mediaPath = config.mediaPath
24 var releases = {}
25 var prioritizeReleases = []
26 var paused = []
27 var torrentState = MutantDict()
28
29 setInterval(pollStats, 5000)
30
31 startSeeding()
32
33 torrentClient.on('torrent', function (torrent) {
34 var updating = false
35 var timer = null
36 torrent.on('download', update)
37 torrent.on('upload', update)
38 torrent.on('done', update)
39 torrent.on('noPeers', update)
40 torrent.on('ready', update)
41 torrent.on('wire', update)
42
43 update()
44
45 function update () {
46 if (!updating) {
47 updating = true
48 setTimeout(updateNow, 500)
49 }
50 }
51
52 function updateNow () {
53 clearTimeout(timer)
54 updating = false
55 var state = {
56 progress: torrent.progress,
57 downloadSpeed: torrent.downloadSpeed,
58 uploadSpeed: torrent.uploadSpeed,
59 numPeers: torrent.numPeers,
60 downloaded: torrent.downloaded,
61 uploaded: torrent.uploaded,
62 loading: false
63 }
64 broadcastTorrentState(torrent.infoHash, state)
65 timer = setTimeout(updateNow, 1000)
66 }
67 })
68
69 ipc.on('bg-release', function (ev, id) {
70 if (releases[id]) {
71 var release = releases[id]
72 releases[id] = null
73 release()
74 }
75 })
76
77 ipc.on('bg-stream-torrent', (ev, id, torrentId) => {
78 unprioritize(true, () => {
79 var torrent = torrentClient.get(torrentId)
80 if (torrent) {
81 streamTorrent(id, torrentId)
82 } else {
83 addTorrent(torrentId, () => {
84 streamTorrent(id, torrentId)
85 })
86 }
87 })
88
89 function streamTorrent (id, torrentId) {
90 var torrent = torrentClient.get(torrentId)
91 var server = torrent.createServer()
92 prioritize(torrentId)
93 server.listen(0, function (err) {
94 if (err) return ipc.send('bg-response', id, err)
95 var port = server.address().port
96 var url = 'http://localhost:' + port + '/0'
97 ipc.send('bg-response', id, null, url)
98 })
99 releases[id] = () => {
100 server.close()
101 }
102 }
103 })
104
105 ipc.on('bg-check-torrent', (ev, id, torrentId) => {
106 var torrent = torrentClient.get(torrentId)
107 if (torrent) {
108 ipc.send('bg-response', id, null)
109 } else {
110 addTorrent(torrentId, (err) => {
111 ipc.send('bg-response', id, err)
112 })
113 }
114 })
115
116 ipc.on('bg-get-all-torrent-state', (ev, id) => {
117 ipc.send('bg-response', id, torrentState())
118 })
119
120 ipc.on('bg-delete-torrent', (ev, id, torrentId) => {
121 var torrentInfo = parseTorrent(torrentId)
122 var torrent = torrentClient.get(torrentInfo.infoHash)
123 if (torrent) {
124 torrent.destroy()
125 }
126
127 fs.unlink(getTorrentPath(torrentInfo.infoHash), function () {
128 rimraf(getTorrentDataPath(torrentInfo.infoHash), function () {
129 console.log('Deleted torrent', torrentInfo.infoHash)
130 ipc.send('bg-response', id)
131 })
132 })
133 })
134
135 ipc.on('bg-seed-torrent', (ev, id, infoHash) => {
136 var torrent = torrentClient.get(infoHash)
137 if (torrent) {
138 ipc.send('bg-response', id, null, torrent.magnetURI)
139 } else {
140 fs.readFile(getTorrentPath(infoHash), function (err, buffer) {
141 if (err) return ipc.send('bg-response', id, err)
142 var torrent = parseTorrent(buffer)
143 torrent.announce = announce.slice()
144 torrentClient.add(torrent, {
145 path: getTorrentDataPath(infoHash)
146 }, function (torrent) {
147 ipc.send('bg-response', id, null, torrent.magnetURI)
148 })
149 })
150 }
151 })
152
153 ipc.send('ipcBackgroundReady', true)
154
155 // scoped
156
157 function broadcastTorrentState (infoHash, state) {
158 torrentState.put(infoHash, state)
159 ipc.send('bg-torrent-status', infoHash, state)
160 }
161
162 function pollStats () {
163 ipc.send('bg-global-torrent-status', {
164 progress: torrentClient.progress,
165 down: torrentClient.downloadSpeed,
166 up: torrentClient.uploadSpeed
167 })
168 }
169
170 function getTorrentPath (infoHash) {
171 return `${getTorrentDataPath(infoHash)}.torrent`
172 }
173
174 function getTorrentDataPath (infoHash) {
175 return Path.join(mediaPath, `${infoHash}`)
176 }
177
178 function addTorrent (torrentId, cb) {
179 var torrent = parseTorrent(torrentId)
180 var torrentPath = getTorrentPath(torrent.infoHash)
181 torrent.announce = announce.slice()
182
183 torrentClient.add(torrent, {
184 path: getTorrentDataPath(torrent.infoHash)
185 }, function (torrent) {
186 console.log('add torrent', torrent.infoHash)
187 fs.writeFile(torrentPath, torrent.torrentFile, cb)
188 })
189 }
190
191 function startSeeding () {
192 var i = 0
193 var items = []
194 fs.readdir(mediaPath, function (err, entries) {
195 if (err) throw err
196 entries.forEach((name) => {
197 if (getExt(name) === '.torrent') {
198 items.push(Path.join(mediaPath, name))
199 }
200 })
201
202 // make sure the same torrents aren't being seeded every time
203 shuffle(items)
204 next()
205 })
206
207 function next () {
208 // don't seed all of the torrents at once, roll out slowly to avoid cpu spike
209 var item = items[i]
210 setTimeout(function () {
211 fs.readFile(item, function (err, buffer) {
212 if (!err) {
213 var torrent = parseTorrent(buffer)
214 torrent.announce = announce.slice()
215 torrentClient.add(torrent, {
216 path: getTorrentDataPath(Path.basename(item, '.torrent'))
217 }, function (torrent) {
218 console.log('seeding', torrent.infoHash)
219 i += 1
220 if (i < items.length) next()
221 })
222 }
223 })
224 // wait 15 seconds before seeding next file
225 }, 15000)
226 }
227 }
228
229 function unprioritize (restart, cb) {
230 while (prioritizeReleases.length) {
231 prioritizeReleases.pop()()
232 }
233
234 if (paused.length && restart) {
235 var remaining = paused.length
236 console.log(`restarting ${paused.length} torrent(s)`)
237 while (paused.length) {
238 var torrentFile = paused.pop()
239 var torrent = parseTorrent(torrentFile)
240 torrentClient.add(torrent, { path: getTorrentDataPath(torrent.infoHash), announce }, (torrent) => {
241 remaining -= 1
242 if (remaining === 0) {
243 cb && cb()
244 }
245 })
246 }
247 } else {
248 cb && cb()
249 }
250 }
251
252 function prioritize (torrentId) {
253 var torrent = torrentClient.get(torrentId)
254 torrent.critical(0, Math.floor(torrent.pieces.length / 8))
255 if (torrent.progress < 0.5) {
256 torrentClient.torrents.forEach(function (t) {
257 if (t !== torrent && t.progress < 0.9) {
258 paused.push(t.torrentFile)
259 broadcastTorrentState(torrent.infoHash, {
260 paused: true
261 })
262 t.destroy()
263 }
264 })
265
266 console.log(`pausing ${paused.length} torrent(s)`)
267
268 prioritizeReleases.push(watchEvent(torrent, 'download', () => {
269 if (torrent.progress > 0.8) {
270 unprioritize(true)
271 }
272 }))
273 }
274 }
275}
276
277function shuffle (array) {
278 var currentIndex = array.length
279 while (currentIndex !== 0) {
280 var randomIndex = Math.floor(Math.random() * currentIndex)
281 currentIndex -= 1
282 var temporaryValue = array[currentIndex]
283 array[currentIndex] = array[randomIndex]
284 array[randomIndex] = temporaryValue
285 }
286 return array
287}
288

Built with git-ssb-web