Merge "js/core: On npm failures clean the npm cache and try again."
diff --git a/src/rpc/server-router.js b/src/rpc/server-router.js
index 511e8e1..f893fa6 100644
--- a/src/rpc/server-router.js
+++ b/src/rpc/server-router.js
@@ -297,10 +297,72 @@
};
/**
+ * Handles the processing for reserved methods. If this request is not
+ * a reserved method call, this method does nothing.
+ *
+ * @private
+ * @param {module:vanadium.context.Context} ctx The context of the request
+ * @param {number} messageId The flow id
+ * @param {module:vanadium.rpc~Server} server The server instance that is
+ * handling the request.
+ * @param {Invoker} invoker The invoker for this request
+ * @param {string} methodName The name of the method.
+ * @param {object} request The request
+ * @returns Promise A promise that will be resolved when the method is
+ * dispatched or null if this is not a reserved method
+ */
+Router.prototype._maybeHandleReservedMethod = function(
+ ctx, messageId, server, invoker, methodName, request) {
+ var self = this;
+ function globCompletion() {
+ // There are no results to a glob method. Everything is sent back
+ // through the stream.
+ self.sendResult(messageId, methodName, null, undefined, 1);
+ }
+
+ if (request.method === 'Glob__') {
+ if (!invoker.hasGlobber()) {
+ var err = new Error('Glob is not implemented');
+ this.sendResult(messageId, 'Glob__', null, err);
+ return;
+ }
+
+ this._setupStream(messageId, ctx, globSig);
+ this._outstandingRequestForId[messageId] = 0;
+ this.incrementOutstandingRequestForId(messageId);
+ var globPattern = typeUtil.unwrap(request.args[0]);
+ return createServerCall(request, this._blessingsManager)
+ .then(function(call) {
+ self.handleGlobRequest(messageId, call.securityCall.suffix,
+ server, new Glob(globPattern), ctx, call, invoker,
+ globCompletion);
+ });
+ }
+ return null;
+};
+
+Router.prototype._unwrapArgs = function(args, methodSig) {
+ var self = this;
+ // Unwrap the RPC arguments sent to the JS server.
+ var unwrappedArgPromises = args.map(function(arg, i) {
+ // If an any type was expected, unwrapping is not needed.
+ if (methodSig.inArgs[i].type.kind === vdl.kind.ANY) {
+ return Promise.resolve(arg);
+ }
+ var unwrapped = typeUtil.unwrap(arg);
+ if (unwrapped instanceof BlessingsId) {
+ return self._blessingsManager.blessingsFromId(unwrapped);
+ }
+ return Promise.resolve(unwrapped);
+ });
+ return Promise.all(unwrappedArgPromises);
+};
+
+/**
* Performs the rpc request. Unlike handleRPCRequest, this function works on
* the decoded message.
* @private
- * @param {string} messageId Message Id set by the server.
+ * @param {number} messageId Message Id set by the server.
* @param {Object} request Request's structure is
* {
* serverId: number // the server id
@@ -310,7 +372,6 @@
* }
*/
Router.prototype._handleRPCRequestInternal = function(messageId, request) {
- // TODO(bjornick): Break this method up into smaller methods.
var methodName = capitalize(request.method);
var server = this._servers[request.serverId];
var err;
@@ -331,31 +392,15 @@
}
var ctx = this.createRPCContext(request);
+
+ var reservedPromise = this._maybeHandleReservedMethod(
+ ctx, messageId, server, invoker, methodName, request);
+
+ if (reservedPromise) {
+ return;
+ }
+
var self = this;
- function completion() {
- // There are no results to a glob method. Everything is sent back
- // through the stream.
- self.sendResult(messageId, methodName, null, undefined, 1);
- }
-
- if (request.method === 'Glob__') {
- if (!invoker.hasGlobber()) {
- err = new Error('Glob is not implemented');
- self.sendResult(messageId, 'Glob__', null, err);
- return;
- }
-
- this._setupStream(messageId, ctx, globSig);
- this._outstandingRequestForId[messageId] = 0;
- this.incrementOutstandingRequestForId(messageId);
- var globPattern = typeUtil.unwrap(request.args[0]);
- return createServerCall(request, this._blessingsManager)
- .then(function(call) {
- self.handleGlobRequest(messageId, call.securityCall.suffix,
- server, new Glob(globPattern), ctx, call, invoker,
- completion);
- });
- }
var methodSig = getMethodSignature(invoker, methodName);
if (methodSig === undefined) {
@@ -366,63 +411,48 @@
}
this._setupStream(messageId, ctx, methodSig);
+ var args;
+ this._unwrapArgs(request.args, methodSig).then(function(unwrapped) {
+ args = unwrapped;
+ return createServerCall(request, self._blessingsManager);
+ }).then(function(call) {
+ var options = {
+ methodName: methodName,
+ args: args,
+ methodSig: methodSig,
+ ctx: ctx,
+ call: call,
+ stream: self._streamMap[messageId],
+ };
- return createServerCall(request, this._blessingsManager).then(function(call) {
- // Unwrap the RPC arguments sent to the JS server.
- var unwrappedArgPromises = request.args.map(function(arg, i) {
- // If an any type was expected, unwrapping is not needed.
- if (methodSig.inArgs[i].type.kind === vdl.kind.ANY) {
- return Promise.resolve(arg);
- }
- var unwrapped = typeUtil.unwrap(arg);
- if (unwrapped instanceof BlessingsId) {
- return self._blessingsManager.blessingsFromId(unwrapped);
- }
- return Promise.resolve(unwrapped);
- });
-
- return Promise.all(unwrappedArgPromises).then(function(unwrappedArgs) {
- var options = {
- methodName: methodName,
- args: unwrappedArgs,
- methodSig: methodSig,
- ctx: ctx,
- call: call,
- stream: self._streamMap[messageId],
- };
-
- // Invoke the method;
- self.invokeMethod(invoker, options, function(err, results) {
- if (err) {
- var stackTrace;
- if (err instanceof Error && err.stack !== undefined) {
- stackTrace = err.stack;
+ // Invoke the method;
+ self.invokeMethod(invoker, options).then(function(results) {
+ // Has results; associate the types of the outArgs.
+ var canonResults = results.map(function(result, i) {
+ var t = methodSig.outArgs[i].type;
+ if (t.equals(WireBlessings.prototype._type)) {
+ if (!(result instanceof Blessings)) {
+ vlog.logger.error(
+ 'Encoding non-blessings value as wire blessings');
+ return null;
}
- vlog.logger.debug('Requested method ' + methodName +
- ' threw an exception on invoke: ', err, stackTrace);
-
- // The error case has no results; only send the error.
- self.sendResult(messageId, methodName, undefined, err,
- methodSig.outArgs.length);
- return;
+ return result;
}
-
- // Has results; associate the types of the outArgs.
- var canonResults = results.map(function(result, i) {
- var t = methodSig.outArgs[i].type;
- if (t.equals(WireBlessings.prototype._type)) {
- if (!(result instanceof Blessings)) {
- vlog.logger.error(
- 'Encoding non-blessings value as wire blessings');
- return null;
- }
- return result;
- }
- return vdl.canonicalize.fill(result, t);
- });
- self.sendResult(messageId, methodName, canonResults, undefined,
- methodSig.outArgs.length);
+ return vdl.canonicalize.fill(result, t);
});
+ self.sendResult(messageId, methodName, canonResults, undefined,
+ methodSig.outArgs.length);
+ }, function(err) {
+ var stackTrace;
+ if (err instanceof Error && err.stack !== undefined) {
+ stackTrace = err.stack;
+ }
+ vlog.logger.debug('Requested method ' + methodName +
+ ' threw an exception on invoke: ', err, stackTrace);
+
+ // The error case has no results; only send the error.
+ self.sendResult(messageId, methodName, undefined, err,
+ methodSig.outArgs.length);
});
});
};
@@ -467,7 +497,7 @@
/**
* Invokes a method with a methodSig
*/
-Router.prototype.invokeMethod = function(invoker, options, cb) {
+Router.prototype.invokeMethod = function(invoker, options) {
var methodName = options.methodName;
var args = options.args;
var ctx = options.ctx;
@@ -480,15 +510,20 @@
};
var rootCtx = this._rootCtx;
+ var def = new Deferred();
function InvocationFinishedCallback(err, results) {
// Note: We use the rootCtx here because we want to make this
// call to clean up the blessings even if the method invocation
// is cancelled.
call.securityCall.remoteBlessings.release(rootCtx);
- cb(err, results);
+ if (err) {
+ return def.reject(err);
+ }
+ def.resolve(results);
}
invoker.invoke(methodName, args, injections, InvocationFinishedCallback);
+ return def.promise;
};
function createGlobReply(name) {
@@ -510,6 +545,19 @@
context, call, invoker, cb) {
var self = this;
var options;
+
+ function invokeAndCleanup(invoker, options, method) {
+ self.invokeMethod(invoker, options).catch(function(err) {
+ var verr = new verror.InternalError(context,
+ method +'() failed', glob, err);
+ var errReply = createGlobErrorReply(name, verr, self._appName);
+ self._streamMap[messageId].write(errReply);
+ vlog.logger.info(verr);
+ }).then(function() {
+ // Always decrement the outstanding request counter.
+ self.decrementOutstandingRequestForId(messageId, cb);
+ });
+ }
if (invoker.hasMethod('__glob')) {
options = {
methodName: '__glob',
@@ -517,20 +565,11 @@
methodSig: { outArgs: [] },
ctx: context,
call: call,
- // For the glob__ method we just write the
+ // For the __glob method we just write the
// results directly out to the rpc stream.
stream: this._streamMap[messageId]
};
- this.invokeMethod(invoker, options, function(err, results) {
- if (err) {
- var verr = new verror.InternalError(context,
- '__glob() failed', glob, err);
- var errReply = createGlobErrorReply(name, verr, self._appName);
- self._streamMap[messageId].write(errReply);
- vlog.logger.info(verr);
- }
- self.decrementOutstandingRequestForId(messageId, cb);
- });
+ invokeAndCleanup(invoker, options, '__glob');
} else if (invoker.hasMethod('__globChildren')) {
if (glob.length() === 0) {
// This means we match the current object.
@@ -591,16 +630,7 @@
});
});
- this.invokeMethod(invoker, options, function(err, results) {
- if (err) {
- var verr = new verror.InternalError(context,
- '__globChildren() failed', glob, err);
- var errReply = createGlobErrorReply(name, verr, self._appName);
- this._streamMap[messageId].write(errReply);
- vlog.logger.info(verr);
- }
- self.decrementOutstandingRequestForId(messageId, cb);
- });
+ invokeAndCleanup(invoker, options, '__globChildren');
} else {
// This is a leaf of the globChildren call so we return this as
// a result.
@@ -625,10 +655,10 @@
/**
* Sends the result of a requested invocation back to jspr
* @private
- * @param {string} messageId Message id of the original invocation request
+ * @param {number} messageId Message id of the original invocation request
* @param {string} name Name of method
* @param {Object} results Result of the call
- * @param {Object} err Error from the call
+ * @param {Error} err Error from the call
*/
Router.prototype.sendResult = function(messageId, name, results, err,
numOutArgs) {