Exemplo n.º 1
0
Table.prototype.createReadStream = function() {
  var that = this;

  var stream = streamEvents(through.obj());
  stream.once('reading', function() {
    that.getRows(handleResponse);
  });
  return stream;

  function handleResponse(err, rows, nextQuery) {
    if (err) {
      stream.emit('error', err);
      stream.end();
      return;
    }

    rows.forEach(function(row) {
      stream.push(row);
    });

    if (nextQuery) {
      that.getRows(nextQuery, handleResponse);
    } else {
      stream.end();
    }
  }
};
Exemplo n.º 2
0
/**
 * Limit requests according to a `maxApiCalls` limit.
 *
 * @param {function} makeRequestFn - The function that will be called.
 * @param {object=} options - Configuration object.
 * @param {number} options.maxApiCalls - The maximum number of API calls to
 *     make.
 * @param {object} options.streamOptions - Options to pass to the Stream
 *     constructor.
 */
function createLimiter(makeRequestFn, options) {
  options = options || {};

  const stream = streamEvents(through.obj(options.streamOptions));

  let requestsMade = 0;
  let requestsToMake = -1;

  if (is.number(options.maxApiCalls)) {
    requestsToMake = options.maxApiCalls;
  }

  return {
    makeRequest: function() {
      requestsMade++;

      if (requestsToMake >= 0 && requestsMade > requestsToMake) {
        stream.push(null);
        return;
      }

      makeRequestFn.apply(null, arguments);

      return stream;
    },

    stream: stream,
  };
}
Exemplo n.º 3
0
File.prototype.createWriteStream = function(metadata) {
  var that = this;
  var dup = streamEvents(duplexify());

  dup.once('writing', function() {
    util.makeWritableStream(dup, {
      makeAuthorizedRequest: that.bucket.storage.makeAuthorizedRequest_,
      metadata: metadata,
      request: {
        qs: {
          name: that.name
        },
        uri: util.format('{base}/{bucket}/o', {
          base: STORAGE_UPLOAD_BASE_URL,
          bucket: that.bucket.name
        })
      }
    }, function(data) {
      that.metadata = data;

      dup.emit('complete', data);
      dup.end();
    });
  });

  return dup;
};
Exemplo n.º 4
0
Table.prototype.createWriteStream = function(metadata) {
  var self = this;

  metadata = metadata || {};

  var fileTypes = Object.keys(FORMATS).map(function(key) {
    return FORMATS[key];
  });

  if (is.string(metadata)) {
    metadata = {
      sourceFormat: FORMATS[metadata.toLowerCase()]
    };
  }

  if (is.string(metadata.schema)) {
    metadata.schema = Table.createSchemaFromString_(metadata.schema);
  }

  extend(true, metadata, {
    destinationTable: {
      projectId: self.bigQuery.projectId,
      datasetId: self.dataset.id,
      tableId: self.id
    }
  });

  if (metadata.hasOwnProperty('sourceFormat') &&
      fileTypes.indexOf(metadata.sourceFormat) < 0) {
    throw new Error('Source format not recognized: ' + metadata.sourceFormat);
  }

  var dup = streamEvents(duplexify());

  dup.once('writing', function() {
    common.util.makeWritableStream(dup, {
      makeAuthenticatedRequest: self.bigQuery.makeAuthenticatedRequest,
      metadata: {
        configuration: {
          load: metadata
        }
      },
      request: {
        uri: format('{base}/{projectId}/jobs', {
          base: 'https://www.googleapis.com/upload/bigquery/v2/projects',
          projectId: self.bigQuery.projectId
        })
      }
    }, function(data) {
      var job = self.bigQuery.job(data.jobReference.jobId);
      job.metadata = data;

      dup.emit('complete', job);
    });
  });

  return dup;
};
Exemplo n.º 5
0
  methods.streamingRecognize = function(streamingConfig, options) {
    options = options || {};
    streamingConfig = streamingConfig || {};

    // Format the audio content as input request for pipeline
    const recognizeStream = streamEvents(pumpify.obj());

    const requestStream = this._innerApiCalls
      .streamingRecognize(options)
      .on('error', err => {
        recognizeStream.destroy(err);
      })
      .on('response', response => {
        recognizeStream.emit('response', response);
      });

    // Attach the events to the request stream, but only do so
    // when the first write (of data) comes in.
    //
    // This also means that the sending of the initial request (with the
    // config) is delayed until we get the first burst of data.
    recognizeStream.once('writing', () => {
      // The first message should contain the streaming config.
      requestStream.write({streamingConfig});

      // Set up appropriate piping between the stream returned by
      // the underlying API method and the one that we return.
      recognizeStream.setPipeline([
        // Format the user's input.
        // This entails that the user sends raw audio; it is wrapped in
        // the appropriate request structure.
        through.obj((audioContent, _, next) => {
          if (audioContent !== undefined) {
            next(null, {audioContent});
            return;
          }

          next();
        }),
        requestStream,
        through.obj((response, enc, next) => {
          if (response.error) {
            next(new common.util.ApiError(response.error));
            return;
          }

          next(null, response);
        }),
      ]);
    });

    return recognizeStream;
  };
