Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"grpc": "^0.14.1",
"is": "^3.0.1",
"methmeth": "^1.0.0",
"modelo": "^4.2.0",
"request": "^2.70.0",
"retry-request": "^1.3.0",
"split-array-stream": "^1.0.0",
Expand Down
192 changes: 192 additions & 0 deletions packages/common/src/grpc-operation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*!
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*!
* @module common/grpcOperation
*/

'use strict';

var events = require('events');
var modelo = require('modelo');

/**
* @type {module:common/grpcService}
* @private
*/
var GrpcService = require('./grpc-service.js');

/**
* @type {module:common/grpcServiceObject}
* @private
*/
var GrpcServiceObject = require('./grpc-service-object.js');

// jscs:disable maximumLineLength
/**
* An Operation object allows you to interact with APIs that take longer to
* process things.
*
* @constructor
* @alias module:common/grpcOperation
*
* @param {module:common/grpcService|module:common/grpcServiceObject} parent - The
* parent object. This should be configured to use the longrunning.operation
* service.
* @param {string} name - The operation name.
*/
// jscs:enable maximumLineLength
function GrpcOperation(parent, name) {
var methods = {

/**
* Deletes an operation.
*/
delete: {
protoOpts: {
service: 'Operations',
method: 'deleteOperation'
},
reqOpts: {
name: name
}
},

/**
* Checks to see if an operation exists.
*/
exists: true,

/**
* Retrieves the operation.
*/
get: true,

/**
* Retrieves metadata for the operation.
*/
getMetadata: {
protoOpts: {
service: 'Operations',
method: 'getOperation'
},
reqOpts: {
name: name
}
}
};

var config = {
parent: parent,
id: name,
methods: methods
};

GrpcServiceObject.call(this, config);
events.EventEmitter.call(this);

this.completeListeners = 0;
this.hasActiveListeners = false;

this.listenForEvents_();
}

modelo.inherits(GrpcOperation, GrpcServiceObject, events.EventEmitter);

/**
* Cancel the operation.
*
* @param {function=} callback - The callback function.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

* @param {?error} callback.err - An error returned while making this
* request.
* @param {object} callback.apiResponse - The full API response.
*/
GrpcOperation.prototype.cancel = function(callback) {
var protoOpts = {
service: 'Operations',
method: 'cancelOperation'
};

var reqOpts = {
name: this.id
};

this.request(protoOpts, reqOpts, callback);
};

/**
* Begin listening for events on the operation. This method keeps track of how
* many "complete" listeners are registered and removed, making sure polling is
* handled automatically.
*
* As long as there is one active "complete" listener, the connection is open.
* When there are no more listeners, the polling stops.
*
* @private
*/
GrpcOperation.prototype.listenForEvents_ = function() {
var self = this;

this.on('newListener', function(event) {
if (event === 'complete') {
self.completeListeners++;

if (!self.hasActiveListeners) {
self.hasActiveListeners = true;
self.startPolling_();
}
}
});

this.on('removeListener', function(event) {
if (event === 'complete' && --self.completeListeners === 0) {
self.hasActiveListeners = false;
}
});
};

/**
* Poll `getMetadata` to check the operation's status. This runs a loop to ping
* the API on an interval.
*
* Note: This method is automatically called once a "complete" event handler is
* registered on the operation.
*
* @private
*/
GrpcOperation.prototype.startPolling_ = function() {
var self = this;

if (!this.hasActiveListeners) {
return;
}

this.getMetadata(function(err, resp) {
if (err || resp.error) {
self.emit('error', err || GrpcService.decorateStatus_(resp.result));
return;
}

if (!resp.done) {
setTimeout(self.startPolling_.bind(self), 500);
return;
}

self.emit('complete', resp);
});
};

module.exports = GrpcOperation;
6 changes: 6 additions & 0 deletions packages/common/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
* limitations under the License.
*/

/**
* @type {module:common/grpcOperation}
* @private
*/
exports.GrpcOperation = require('./grpc-operation.js');

/**
* @type {module:common/grpcService}
* @private
Expand Down
Loading