Skip to content

Commit c99eb89

Browse files
authored
fix: drop buffer (#465)
1 parent 6864ef9 commit c99eb89

File tree

12 files changed

+85
-99
lines changed

12 files changed

+85
-99
lines changed

client.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import once from 'once'
44
import parallel from 'run-parallel'
55
import Peer from 'simple-peer'
66
import queueMicrotask from 'queue-microtask'
7+
import { hex2arr, hex2bin, text2arr, arr2hex, arr2text } from 'uint8-util'
78

89
import common from './lib/common.js'
910
import HTTPTracker from './lib/client/http-tracker.js' // empty object in browser
@@ -18,8 +19,8 @@ const debug = Debug('bittorrent-tracker:client')
1819
* Find torrent peers, to help a torrent client participate in a torrent swarm.
1920
*
2021
* @param {Object} opts options object
21-
* @param {string|Buffer} opts.infoHash torrent info hash
22-
* @param {string|Buffer} opts.peerId peer id
22+
* @param {string|Uint8Array} opts.infoHash torrent info hash
23+
* @param {string|Uint8Array} opts.peerId peer id
2324
* @param {string|Array.<string>} opts.announce announce
2425
* @param {number} opts.port torrent client listening port
2526
* @param {function} opts.getAnnounceOpts callback to provide data to tracker
@@ -39,15 +40,15 @@ class Client extends EventEmitter {
3940

4041
this.peerId = typeof opts.peerId === 'string'
4142
? opts.peerId
42-
: opts.peerId.toString('hex')
43-
this._peerIdBuffer = Buffer.from(this.peerId, 'hex')
44-
this._peerIdBinary = this._peerIdBuffer.toString('binary')
43+
: arr2hex(opts.peerId)
44+
this._peerIdBuffer = hex2arr(this.peerId)
45+
this._peerIdBinary = hex2bin(this.peerId)
4546

4647
this.infoHash = typeof opts.infoHash === 'string'
4748
? opts.infoHash.toLowerCase()
48-
: opts.infoHash.toString('hex')
49-
this._infoHashBuffer = Buffer.from(this.infoHash, 'hex')
50-
this._infoHashBinary = this._infoHashBuffer.toString('binary')
49+
: arr2hex(opts.infoHash)
50+
this._infoHashBuffer = hex2arr(this.infoHash)
51+
this._infoHashBinary = hex2bin(this.infoHash)
5152

5253
debug('new client %s', this.infoHash)
5354

@@ -69,7 +70,7 @@ class Client extends EventEmitter {
6970

7071
// Remove trailing slash from trackers to catch duplicates
7172
announce = announce.map(announceUrl => {
72-
announceUrl = announceUrl.toString()
73+
announceUrl = arr2text(announceUrl)
7374
if (announceUrl[announceUrl.length - 1] === '/') {
7475
announceUrl = announceUrl.substring(0, announceUrl.length - 1)
7576
}
@@ -260,7 +261,7 @@ Client.scrape = (opts, cb) => {
260261

261262
const clientOpts = Object.assign({}, opts, {
262263
infoHash: Array.isArray(opts.infoHash) ? opts.infoHash[0] : opts.infoHash,
263-
peerId: Buffer.from('01234567890123456789'), // dummy value
264+
peerId: text2arr('01234567890123456789'), // dummy value
264265
port: 6881 // dummy value
265266
})
266267

@@ -284,9 +285,6 @@ Client.scrape = (opts, cb) => {
284285
}
285286
})
286287

287-
opts.infoHash = Array.isArray(opts.infoHash)
288-
? opts.infoHash.map(infoHash => Buffer.from(infoHash, 'hex'))
289-
: Buffer.from(opts.infoHash, 'hex')
290288
client.scrape({ infoHash: opts.infoHash })
291289
return client
292290
}

lib/client/http-tracker.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import clone from 'clone'
44
import Debug from 'debug'
55
import get from 'simple-get'
66
import Socks from 'socks'
7+
import { bin2hex, hex2bin, arr2text } from 'uint8-util'
78

89
import common from '../common.js'
910
import Tracker from './tracker.js'
@@ -65,8 +66,8 @@ class HTTPTracker extends Tracker {
6566
}
6667

6768
const infoHashes = (Array.isArray(opts.infoHash) && opts.infoHash.length > 0)
68-
? opts.infoHash.map(infoHash => infoHash.toString('binary'))
69-
: (opts.infoHash && opts.infoHash.toString('binary')) || this.client._infoHashBinary
69+
? opts.infoHash.map(infoHash => hex2bin(infoHash))
70+
: (opts.infoHash && hex2bin(opts.infoHash)) || this.client._infoHashBinary
7071
const params = {
7172
info_hash: infoHashes
7273
}
@@ -159,13 +160,13 @@ class HTTPTracker extends Tracker {
159160
} catch (err) {
160161
return cb(new Error(`Error decoding tracker response: ${err.message}`))
161162
}
162-
const failure = data['failure reason'] && Buffer.from(data['failure reason']).toString()
163+
const failure = data['failure reason'] && arr2text(data['failure reason'])
163164
if (failure) {
164165
debug(`failure from ${requestUrl} (${failure})`)
165166
return cb(new Error(failure))
166167
}
167168

168-
const warning = data['warning message'] && Buffer.from(data['warning message']).toString()
169+
const warning = data['warning message'] && arr2text(data['warning message'])
169170
if (warning) {
170171
debug(`warning from ${requestUrl} (${warning})`)
171172
self.client.emit('warning', new Error(warning))
@@ -189,7 +190,7 @@ class HTTPTracker extends Tracker {
189190

190191
const response = Object.assign({}, data, {
191192
announce: this.announceUrl,
192-
infoHash: common.binaryToHex(data.info_hash)
193+
infoHash: bin2hex(data.info_hash || String(data.info_hash))
193194
})
194195
this.client.emit('update', response)
195196

@@ -248,7 +249,7 @@ class HTTPTracker extends Tracker {
248249
// (separate from announce interval)
249250
const response = Object.assign(data[infoHash], {
250251
announce: this.announceUrl,
251-
infoHash: common.binaryToHex(infoHash)
252+
infoHash: bin2hex(infoHash)
252253
})
253254
this.client.emit('scrape', response)
254255
})

lib/client/udp-tracker.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import arrayRemove from 'unordered-array-remove'
2-
import BN from 'bn.js'
32
import clone from 'clone'
43
import Debug from 'debug'
54
import dgram from 'dgram'
6-
import randombytes from 'randombytes'
75
import Socks from 'socks'
6+
import { concat, hex2arr, randomBytes } from 'uint8-util'
87

98
import common from '../common.js'
109
import Tracker from './tracker.js'
@@ -131,7 +130,7 @@ class UDPTracker extends Tracker {
131130
}, common.REQUEST_TIMEOUT)
132131
if (timeout.unref) timeout.unref()
133132

134-
send(Buffer.concat([
133+
send(concat([
135134
common.CONNECTION_ID,
136135
common.toUInt32(common.ACTIONS.CONNECT),
137136
transactionId
@@ -175,7 +174,8 @@ class UDPTracker extends Tracker {
175174

176175
function onSocketMessage (msg) {
177176
if (proxySocket) msg = msg.slice(10)
178-
if (msg.length < 8 || msg.readUInt32BE(4) !== transactionId.readUInt32BE(0)) {
177+
const view = new DataView(transactionId.buffer)
178+
if (msg.length < 8 || msg.readUInt32BE(4) !== view.getUint32(0)) {
179179
return onError(new Error('tracker sent invalid transaction id'))
180180
}
181181

@@ -270,14 +270,14 @@ class UDPTracker extends Tracker {
270270
function announce (connectionId, opts) {
271271
transactionId = genTransactionId()
272272

273-
send(Buffer.concat([
273+
send(concat([
274274
connectionId,
275275
common.toUInt32(common.ACTIONS.ANNOUNCE),
276276
transactionId,
277277
self.client._infoHashBuffer,
278278
self.client._peerIdBuffer,
279279
toUInt64(opts.downloaded),
280-
opts.left != null ? toUInt64(opts.left) : Buffer.from('FFFFFFFFFFFFFFFF', 'hex'),
280+
opts.left != null ? toUInt64(opts.left) : hex2arr('ffffffffffffffff'),
281281
toUInt64(opts.uploaded),
282282
common.toUInt32(common.EVENTS[opts.event] || 0),
283283
common.toUInt32(0), // ip address (optional)
@@ -291,10 +291,10 @@ class UDPTracker extends Tracker {
291291
transactionId = genTransactionId()
292292

293293
const infoHash = (Array.isArray(opts.infoHash) && opts.infoHash.length > 0)
294-
? Buffer.concat(opts.infoHash)
294+
? concat(opts.infoHash)
295295
: (opts.infoHash || self.client._infoHashBuffer)
296296

297-
send(Buffer.concat([
297+
send(concat([
298298
connectionId,
299299
common.toUInt32(common.ACTIONS.SCRAPE),
300300
transactionId,
@@ -307,26 +307,26 @@ class UDPTracker extends Tracker {
307307
UDPTracker.prototype.DEFAULT_ANNOUNCE_INTERVAL = 30 * 60 * 1000 // 30 minutes
308308

309309
function genTransactionId () {
310-
return randombytes(4)
310+
return randomBytes(4)
311311
}
312312

313313
function toUInt16 (n) {
314-
const buf = Buffer.allocUnsafe(2)
315-
buf.writeUInt16BE(n, 0)
314+
const buf = new Uint8Array(2)
315+
const view = new DataView(buf.buffer)
316+
view.setUint16(0, n)
316317
return buf
317318
}
318319

319320
const MAX_UINT = 4294967295
320321

321322
function toUInt64 (n) {
322323
if (n > MAX_UINT || typeof n === 'string') {
323-
const bytes = new BN(n).toArray()
324-
while (bytes.length < 8) {
325-
bytes.unshift(0)
326-
}
327-
return Buffer.from(bytes)
324+
const buf = new Uint8Array(8)
325+
const view = new DataView(buf.buffer)
326+
view.setBigUint64(0, n)
327+
return buf
328328
}
329-
return Buffer.concat([common.toUInt32(0), common.toUInt32(n)])
329+
return concat([new Uint8Array(4), common.toUInt32(n)])
330330
}
331331

332332
function noop () {}

lib/client/websocket-tracker.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import clone from 'clone'
22
import Debug from 'debug'
33
import Peer from 'simple-peer'
4-
import randombytes from 'randombytes'
54
import Socket from '@thaunknown/simple-websocket'
65
import Socks from 'socks'
6+
import { arr2text, arr2hex, hex2bin, bin2hex, randomBytes } from 'uint8-util'
77

8-
import common from '../common.js'
8+
import { DESTROY_TIMEOUT } from '../common.js'
99
import Tracker from './tracker.js'
1010

1111
const debug = Debug('bittorrent-tracker:websocket-tracker')
@@ -80,8 +80,8 @@ class WebSocketTracker extends Tracker {
8080
}
8181

8282
const infoHashes = (Array.isArray(opts.infoHash) && opts.infoHash.length > 0)
83-
? opts.infoHash.map(infoHash => infoHash.toString('binary'))
84-
: (opts.infoHash && opts.infoHash.toString('binary')) || this.client._infoHashBinary
83+
? opts.infoHash.map(infoHash => hex2bin(infoHash))
84+
: (opts.infoHash && hex2bin(opts.infoHash)) || this.client._infoHashBinary
8585
const params = {
8686
action: 'scrape',
8787
info_hash: infoHashes
@@ -138,7 +138,7 @@ class WebSocketTracker extends Tracker {
138138

139139
// Otherwise, wait a short time for potential responses to come in from the
140140
// server, then force close the socket.
141-
timeout = setTimeout(destroyCleanup, common.DESTROY_TIMEOUT)
141+
timeout = setTimeout(destroyCleanup, DESTROY_TIMEOUT)
142142

143143
// But, if a response comes from the server before the timeout fires, do cleanup
144144
// right away.
@@ -214,7 +214,7 @@ class WebSocketTracker extends Tracker {
214214
this.expectingResponse = false
215215

216216
try {
217-
data = JSON.parse(Buffer.from(data))
217+
data = JSON.parse(arr2text(data))
218218
} catch (err) {
219219
this.client.emit('warning', new Error('Invalid tracker response'))
220220
return
@@ -233,7 +233,7 @@ class WebSocketTracker extends Tracker {
233233
if (data.info_hash !== this.client._infoHashBinary) {
234234
debug(
235235
'ignoring websocket data from %s for %s (looking for %s: reused socket)',
236-
this.announceUrl, common.binaryToHex(data.info_hash), this.client.infoHash
236+
this.announceUrl, bin2hex(data.info_hash), this.client.infoHash
237237
)
238238
return
239239
}
@@ -266,7 +266,7 @@ class WebSocketTracker extends Tracker {
266266
if (data.complete != null) {
267267
const response = Object.assign({}, data, {
268268
announce: this.announceUrl,
269-
infoHash: common.binaryToHex(data.info_hash)
269+
infoHash: bin2hex(data.info_hash)
270270
})
271271
this.client.emit('update', response)
272272
}
@@ -275,7 +275,7 @@ class WebSocketTracker extends Tracker {
275275
if (data.offer && data.peer_id) {
276276
debug('creating peer (from remote offer)')
277277
peer = this._createPeer()
278-
peer.id = common.binaryToHex(data.peer_id)
278+
peer.id = bin2hex(data.peer_id)
279279
peer.once('signal', answer => {
280280
const params = {
281281
action: 'announce',
@@ -293,10 +293,10 @@ class WebSocketTracker extends Tracker {
293293
}
294294

295295
if (data.answer && data.peer_id) {
296-
const offerId = common.binaryToHex(data.offer_id)
296+
const offerId = bin2hex(data.offer_id)
297297
peer = this.peers[offerId]
298298
if (peer) {
299-
peer.id = common.binaryToHex(data.peer_id)
299+
peer.id = bin2hex(data.peer_id)
300300
this.client.emit('peer', peer)
301301
peer.signal(data.answer)
302302

@@ -323,7 +323,7 @@ class WebSocketTracker extends Tracker {
323323
// (separate from announce interval)
324324
const response = Object.assign(data[infoHash], {
325325
announce: this.announceUrl,
326-
infoHash: common.binaryToHex(infoHash)
326+
infoHash: bin2hex(infoHash)
327327
})
328328
this.client.emit('scrape', response)
329329
})
@@ -376,13 +376,13 @@ class WebSocketTracker extends Tracker {
376376
checkDone()
377377

378378
function generateOffer () {
379-
const offerId = randombytes(20).toString('hex')
379+
const offerId = arr2hex(randomBytes(20))
380380
debug('creating peer (from _generateOffers)')
381381
const peer = self.peers[offerId] = self._createPeer({ initiator: true })
382382
peer.once('signal', offer => {
383383
offers.push({
384384
offer,
385-
offer_id: common.hexToBinary(offerId)
385+
offer_id: hex2bin(offerId)
386386
})
387387
checkDone()
388388
})

lib/common-node.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
*/
55

66
import querystring from 'querystring'
7+
import { concat } from 'uint8-util'
78

89
export const IPV4_RE = /^[\d.]+$/
910
export const IPV6_RE = /^[\da-fA-F:]+$/
1011
export const REMOVE_IPV4_MAPPED_IPV6_RE = /^::ffff:/
1112

12-
export const CONNECTION_ID = Buffer.concat([toUInt32(0x417), toUInt32(0x27101980)])
13+
export const CONNECTION_ID = concat([toUInt32(0x417), toUInt32(0x27101980)])
1314
export const ACTIONS = { CONNECT: 0, ANNOUNCE: 1, SCRAPE: 2, ERROR: 3 }
1415
export const EVENTS = { update: 0, completed: 1, started: 2, stopped: 3, paused: 4 }
1516
export const EVENT_IDS = {
@@ -40,8 +41,9 @@ export const REQUEST_TIMEOUT = 15000
4041
export const DESTROY_TIMEOUT = 1000
4142

4243
export function toUInt32 (n) {
43-
const buf = Buffer.allocUnsafe(4)
44-
buf.writeUInt32BE(n, 0)
44+
const buf = new Uint8Array(4)
45+
const view = new DataView(buf.buffer)
46+
view.setUint32(0, n)
4547
return buf
4648
}
4749

lib/common.js

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,11 @@
22
* Functions/constants needed by both the client and server.
33
*/
44
import * as common from './common-node.js'
5+
export * from './common-node.js'
56

67
export const DEFAULT_ANNOUNCE_PEERS = 50
78
export const MAX_ANNOUNCE_PEERS = 82
89

9-
export const binaryToHex = str => {
10-
if (typeof str !== 'string') {
11-
str = String(str)
12-
}
13-
return Buffer.from(str, 'binary').toString('hex')
14-
}
15-
16-
export const hexToBinary = str => {
17-
if (typeof str !== 'string') {
18-
str = String(str)
19-
}
20-
return Buffer.from(str, 'hex').toString('binary')
21-
}
22-
2310
// HACK: Fix for WHATWG URL object not parsing non-standard URL schemes like
2411
// 'udp:'. Just replace it with 'http:' since we only need a few properties.
2512
//
@@ -49,8 +36,6 @@ export const parseUrl = str => {
4936
export default {
5037
DEFAULT_ANNOUNCE_PEERS,
5138
MAX_ANNOUNCE_PEERS,
52-
binaryToHex,
53-
hexToBinary,
5439
parseUrl,
5540
...common
5641
}

0 commit comments

Comments
 (0)