Exemplo n.º 6
0
SessionPool.prototype.requestStream = function(config) {
  if (global.GCLOUD_SANDBOX_ENV) {
    return through.obj();
  }

  var self = this;

  var requestStream;
  var session;

  var waitForSessionStream = streamEvents(through.obj());
  waitForSessionStream.abort = function() {
    releaseSession();

    if (requestStream) {
      requestStream.cancel();
    }
  };

  function releaseSession() {
    if (session) {
      self.release(session);
      session = null;
    }
  }

  waitForSessionStream.on('reading', function() {
    self.getSession(function(err, session_) {
      if (err) {
        waitForSessionStream.destroy(err);
        return;
      }

      session = session_;

      config.reqOpts.session = session_.formattedName_;

      requestStream = config.method(config.reqOpts);

      requestStream
        .on('error', releaseSession)
        .on('error', function(err) {
          waitForSessionStream.destroy(err);
        })
        .on('end', releaseSession)
        .pipe(waitForSessionStream);
    });
  });

  return waitForSessionStream;
};
Exemplo n.º 7
0
Model.prototype.createWriteStream = function(label) {
  var self = this;
  var writeStream = streamEvents(pumpify());

  writeStream.once('writing', function() {
    var template = JSON.stringify({
      output: label,
      csvInstance: [[]]
    }).split('[]');

    var requestStream = self.request({
      method: 'PUT',
      uri: '',
      headers: {
        accept: 'application/json',
        'content-type': 'application/json'
      }
    });

    requestStream
      .on('response', function(resp) {
        writeStream.emit('response', resp);
      })
      .on('prefinish', function() {
        writeStream.cork();
      })
      .on('complete', function(resp) {
        util.handleResp(null, resp, resp.body, function(err) {
          if (err) {
            writeStream.destroy(err);
            return;
          }

          writeStream.uncork();
        });
      });

    writeStream.setPipeline([
      through({ encoding: 'utf-8' }),
      JSONStream.stringify(template[0], ',', template[1]),
      requestStream
    ]);
  });

  return writeStream;
};
Exemplo n.º 8
0
Speech.prototype.createRecognizeStream = function(config) {
  var self = this;

  var verboseMode = config.verbose === true;
  delete config.verbose;

  var gaxOptions = {};

  if (is.number(config.timeout)) {
    gaxOptions.timeout = config.timeout * 1000;
    delete config.timeout;
  }

  var recognizeStream = streamEvents(pumpify.obj());

  recognizeStream.once('writing', function() {
    var requestStream = self.api.Speech.streamingRecognize(gaxOptions);

    requestStream.on('response', function(response) {
      recognizeStream.emit('response', response);
    });

    requestStream.write({
      streamingConfig: config
    });

    this.setPipeline([
      // Format the user's input.
      through.obj(function(obj, _, next) {
        next(null, {
          audioContent: obj
        });
      }),

      requestStream,

      // Format the results.
      through.obj(function(obj, _, next) {
        obj.results = Speech.formatResults_(obj.results, verboseMode);
        next(null, obj);
      })
    ]);
  });

  return recognizeStream;
};
Exemplo n.º 9
0
BigQuery.prototype.query = function(options, callback) {
  var that = this;
  var stream;

  if (util.is(options, 'string')) {
    options = {
      query: options
    };
  }

  options = options || {};

  if (!util.is(callback, 'function')) {
    stream = streamEvents(through.obj());
    stream.once('reading', runQuery);
    return stream;
  } else {
    callback = callback || util.noop;
    runQuery();
  }

  function runQuery() {
    if (options.job) {
      that.makeReq_(
        'GET', '/queries/' + options.job.id, options, null, responseHandler);
    } else {
      // Create a job.
      that.makeReq_('POST', '/queries', null, options, responseHandler);
    }

    function responseHandler(err, resp) {
      if (err) {
        onComplete(err, null, null, resp);
        return;
      }

      var job = that.job(resp.jobReference.jobId);
      var nextQuery = null;
      var rows = Table.mergeSchemaWithRows_(resp.schema, resp.rows || []);

      if (resp.jobComplete === false) {
        // Query is still running.
        nextQuery = extend({
          job: job
        }, options);
      } else if (resp.pageToken) {
        // More results exist.
        nextQuery = extend({
          job: job
        }, options, {
          pageToken: resp.pageToken
        });
      }

      onComplete(null, rows, nextQuery, resp);
    }

    function onComplete(err, rows, nextQuery, resp) {
      if (err) {
        if (stream) {
          stream.emit('error', err);
          stream.end();
        } else {
          callback(err, null, null, resp);
        }
        return;
      }

      if (stream) {
        rows.forEach(function(row) {
          stream.push(row);
        });

        if (nextQuery) {
          that.query(nextQuery, onComplete);
        } else {
          stream.end();
        }
      } else {
        callback(null, rows, nextQuery, resp);
      }
    }
  }
};
Exemplo n.º 10
0
File.prototype.createWriteStream = function(options) {
  options = options || {};

  var self = this;

  var gzip = options.gzip;

  var metadata = options.metadata || {};
  if (gzip) {
    metadata.contentEncoding = 'gzip';
  }

  var crc32c = options.validation !== false;
  var md5 = options.validation !== false;

  if (is.string(options.validation)) {
    options.validation = options.validation.toLowerCase();
    crc32c = options.validation === 'crc32c';
    md5 = options.validation === 'md5';
  }

  // Collect data as it comes in to store in a hash. This is compared to the
  // checksum value on the returned metadata from the API.
  var validateStream = hashStreamValidation({
    crc32c: crc32c,
    md5: md5
  });

  var fileWriteStream = duplexify();

  var stream = streamEvents(pumpify([
    gzip ? zlib.createGzip() : through(),
    validateStream,
    fileWriteStream
  ]));

  // Wait until we've received data to determine what upload technique to use.
  stream.on('writing', function() {
    if (options.resumable === false) {
      self.startSimpleUpload_(fileWriteStream, metadata);
    } else {
      self.startResumableUpload_(fileWriteStream, metadata);
    }
  });

  fileWriteStream.on('response', stream.emit.bind(stream, 'response'));

  // This is to preserve the `finish` event. We wait until the request stream
  // emits "complete", as that is when we do validation of the data. After that
  // is successful, we can allow the stream to naturally finish.
  //
  // Reference for tracking when we can use a non-hack solution:
  // https://github.com/nodejs/node/pull/2314
  fileWriteStream.on('prefinish', function() {
    stream.cork();
  });

  // Compare our hashed version vs the completed upload's version.
  fileWriteStream.on('complete', function() {
    var metadata = self.metadata;

    // If we're doing validation, assume the worst-- a data integrity mismatch.
    // If not, these tests won't be performed, and we can assume the best.
    var failed = crc32c || md5;

    if (crc32c && metadata.crc32c) {
      // We must remove the first four bytes from the returned checksum.
      // http://stackoverflow.com/questions/25096737/
      //   base64-encoding-of-crc32c-long-value
      failed = !validateStream.test('crc32c', metadata.crc32c.substr(4));
    }

    if (md5 && metadata.md5Hash) {
      failed = !validateStream.test('md5', metadata.md5Hash);
    }

    if (failed) {
      self.delete(function(err) {
        var code;
        var message;

        if (err) {
          code = 'FILE_NO_UPLOAD_DELETE';
          message = [
            'The uploaded data did not match the data from the server. As a',
            'precaution, we attempted to delete the file, but it was not',
            'successful. To be sure the content is the same, you should try',
            'removing the file manually, then uploading the file again.',
            '\n\nThe delete attempt failed with this message:',
            '\n\n  ' + err.message
          ].join(' ');
        } else {
          code = 'FILE_NO_UPLOAD';
          message = [
            'The uploaded data did not match the data from the server. As a',
            'precaution, the file has been deleted. To be sure the content',
            'is the same, you should try uploading the file again.'
          ].join(' ');
        }

        var error = new Error(message);
        error.code = code;
        error.errors = [err];

        fileWriteStream.destroy(error);
      });

      return;
    }

    stream.uncork();
  });

  return stream;
};
Exemplo n.º 11
0
File.prototype.createReadStream = function(options) {
  options = options || {};

  var self = this;
  var rangeRequest = is.number(options.start) || is.number(options.end);
  var tailRequest = options.end < 0;
  var throughStream = streamEvents(through());

  var crc32c = options.validation !== false;
  var md5 = options.validation !== false;

  if (is.string(options.validation)) {
    options.validation = options.validation.toLowerCase();
    crc32c = options.validation === 'crc32c';
    md5 = options.validation === 'md5';
  }

  if (rangeRequest) {
    if (is.string(options.validation) || options.validation === true) {
      throw new Error('Cannot use validation with file ranges (start/end).');
    }
    // Range requests can't receive data integrity checks.
    crc32c = false;
    md5 = false;
  }

  // Authenticate the request, then pipe the remote API request to the stream
  // returned to the user.
  function makeRequest() {
    var reqOpts = {
      uri: format('{downloadBaseUrl}/{bucketName}/{fileName}', {
        downloadBaseUrl: STORAGE_DOWNLOAD_BASE_URL,
        bucketName: self.bucket.name,
        fileName: encodeURIComponent(self.name)
      }),
      gzip: true
    };

    if (self.generation) {
      reqOpts.qs = {
        generation: self.generation
      };
    }

    if (rangeRequest) {
      var start = is.number(options.start) ? options.start : '0';
      var end = is.number(options.end) ? options.end : '';

      reqOpts.headers = {
        Range: 'bytes=' + (tailRequest ? end : start + '-' + end)
      };
    }

    var requestStream = self.storage.makeAuthenticatedRequest(reqOpts);
    var validateStream;

    // We listen to the response event from the request stream so that we can...
    //
    //   1) Intercept any data from going to the user if an error occurred.
    //   2) Calculate the hashes from the http.IncomingMessage response stream,
    //      which will return the bytes from the source without decompressing
    //      gzip'd content. The request stream will do the decompression so the
    //      user receives the expected content.
    function onResponse(err, body, res) {
      if (err) {
        requestStream.unpipe(throughStream);
        return;
      }

      if (!rangeRequest) {
        validateStream = hashStreamValidation({
          crc32c: crc32c,
          md5: md5
        });

        res.pipe(validateStream).on('data', util.noop);
      }
    }

    // This is hooked to the `complete` event from the request stream. This is
    // our chance to validate the data and let the user know if anything went
    // wrong.
    function onComplete(err, body, res) {
      if (err) {
        throughStream.destroy(err);
        return;
      }

      if (rangeRequest) {
        return;
      }

      var hashes = {};
      res.headers['x-goog-hash'].split(',').forEach(function(hash) {
        var hashType = hash.split('=')[0].trim();
        hashes[hashType] = hash.substr(hash.indexOf('=') + 1);
      });

      // If we're doing validation, assume the worst-- a data integrity
      // mismatch. If not, these tests won't be performed, and we can assume the
      // best.
      var failed = crc32c || md5;

      if (crc32c && hashes.crc32c) {
        // We must remove the first four bytes from the returned checksum.
        // http://stackoverflow.com/questions/25096737/
        //   base64-encoding-of-crc32c-long-value
        failed = !validateStream.test('crc32c', hashes.crc32c.substr(4));
      }

      if (md5 && hashes.md5) {
        failed = !validateStream.test('md5', hashes.md5);
      }

      if (failed) {
        var mismatchError = new Error([
          'The downloaded data did not match the data from the server.',
          'To be sure the content is the same, you should download the',
          'file again.'
        ].join(' '));
        mismatchError.code = 'CONTENT_DOWNLOAD_MISMATCH';

        throughStream.destroy(mismatchError);
      }
    }

    requestStream
      .on('error', function(err) {
        throughStream.destroy(err);
      })
      .on('response', function(res) {
        throughStream.emit('response', res);
        util.handleResp(null, res, null, onResponse);
      })
      .on('complete', function(res) {
        util.handleResp(null, res, null, onComplete);
      })
      .pipe(throughStream)
      .on('error', function() {
        // An error can occur before the request stream has been created (during
        // authentication).
        if (requestStream.abort) {
          requestStream.abort();
        }

        requestStream.destroy();
      });
  }

  throughStream.on('reading', makeRequest);

  return throughStream;
};
Exemplo n.º 12
0
Table.prototype.createWriteStream = function(metadata) {
  var that = this;

  metadata = metadata || {};

  var fileTypeMap = {
    csv: 'CSV',
    json: 'NEWLINE_DELIMITED_JSON'
  };
  var fileTypes = Object.keys(fileTypeMap).map(function(key) {
    return fileTypeMap[key];
  });

  if (util.is(metadata, 'string')) {
    metadata = {
      sourceFormat: fileTypeMap[metadata.toLowerCase()]
    };
  }

  if (util.is(metadata.schema, 'string')) {
    metadata.schema = Table.createSchemaFromString_(metadata.schema);
  }

  extend(true, metadata, {
    destinationTable: {
      projectId: that.bigQuery.projectId,
      datasetId: that.dataset.id,
      tableId: that.id
    }
  });

  if (metadata.hasOwnProperty('sourceFormat') &&
      fileTypes.indexOf(metadata.sourceFormat) < 0) {
    throw new Error('Source format not recognized: ' + metadata.sourceFormat);
  }

  var dup = streamEvents(duplexify());

  dup.once('writing', function() {
    util.makeWritableStream(dup, {
      makeAuthorizedRequest: that.bigQuery.makeAuthorizedRequest_,
      metadata: {
        configuration: {
          load: metadata
        }
      },
      request: {
        uri: util.format('{base}/{projectId}/jobs', {
          base: 'https://www.googleapis.com/upload/bigquery/v2/projects',
          projectId: that.bigQuery.projectId
        })
      }
    }, function(data) {
      var job = that.bigQuery.job(data.jobReference.jobId);
      job.metadata = data;

      dup.emit('complete', job);
      dup.end();
    });
  });

  return dup;
};
Exemplo n.º 13
0
File.prototype.createReadStream = function(options) {
  options = options || {};

  var that = this;
  var rangeRequest =
    util.is(options.start, 'number') || util.is(options.end, 'number');
  var throughStream = streamEvents(through());

  var validations = ['crc32c', 'md5'];
  var validation;

  if (util.is(options.validation, 'string')) {
    options.validation = options.validation.toLowerCase();

    if (validations.indexOf(options.validation) > -1) {
      validation = options.validation;
    } else {
      validation = 'all';
    }
  }

  if (util.is(options.validation, 'undefined')) {
    validation = 'all';
  }

  if (rangeRequest) {
    validation = false;
  }

  var crc32c = validation === 'crc32c' || validation === 'all';
  var md5 = validation === 'md5' || validation === 'all';

  if (this.metadata.mediaLink) {
    createAuthorizedReq(this.metadata.mediaLink);
  } else {
    this.getMetadata(function(err, metadata) {
      if (err) {
        done(err);
        return;
      }

      createAuthorizedReq(metadata.mediaLink);
    });
  }

  return throughStream;

  // Authenticate the request, then pipe the remote API request to the stream
  // returned to the user.
  function createAuthorizedReq(uri) {
    var reqOpts = {
      uri: uri
    };

    if (rangeRequest) {
      var start = util.is(options.start, 'number') ? options.start : '0';
      var end = util.is(options.end, 'number') ? options.end : '';
      reqOpts.headers = {
        Range: 'bytes=' + start + '-' + end
      };
    }

    that.bucket.storage.makeAuthorizedRequest_(reqOpts, {
      onAuthorized: function(err, authorizedReqOpts) {
        if (err) {
          done(err);
          return;
        }

        // For data integrity, hash the contents of the stream as we receive it
        // from the server.
        var localCrcHash;
        var localMd5Hash = crypto.createHash('md5');

        request(authorizedReqOpts)
          .on('error', done)

          .on('data', function(chunk) {
            if (crc32c) {
              localCrcHash = crc.calculate(chunk, localCrcHash);
            }

            if (md5) {
              localMd5Hash.update(chunk);
            }
          })

          .on('complete', function(res) {
            util.handleResp(null, res, res.body, function(err) {
              if (err) {
                done(err);
                return;
              }

              if (rangeRequest) {
                // Range requests can't receive data integrity checks.
                done(null, res);
                return;
              }

              var failed = false;
              var crcFail = true;
              var md5Fail = true;

              var hashes = {};
              res.headers['x-goog-hash'].split(',').forEach(function(hash) {
                var hashType = hash.split('=')[0];
                hashes[hashType] = hash.substr(hash.indexOf('=') + 1);
              });

              var remoteMd5 = hashes.md5;
              var remoteCrc = hashes.crc32c && hashes.crc32c.substr(4);

              if (crc32c) {
                crcFail =
                  new Buffer([localCrcHash]).toString('base64') !== remoteCrc;
                failed = crcFail;
              }

              if (md5) {
                md5Fail = localMd5Hash.digest('base64') !== remoteMd5;
                failed = md5Fail;
              }

              if (validation === 'all') {
                failed = remoteMd5 ? md5Fail : crcFail;
              }

              if (failed) {
                var mismatchError = new Error([
                  'The downloaded data did not match the data from the server.',
                  'To be sure the content is the same, you should download the',
                  'file again.'
                ].join(' '));
                mismatchError.code = 'CONTENT_DOWNLOAD_MISMATCH';

                done(mismatchError);
              } else {
                done(null, res);
              }
            });
          })

          .pipe(throughStream);
      }
    });
  }

  // End the stream, first emitting an error or complete event.
  function done(err, response) {
    if (err) {
      throughStream.emit('error', err);
    } else {
      throughStream.emit('complete', response);
    }

    throughStream.end();
  }
};
Exemplo n.º 14
0
/**
 * Rows returned from queries may be chunked, requiring them to be stitched
 * together. This function returns a stream that will properly assemble these
 * rows, as well as retry after an error. Rows are only emitted if they hit a
 * "checkpoint", which is when a `resumeToken` is returned from the API. Without
 * that token, it's unsafe for the query to be retried, as we wouldn't want to
 * emit the same data multiple times.
 *
 * @private
 *
 * @param {function} requestFn - The function that makes an API request. It will
 *     receive one argument, `resumeToken`, which should be used however is
 *     necessary to send to the API for additional requests.
 */
