stream#Duplex TypeScript Examples

The following examples show how to use stream#Duplex. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: http-proxy-server.ts    From shadowsocks-electron with GNU General Public License v3.0 6 votes vote down vote up
/**
    * connect [HTTP CONNECT method for https proxy]
    * @author nojsja
    * @param  {http.IncomingMessage} request [request]
    * @param  {Duplex} cSocket [cSocket]
    * @param  {Buffer} head [head]
    * @return {void}
    */
  private connect = (request: http.IncomingMessage, cSocket: Duplex, head: Buffer) => {
    const u = url.parse('http://' + request.url)
    console.log('connect: ', request.url);
    const { agentConf } = this;
    const options = {
      command: 'connect',
      proxy: agentConf,
      target: { host: u.hostname, port: u.port },
    };
    // connect tcp tunnel between https-client and socks5-client by proxy-server.
    // when tcp tunnel established, the tunnel let data-pack pass from https-client to target-server with socks5 proxy.
    // the entire process: https-client <--(tcp)--> sockets-client <--(tcp)--> sockets-server <--(tcp)--> https-server
    socks.createConnection(options, (error: Error | null, pSocket: Duplex) => {
      if (error) {
        cSocket.write(`HTTP/${request.httpVersion} 500 Connection error\r\n\r\n`);
        return;
      }
      pSocket.pipe(cSocket);
      cSocket.pipe(pSocket);
      pSocket.write(head);
      cSocket.write(`HTTP/${request.httpVersion} 200 Connection established\r\n\r\n`)
      pSocket.resume();
    });
  }
Example #2
Source File: stream.spec.ts    From kassette with MIT License 5 votes vote down vote up
describe('stream', () => {
  describe('fetchContent', () => {
    it('should handle stream-like objects', () => {
      class MyStream {
        private _onData: (chunk: Buffer) => {};
        private _onEnd: () => {};

        on(eventName: string, callback: any) {
          if (eventName === 'data') {
            this._onData = callback;
          } else if (eventName === 'end') {
            this._onEnd = callback;
          }
        }

        private _pushData(chunk: string) {
          this._onData(Buffer.from(chunk));
        }
        private _end() {
          this._onEnd();
        }

        start() {
          this._pushData('hel');
          this._pushData('lo');
          this._end();
        }
      }
      const stream = new MyStream();

      const promise = readAll(stream).then((result) => {
        expect(result.toString()).toEqual('hello');
      });

      stream.start();
      return promise;
    });

    it('should handle Node.js streams', () => {
      let content = '';
      const stream = new Duplex({
        read(size: number) {
          this.push(content.slice(0, size));
          content = content.slice(size);
          if (content === '') {
            this.push(null);
          }
        },

        write(chunk: any, _encoding: string, callback: Function) {
          content += chunk;
          callback();
        },
      });

      const promise = readAll(stream).then((result) => {
        expect(result.toString()).toEqual('hello');
      });

      stream.write('hel');
      stream.end('lo');
      return promise;
    });
  });
});
Example #3
Source File: index.ts    From discord-ytdl-core with Apache License 2.0 5 votes vote down vote up
arbitraryStream = (
    stream: string | Readable | Duplex,
    options?: StreamOptions
) => {
    if (!stream) {
        throw new Error('No stream source provided');
    }

    options ??= {};

    let FFmpegArgs: string[];
    if (typeof stream === 'string') {
        FFmpegArgs = [
            '-reconnect',
            '1',
            '-reconnect_streamed',
            '1',
            '-reconnect_delay_max',
            '5',
            '-i',
            stream,
            '-analyzeduration',
            '0',
            '-loglevel',
            '0',
            '-f',
            `${typeof options.fmt === 'string' ? options.fmt : 's16le'}`,
            '-ar',
            '48000',
            '-ac',
            '2',
        ];
    } else {
        FFmpegArgs = [
            '-analyzeduration',
            '0',
            '-loglevel',
            '0',
            '-f',
            `${typeof options.fmt === 'string' ? options.fmt : 's16le'}`,
            '-ar',
            '48000',
            '-ac',
            '2',
        ];
    }

    if (!isNaN(options.seek)) {
        FFmpegArgs.unshift('-ss', options.seek.toString());
    }

    if (Array.isArray(options.encoderArgs)) {
        FFmpegArgs = FFmpegArgs.concat(options.encoderArgs);
    }

    let transcoder = new FFmpeg({
        args: FFmpegArgs,
    });
    if (typeof stream !== 'string') {
        transcoder = stream.pipe(transcoder);
        stream.on('error', () => transcoder.destroy());
    }
    if (options && !options.opusEncoded) {
        transcoder.on('close', () => transcoder.destroy());
        return transcoder;
    }
    const opus = new Opus.Encoder({
        rate: 48000,
        channels: 2,
        frameSize: 960,
    });

    const outputStream = transcoder.pipe(opus);
    outputStream.on('close', () => {
        transcoder.destroy();
        opus.destroy();
    });
    return outputStream;
}
Example #4
Source File: context.ts    From flatend with MIT License 4 votes vote down vote up
export class Context extends Duplex {
  _provider: Provider;
  _stream: Stream;
  _headersWritten = false;
  _headers: { [key: string]: string } = {};

