UNPKG

@substrate-system/bittorrent-protocol

Version:

Simple, robust, BitTorrent peer wire protocol implementation

331 lines 13.1 kB
import BitField from '@substrate-system/bitfield'; import { Duplex, type DuplexEvents, type StreamEvents } from 'streamx'; declare class HaveAllBitField { buffer: Uint8Array; constructor(); get(_index?: number): boolean; set(_index?: number): void; } export type ProtocolEvents = StreamEvents & { 'upload': (data: any) => void; 'new-item': (item: string) => void; 'item-updated': (item: string, newValue: number) => void; 'finish': (item: any) => void; 'piping': (data: any) => any; 'handshake': (data: any) => any; 'unchoke': () => any; 'have-all': () => void; 'end': () => void; }; export interface Ext { onHandshake?(infoHash: string, peerId: string, extensions: { [name: string]: boolean; }): void; onExtendedHandshake?(handshake: { [key: string]: any; }): void; onMessage?(buf: Uint8Array): void; name: string; } export declare class Wire extends Duplex<any> { _debugId: string; peerId: null | string; peerIdBuffer: null | Uint8Array; readonly type: 'webrtc' | 'tcpIncoming' | 'tcpOutgoing' | 'webSeed' | null; peerChoking: boolean; peerInterested: boolean; readonly requests: any[]; readonly peerRequests: any[]; readonly extendedMapping: Record<number, string>; readonly peerExtendedMapping: Record<string, number>; amChoking: boolean; amInterested: boolean; _dh: any | null; _myPubKey: null | string; _setGenerators: boolean; _decryptGenerator: any; _encryptGenerator: any; _encryptMethod: any; _peerPubKey: any; _sharedSecret: string | null; _cryptoHandshakeDone: boolean; _peerCryptoProvide: any; peerPieces: InstanceType<typeof BitField> | InstanceType<typeof HaveAllBitField>; extensions: Partial<Record<'extended' | 'dht' | 'fast', boolean>>; peerExtensions: Record<string, any>; peerExtendedHandshake: any; extendedHandshake: {}; hasFast: boolean; allowedFastSet: any; peerAllowedFastSet: any; _ext: Record<string, Ext>; _nextExt: number; uploaded: number; downloaded: number; uploadSpeed: (delta: number) => number; downloadSpeed: (delta: number) => number; _keepAliveInterval: any; _timeout: any; _timeoutMs: any; _timeoutUnref?: boolean; _timeoutExpiresAt: any; _finished: boolean; _parserSize: number; _parser: ((buf: Uint8Array) => void) | null | undefined; _buffer: any; _bufferSize: number; _peEnabled: boolean; _waitMaxBytes: number | null; _cryptoSyncPattern: any; _encryptionMethod: null | 1 | 2; _infoHash?: Uint8Array; _handshakeSent?: boolean; _extendedHandshakeSent?: boolean; constructor(type: 'webrtc' | 'tcpIncoming' | 'tcpOutgoing' | 'webSeed' | null, retries?: number, peEnabled?: boolean); /** * Factory function b/c async. * * @returns { Wire } A new Wire instance. */ static create(type?: null, retries?: number, peEnabled?: boolean): Promise<Wire>; once(event: 'bitfield', listener: (bitfield: any) => void): this; once(event: ('keep-alive' | 'choke' | 'unchoke' | 'interested' | 'uninterested' | 'timeout' | 'have-all' | 'have-none' | 'end' | 'close' | 'finish' | 'pe1' | 'pe2' | 'pe3' | 'pe4'), listener: () => void): this; once(event: 'error', listener: (err: Error) => void): this; once(event: 'suggest', listener: (index: number) => void): this; once(event: 'piece', listener: (index: number, offset: number, buffer: Buffer) => void): this; once(event: 'cancel', listener: (index: number, offset: number, length: number) => void): this; once(event: 'extended', listener: (ext: 'handshake' | string, buf: any) => void): void; once(event: 'unknownmessage', listener: (buffer: Buffer) => void): this; once(event: 'handshake', listener: (infoHash: string, peerId: string, extensions: { extended: boolean; fast: boolean; }) => void): this; on(event: 'suggest', listener: (index: number) => void): this; on(event: 'bitfield', listener: (bitfield: any) => void): this; on(event: ('keep-alive' | 'choke' | 'unchoke' | 'interested' | 'uninterested' | 'timeout' | 'have-all' | 'have-none'), listener: () => void): this; on(event: 'upload' | 'have' | 'download' | 'port', listener: (length: number) => void): this; on(event: 'handshake', listener: (infoHash: string, peerId: string, extensions: { extended: boolean; fast: boolean; }) => void): this; on(event: 'request', listener: (index: number, offset: number, length: number, respond: (err: Error | null, data?: any) => void) => void): this; on(event: 'piece', listener: (index: number, offset: number, buffer: Buffer) => void): this; on(event: 'cancel', listener: (index: number, offset: number, length: number) => void): this; on(event: 'extended', listener: (ext: 'handshake' | string, buf: any) => void): void; on(event: 'unknownmessage', listener: (buffer: Buffer) => void): this; on(event: string, listener: (...args: any[]) => void): this; emit<K extends keyof ProtocolEvents>(evName: K & 'readable', ...rest: any[]): boolean; removeListener<TEvent extends keyof StreamEvents | 'piping' | 'readable' | 'data' | 'end' | 'pipe' | 'finish' | 'drain'>(event: TEvent, listener: TEvent extends keyof StreamEvents | 'piping' | 'readable' | 'data' | 'end' | 'pipe' | 'finish' | 'drain' ? DuplexEvents<any, any>[TEvent] : (...args: any[]) => void): this; /** * Set whether to send a "keep-alive" ping (sent every 55s) * @param {boolean} enable */ setKeepAlive(enable: boolean): void; /** * Set the amount of time to wait before considering a request to be "timed out" * @param {number} ms * @param {boolean=} unref (should the timer be unref'd? default: false) */ setTimeout(ms: number, unref?: boolean): void; destroy(): this | undefined; end(data?: any): void; /** * Use the specified protocol extension. * * @param {function} Extension */ use(Extension: any): void; /** * Message "keep-alive": <len=0000> */ keepAlive(): void; sendPe1(): void; sendPe2(): void; sendPe3(infoHash: string): Promise<void>; sendPe4(infoHash: string): Promise<void>; /** * Message: "handshake" <pstrlen><pstr><reserved><info_hash><peer_id> * * @param {Uint8Array|string} infoHash (as Buffer or *hex* string) * @param {Uint8Array|string} peerId * @param {Object} extensions */ handshake(infoHash: Uint8Array | string, peerId: Uint8Array | string, extensions?: any): void; _sendExtendedHandshake(): void; /** * Message "choke": <len=0001><id=0> */ choke(): void; /** * Message "unchoke": <len=0001><id=1> */ unchoke(): void; /** * Message "interested": <len=0001><id=2> */ interested(): void; /** * Message "uninterested": <len=0001><id=3> */ uninterested(): void; /** * Message "have": <len=0005><id=4><piece index> * @param {number} index */ have(index: number): void; /** * Message "bitfield": <len=0001+X><id=5><bitfield> * @param {BitField|Buffer} bitfield */ bitfield(bitfield: any): void; /** * Message "request": <len=0013><id=6><index><begin><length> * @param {number} index * @param {number} offset * @param {number} length * @param {function} cb */ request(index: any, offset: any, length: any, cb: any): any; /** * Message "piece": <len=0009+X><id=7><index><begin><block> * @param {number} index * @param {number} offset * @param {Uint8Array} buffer */ piece(index: number, offset: number, buffer: Uint8Array): void; /** * Message "cancel": <len=0013><id=8><index><begin><length> * @param {number} index * @param {number} offset * @param {number} length */ cancel(index: any, offset: any, length: any): void; /** * Message: "port" <len=0003><id=9><listen-port> * @param {Number} port */ port(port: any): void; /** * Message: "suggest" <len=0x0005><id=0x0D><piece index> (BEP6) * @param {number} index */ suggest(index: any): void; /** * Message: "have-all" <len=0x0001><id=0x0E> (BEP6) */ haveAll(): void; /** * Message: "have-none" <len=0x0001><id=0x0F> (BEP6) */ haveNone(): void; /** * Message "reject": <len=0x000D><id=0x10><index><offset><length> (BEP6) * @param {number} index * @param {number} offset * @param {number} length */ reject(index: any, offset: any, length: any): void; /** * Message: "allowed-fast" <len=0x0005><id=0x11><piece index> (BEP6) * @param {number} index */ allowedFast(index: any): void; /** * Message: "extended" <len=0005+X><id=20><ext-number><payload> * @param {number|string} ext * @param {Object} obj */ extended(ext: number | string, obj: Uint8Array | object): void; /** * Sets the encryption method for this wire, as per PSE/ME specification * * @param {string} sharedSecret: A hex-encoded string, which is the shared secret agreed * upon from DH key exchange * @param {string} infoHash: A hex-encoded info hash * @returns boolean, true if encryption setting succeeds, false if it fails. */ setEncrypt(sharedSecret: any, infoHash: any): Promise<boolean>; /** * Send a message to the remote peer. */ _message(id: any, numbers: any, data: any): void; _push(data: any): boolean | undefined; _onKeepAlive(): void; _onPe1(pubKeyBuffer: any): void; _onPe2(pubKeyBuffer: any): void; _onPe3(hashesXorBuffer: Uint8Array): Promise<void>; _onPe3Encrypted(vcBuffer: any, peerProvideBuffer: any): void; _onPe4(peerSelectBuffer: Uint8Array): void; _onHandshake(infoHashBuffer: any, peerIdBuffer: any, extensions: any): void; _onChoke(): void; _onUnchoke(): void; _onInterested(): void; _onUninterested(): void; _onHave(index: any): void; _onBitField(buffer: any): void; _onRequest(index: number, offset: number, length: number): void; _onPiece(index: any, offset: any, buffer: any): void; _onCancel(index: any, offset: any, length: any): void; _onPort(port: any): void; _onSuggest(index: any): void; _onHaveAll(): void; _onHaveNone(): void; _onReject(index: any, offset: any, length: any): void; _onAllowedFast(index: number): void; _onExtended(ext: number | string, buf: Uint8Array): void; _onTimeout(): void; /** * Duplex stream method. Called whenever the remote peer has data for us. Data that the * remote peer sends gets buffered (i.e. not actually processed) until the right number * of bytes have arrived, determined by the last call to `this._parse(number, callback)`. * Once enough bytes have arrived to process the message, the callback function * (i.e. `this._parser`) gets called with the full buffer of data. * @param {Uint8Array} data * @param {(null):void} cb Signal that we're ready for more data */ _write(data: Uint8Array, cb: any): void; _callback(request: any, err: any, buffer: any): void; _resetTimeout(setAgain: any): void; /** * Takes a number of bytes that the local peer is waiting to receive from * the remote peer. * In order to parse a complete message, add a callback function to be * called once enough bytes have arrived. * @param {number} size * @param {function} parser */ _parse(size: number, parser?: (buf: Uint8Array) => void): void; _parseUntil(pattern: any, maxBytes: any): void; /** * Handle the first 4 bytes of a message, to determine the length of bytes * that must be waited for in order to have the whole message. * @param {Uint8Array} buffer */ _onMessageLength(buffer: Uint8Array): void; /** * Handle a message from the remote peer. * @param {Uint8Array} buffer */ _onMessage(buffer: Uint8Array): void; _determineHandshakeType(): void; _parsePe1(pubKeyPrefix: any): void; _parsePe2(): void; _parsePe3(): Promise<void>; _parsePe3Encrypted(): void; _parsePe4(): void; /** * Reads the handshake as specified by the bittorrent wire protocol. */ _parseHandshake(): void; _onHandshakeBuffer(handshake: any): void; _onFinish(): void; _debug(...args: any[]): void; _pull(requests: any, piece: any, offset: any, length: any): any; _encryptHandshake(buf: any): Uint8Array<any>; _encrypt(buf: Uint8Array): Uint8Array<ArrayBuffer>; _decryptHandshake(buf: Uint8Array): Uint8Array<ArrayBuffer>; _decrypt(buf: Uint8Array): Uint8Array<ArrayBuffer>; _utfToHex(str: string): string; } export default Wire; //# sourceMappingURL=index.d.ts.map