bittorrent-protocol
Simple, robust, BitTorrent wire protocol implementation
Node.js implementation of the BitTorrent peer wire protocol.
The protocol is the main communication layer for BitTorrent file transfer.
Also works in the browser with browserify! This module is used
by WebTorrent.
install
npm install bittorrent-protocol
usage
The protocol is implemented as a duplex stream, so all you have to do is pipe to and
from it.
duplex streams | a.pipe(b).pipe(a) |
---|
| |
(Images from the "harnessing streams" talk by substack.)
const Protocol = require('bittorrent-protocol')
const net = require('net')
net.createServer(socket => {
const wire = new Protocol()
socket.pipe(wire).pipe(socket)
wire.on('handshake', (infoHash, peerId) => {
wire.handshake('my info hash (hex)', 'my peer id (hex)')
})
wire.on('unchoke', () => {
console.log('peer is no longer choking us: ' + wire.peerChoking)
})
}).listen(6881)
methods
handshaking
Send and receive a handshake from the peer. This is the first message.
wire.handshake(infoHash, peerId, { dht: true })
wire.on('handshake', (infoHash, peerId, extensions) => {
console.log(extensions.dht)
console.log(extensions.extended)
})
For wire.handshake()
, the infoHash
and the peerId
should be 20 bytes (hex-encoded string
or Buffer
).
choking
Check if you or the peer is choking.
wire.peerChoking
wire.amChoking
wire.on('choke', () => {
})
wire.on('unchoke', () => {
})
interested
See if you or the peer is interested.
wire.peerInterested
wire.amInterested
wire.on('interested', () => {
})
wire.on('uninterested', () => {
})
bitfield
Exchange piece information with the peer.
wire.bitfield(buffer)
wire.on('bitfield', bitfield => {
})
wire.have(pieceIndex)
wire.on('have', pieceIndex => {
})
You can always see which pieces the peer has
wire.peerPieces.get(i)
wire.peerPieces
is a BitField
, see docs.
requests
Send and respond to requests for pieces.
wire.request(pieceIndex, offset, length, (err, block) => {
if (err) {
return
}
})
wire.cancel(pieceIndex, offset, length)
wire.on('request', (pieceIndex, offset, length, callback) => {
callback(null, block)
})
wire.requests
wire.peerRequests
You can set a request timeout if you want to.
wire.setTimeout(5000)
If the timeout is triggered the request callback is called with an error and a timeout
event is emitted.
dht and port
You can set the extensions flag dht
in the handshake to true
if you participate in
the torrent dht. Afterwards you can send your dht port.
wire.port(dhtPort)
wire.on('port', dhtPort => {
})
You can check to see if the peer supports extensions.
wire.peerExtensions.dht
wire.peerExtensions.extended
keep-alive
You can enable the keep-alive ping (triggered every 60s).
wire.setKeepAlive(true)
wire.on('keep-alive', () => {
})
fast extension (BEP 6)
This module has built-in support for the
BitTorrent Fast Extension (BEP 6).
The Fast Extension introduces several messages to make the protocol more efficient:
have-none, have-all, suggest, reject, and allowed-fast.
wire.handshake(infoHash, peerId, { fast: true })
wire.hasFast
wire.haveNone()
wire.on('have-none', () => {
})
wire.haveAll()
wire.on('have-all', () => {
})
wire.suggest(pieceIndex)
wire.on('suggest', (pieceIndex) => {
})
wire.on('allowed-fast', (pieceIndex) => {
})
wire.peerAllowedFastSet
wire.reject(pieceIndex, offset, length)
wire.on('reject', (pieceIndex, offset, length) => {
})
extension protocol (BEP 10)
This module has built-in support for the
BitTorrent Extension Protocol (BEP 10).
The intention of BEP 10 is to provide a simple and thin transport for extensions to the
bittorrent protocol. Most extensions to the protocol use BEP 10 so they can add new
features to the protocol without interfering with the standard bittorrent protocol or
clients that don't support the new extension.
An example of a BitTorrent extension that uses BEP 10 is
ut_metadata (BEP 9), the extension that
allows magnet uris to work.
wire.extended(code, buffer)
This package, bittorrent-protocol, also provides an extension API to make it easy to
add extensions to this module using the "extension protocol" (BEP 10). For example, to
support ut_metadata (BEP 9), you need only install the
ut_metadata npm module and call wire.use()
.
See the Extension API section for more information.
transfer stats
Check how many bytes you have uploaded and download, and current speed
wire.uploaded
wire.downloaded
wire.uploadSpeed()
wire.downloadSpeed()
wire.on('download', numberOfBytes => {
...
})
wire.on('upload', numberOfBytes => {
...
})
extension api
This package supports a simple extension API so you can extend the default protocol
functionality with common protocol extensions like ut_metadata (magnet uris).
Here are the bittorrent-protocol extensions that we know about:
- ut_metadata - Extension for Peers to Send Metadata Files (BEP 9)
- ut_pex - Extension for Peer Discovery (PEX)
- Add yours here! Send a pull request!
In short, an extension can register itself with at a certain name, which will be added to
the extended protocol handshake sent to the remote peer. Extensions can also hook events
like 'handshake' and 'extended'. To use an extension, simply require it and call
wire.use()
.
Here is an example of the ut_metadata extension being used with
bittorrent-protocol:
const Protocol = require('bittorrent-protocol')
const net = require('net')
const ut_metadata = require('ut_metadata')
net.createServer(socket => {
const wire = new Protocol()
socket.pipe(wire).pipe(socket)
wire.use(ut_metadata())
wire.ut_metadata.fetch()
wire.ut_metadata.on('metadata', metadata => {
})
wire.ut_metadata.on('warning', err => {
console.log(err.message)
})
wire.on('handshake', (infoHash, peerId) => {
wire.handshake(new Buffer('my info hash'), new Buffer('my peer id'))
})
}).listen(6881)
If you want to write your own extension, take a look at the
ut_metadata index.js file
to see how it's done.
license
MIT. Copyright (c) Feross Aboukhadijeh, Mathias Buus, and WebTorrent, LLC.