  headers: { [key: string]: string };

  get id(): ID {
    return this._provider.id!;
  }

  constructor(
    provider: Provider,
    stream: Stream,
    headers: { [key: string]: string }
  ) {
    super();

    this._provider = provider;
    this._stream = stream;
    this.headers = headers;

    // pipe stream body to context

    setImmediate(async () => {
      for await (const frame of this._stream.body) {
        this.push(frame);
      }
      this.push(null);
    });

    // write stream eof when stream writable is closed

    setImmediate(async () => {
      await util.promisify(finished)(this, { readable: false });

      await this._writeHeader();

      const payload = new DataPacket(this._stream.id, Buffer.of()).encode();
      await this._provider.write(
        this._provider.rpc.message(
          0,
          Buffer.concat([Buffer.of(Opcode.Data), payload])
        )
      );
    });
  }

  header(key: string, val: string): Context {
    this._headers[key] = val;
    return this;
  }

  send(data: string | Buffer | Uint8Array) {
    this.write(data);
    if (!this.writableEnded) this.end();
  }

  json(data: any) {
    this.header("content-type", "application/json");
    this.send(JSON.stringify(data));
  }

  _read(size: number) {
    this._stream.body._read(size);
  }

  async body(opts?: { limit?: number }): Promise<Buffer> {
    const limit = opts?.limit ?? 2 ** 16;

    let buf = Buffer.of();
    for await (const chunk of this) {
      buf = Buffer.concat([buf, chunk]);
      if (buf.byteLength > limit) {
        throw new Error(
          `Exceeded max allowed body size limit of ${limit} byte(s).`
        );
      }
    }

    return buf;
  }

  async _writeHeader() {
    if (!this._headersWritten) {
      this._headersWritten = true;

      const payload = new ServiceResponsePacket(
        this._stream.id,
        true,
        this._headers
      ).encode();
      await this._provider.write(
        this._provider.rpc.message(
          0,
          Buffer.concat([Buffer.of(Opcode.ServiceResponse), payload])
        )
      );
    }
  }

  _write(
    chunk: any,
    encoding: BufferEncoding,
    callback: (error?: Error | null) => void
  ) {
    const write = async () => {
      await this._writeHeader();

      const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding);

      for (const chunk of chunkBuffer(buf, STREAM_CHUNK_SIZE)) {
        const payload = new DataPacket(this._stream.id, chunk).encode();
        await this._provider.write(
          this._provider.rpc.message(
            0,
            Buffer.concat([Buffer.of(Opcode.Data), payload])
          )
        );
      }
    };

    write()
      .then(() => callback())
      .catch((error) => callback(error));
  }
}