function partialResultStream(requestFn) {
  var lastResumeToken;
  var activeRequestStream;

  // mergeStream allows multiple streams to be connected into one. This is good
  // if we need to retry a request and pipe more data to the user's stream.
  var requestsStream = mergeStream();
  eventsIntercept.patch(requestsStream);

  function makeRequest() {
    activeRequestStream = requestFn(lastResumeToken);
    requestsStream.add(activeRequestStream);
  }

  var batchAndSplitOnTokenStream = checkpointStream.obj({
    maxQueued: 10,
    isCheckpointFn: function(row) {
      return is.defined(row.resumeToken);
    }
  });

  var rowChunks = [];

  var userStream = streamEvents(through.obj(function(row, _, next) {
    var formattedRows = [];

    if (row.chunkedValue) {
      rowChunks.push(row);
      next();
      return;
    }

    if (is.empty(row.values)) {
      next();
      return;
    }

    if (rowChunks.length > 0) {
      // Done getting all the chunks. Put them together.
      formattedRows.push(new RowBuilder(rowChunks.concat(row)).toJSON());
    } else {
      var formattedRow = partialResultStream.formatRow_(row);
      var multipleRows = is.array(formattedRow[0]);

      if (multipleRows) {
        formattedRows = formattedRows.concat(formattedRow);
      } else {
        formattedRows.push(formattedRow);
      }
    }

    rowChunks = [];

    split(formattedRows, userStream, function() {
      next();
    });
  }));

  userStream.abort = function() {
    if (activeRequestStream) {
      activeRequestStream.abort();
    }
  };

  userStream.once('reading', makeRequest);

  return requestsStream
    .intercept('error', function(err) {
      if (lastResumeToken) {
        // We're going to retry from where we left off.
        // Empty queued rows on the checkpoint stream (will not emit them to
        // user).
        batchAndSplitOnTokenStream.reset();
        makeRequest();
        return;
      }

      setImmediate(function() {
        // We won't retry the request, so this will flush any rows the
        // checkpoint stream has queued. After that, we will destroy the user's
        // stream with the same error.
        batchAndSplitOnTokenStream.destroy(err);
      });
    })
    .pipe(batchAndSplitOnTokenStream)
    .on('error', function(err) {
      // If we get this error, the checkpoint stream has flushed any rows it had
      // queued. We can now destroy the user's stream, as our retry attempts are
      // over.
      userStream.destroy(err);
    })
    .on('checkpoint', function(row) {
      lastResumeToken = row.resumeToken;
    })
    .pipe(userStream);
}
Exemplo n.º 15
0
DatastoreRequest.prototype.runQuery = function(q, callback) {
  var that = this;
  var stream;
  var resultsToSend = q.limitVal;

  var req = {
    read_options: {},
    query: entity.queryToQueryProto(q)
  };

  if (q.namespace) {
    req.partition_id = {
      namespace: q.namespace
    };
  }

  if (!util.is(callback, 'function')) {
    stream = streamEvents(through.obj());
    stream.once('reading', runQuery);
    return stream;
  } else {
    runQuery();
  }

  function runQuery() {
    that.makeReq_('runQuery', req, function(err, resp) {
      if (err) {
        if (stream) {
          stream.emit('error', err);
          stream.end();
        } else {
          callback(err);
        }
        return;
      }

      var entities = entity.formatArray(resp.batch.entity_result);

      var cursor = '';
      if (resp.batch.end_cursor) {
        cursor = resp.batch.end_cursor.toBase64();
      }

      if (!stream) {
        callback(null, entities, cursor);
        return;
      }

      if (!cursor || entities.length === 0) {
        stream.end();
        return;
      }

      var result;
      while ((result = entities.shift()) && resultsToSend !== 0) {
        stream.push(result);
        resultsToSend--;
      }

      if (resultsToSend === 0) {
        stream.end();
        return;
      }

      req.query = entity.queryToQueryProto(q.start(cursor).offset(0));
      runQuery();
    });
  }
};
Exemplo n.º 16
0
Speech.prototype.createRecognizeStream = function(config) {
  var self = this;

  if (!config) {
    throw new Error('A recognize request requires a configuration object.');
  }

  config = extend(true, {
    config: {}
  }, config);

  // As of Speech v1, a language code is required; throw an exception if we did
  // not receive one.
  if (config.languageCode) {
    config.config.languageCode = config.languageCode;
    delete config.languageCode;
  }

  if (!config.config.languageCode) {
    throw new Error('A `languageCode` is required in the config object.');
  }

  var verboseMode = config.verbose === true;
  delete config.verbose;

  var gaxOptions = {};

  if (is.number(config.timeout)) {
    gaxOptions.timeout = config.timeout * 1000;
    delete config.timeout;
  }

  var recognizeStream = streamEvents(pumpify.obj());

  recognizeStream.once('writing', function() {
    var requestStream = self.api.Speech.streamingRecognize(gaxOptions);

    requestStream.on('error', function(err) {
      recognizeStream.destroy(err);
    });

    requestStream.on('response', function(response) {
      recognizeStream.emit('response', response);
    });

    requestStream.write({
      streamingConfig: config
    });

    this.setPipeline([
      // Format the user's input.
      through.obj(function(obj, _, next) {
        next(null, {
          audioContent: obj
        });
      }),

      requestStream,

      // Format the results.
      through.obj(function(obj, _, next) {
        obj.results = Speech.formatResults_(obj.results, verboseMode);
        next(null, obj);
      })
    ]);
  });

  return recognizeStream;
};
Exemplo n.º 17
0
File.prototype.createWriteStream = function(options) {
  options = options || {};

  var that = this;
  var metadata = options.metadata || {};
  var validations = ['crc32c', 'md5'];
  var validation;

  if (util.is(options.validation, 'string')) {
    options.validation = options.validation.toLowerCase();

    if (validations.indexOf(options.validation) > -1) {
      validation = options.validation;
    } else {
      validation = 'all';
    }
  }

  if (util.is(options.validation, 'undefined')) {
    validation = 'all';
  }

  var crc32c = validation === 'crc32c' || validation === 'all';
  var md5 = validation === 'md5' || validation === 'all';

  // Collect data as it comes in to store in a hash. This is compared to the
  // checksum value on the returned metadata from the API.
  var localCrc32cHash;
  var localMd5Hash = crypto.createHash('md5');

  var dup = streamEvents(duplexify());

  var throughStream = through(function(chunk, enc, next) {
    if (crc32c) {
      localCrc32cHash = crc.calculate(chunk, localCrc32cHash);
    }

    if (md5) {
      localMd5Hash.update(chunk);
    }

    this.push(chunk);
    next();
  });

  throughStream
    .on('end', function() {
      if (crc32c) {
        localCrc32cHash = new Buffer([localCrc32cHash]).toString('base64');
      }

      if (md5) {
        localMd5Hash = localMd5Hash.digest('base64');
      }
    })

    .pipe(dup)

    // Wait until we've received data to determine what upload technique to use.
    .once('writing', function() {
      if (util.is(options.resumable, 'boolean') && !options.resumable) {
        that.startSimpleUpload_(dup, metadata);
      } else {
        that.startResumableUpload_(dup, metadata);
      }
    })

    // Catch any errors from the writable stream and patch them upstream.
    .on('error', function(err) {
      throughStream.emit('error', err);
      throughStream.end();
    })

    // Compare our hashed version vs the completed upload's version.
    .on('complete', function(metadata) {
      var failed = false;

      // We must remove the first four bytes from the returned checksum.
      // http://stackoverflow.com/questions/25096737/
      //   base64-encoding-of-crc32c-long-value

      if (validation === 'all') {
        if (metadata.md5Hash) {
          failed = localMd5Hash !== metadata.md5Hash;
        } else if (metadata.crc32c) {
          failed = localCrc32cHash !== metadata.crc32c.substr(4);
        }
      } else if (md5) {
        failed = localMd5Hash !== metadata.md5Hash;
      } else if (crc32c) {
        failed = localCrc32cHash !== metadata.crc32c.substr(4);
      }

      if (failed) {
        that.delete(function(err) {
          var code;
          var message;

          if (err) {
            code = 'FILE_NO_UPLOAD_DELETE';
            message = [
              'The uploaded data did not match the data from the server. As a',
              'precaution, we attempted to delete the file, but it was not',
              'successful. To be sure the content is the same, you should try',
              'removing the file manually, then uploading the file again.',
              '\n\nThe delete attempt failed with this message:',
              '\n\n  ' + err.message
            ].join(' ');
          } else {
            code = 'FILE_NO_UPLOAD';
            message = [
              'The uploaded data did not match the data from the server. As a',
              'precaution, the file has been deleted. To be sure the content',
              'is the same, you should try uploading the file again.'
            ].join(' ');
          }

          var error = new Error(message);
          error.code = code;
          error.errors = [err];

          throughStream.emit('error', error);
        });
      } else {
        throughStream.emit('complete', metadata);
      }

      throughStream.end();
    });

  return throughStream;
};