blob: 89d32c85347dfce0a334ae6318dea425910df53e [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
var vdl = require('../gen-vdl/v.io/x/ref/services/wspr/internal/namespace');
var time = require('../gen-vdl/v.io/v23/vdlroot/time');
var emitStreamError = require('../lib/emit-stream-error');
var Readable = require('stream').Readable;
var inherits = require('util').inherits;
module.exports = Namespace;
/**
* @summary
* Namespace defines the APIs for resolving, globbing and managing names.
*
* @description
* <p>Private Constructor. Use
* [runtime.namespace]{@link module:vanadium~Runtime#namespace} to get an
* instance.</p>
*
* @constructor
* @inner
* @memberof module:vanadium.naming
*/
function Namespace(client, rootCtx) {
this._namespace = client.bindWithSignature(
'__namespace', [vdl.Namespace.prototype._serviceDescription]);
this._rootCtx = rootCtx;
}
function GlobStream(orig) {
Readable.call(this, {objectMode: true});
this._orig = orig;
var stream = this;
orig.on('end', function() {
if (!stream._flow(true)) {
orig.on('writable', stream._flow.bind(stream, true));
}
});
orig.on('readable', stream._flow.bind(stream, false));
stream._flow(false);
}
inherits(GlobStream, Readable);
GlobStream.prototype._flow = function(drain) {
// We split the GlobReply union type and send GlobErrors through the
// stream's error channel and valid MountPoints through the data channel.
var chunk;
while((chunk = this._orig.read()) !== null) {
if (chunk.entry) {
if (!this.push(chunk.entry)) {
return false;
}
} else if (chunk.error) {
emitStreamError(this, chunk.error);
}
}
if (drain) {
this.push(null);
}
return true;
};
GlobStream.prototype._read = function() {
// We don't need to do anything, we're always trying to read.
};
/**
* Glob streams all names matching pattern. If recursive is true, it also
* returns all names below the matching ones.
* @param {module:vanadium.context.Context} ctx The rpc context.
* @param {string} pattern Glob pattern to match
* @param {function} cb(error) Optional callback
* @return {Promise} A promise with an stream object hanging from it.
*/
Namespace.prototype.glob = function(ctx, pattern, cb) {
var promise = this._namespace.glob(ctx, pattern, cb);
// We get back a single stream of errors and entries,
// we now split them into a separate stream of errors and
// data via a transform stream.
var newPromise = Promise.resolve(promise);
newPromise.stream = new GlobStream(promise.stream);
return newPromise;
};
/**
* Mount the server object address under the object name, expiring after
* @param {module:vanadium.context.Context} ctx The rpc context.
* @param {string} name Object name
* @param {string} server Server object address
* @param {number} ttl Expiry time for the mount in milliseconds. ttl of zero
* implies never expire.
* @param {boolean} Optional replaceMount Whether the previous mount should
* be replaced by the new server object address. False by default.
* @param {function} cb(error) Optional callback
* @return {Promise} A promise to be resolved when mount is complete or rejected
* when there is an error
*/
Namespace.prototype.mount = function(ctx, name, server, ttl, replaceMount,
cb) {
ttl = ttl || 0; // Default is 0
var duration = new time.Duration({
seconds: Math.floor(ttl / 1000),
nanos: (ttl % 1000) * 1000000
});
replaceMount = !!replaceMount; // Cast to bool
return this._namespace.mount(ctx, name, server, duration, replaceMount, cb);
};
/**
* Unmount the server object address from the object name, or if server is empty
* unmount all server object address from the object name.
* @param {module:vanadium.context.Context} ctx The rpc context.
* @param {string} name Object name
* @param {string} server Server object address
* @param {function} cb(error) Optional callback
* @return {Promise} A promise to be resolved when unmount is complete or
* rejected when there is an error
*/
Namespace.prototype.unmount = function(ctx, name, server, cb) {
return this._namespace.unmount(ctx, name, server, cb);
};
/**
* Resolve the object name into its mounted servers.
* @param {module:vanadium.context.Context} ctx The rpc context
* @param {string} name Object name
* @param {function} cb(error, string[]) Optional callback
* @return {Promise<string[]>} A promise to be resolved a string array of server
* object object addresses or rejected when there is an error
*/
Namespace.prototype.resolve = function(ctx, name, cb) {
return this._namespace.resolve(ctx, name, cb);
};
/**
* ResolveToMountTable resolves the object name into the mounttables
* directly responsible for the name.
* @param {module:vanadium.context.Context} ctx The rpc context.
* @param {string} name Object name
* @param {function} cb(error, string[]) Optional callback
* @return {Promise<string[]>} A promise to be resolved a string array of
* mounttable object addresses or rejected when there is an error
*/
Namespace.prototype.resolveToMounttable = function(ctx, name, cb) {
return this._namespace.resolveToMountTable(ctx, name, cb);
};
/*
* FlushCacheEntry flushes resolution information cached for the name.
* @param {string} name Object name
* @param {function} cb(error, boolean) Optional callback
* @return {Promise<boolean>} A promise to be resolved a boolean indicating if
* anything was flushed or rejected when there is an error
*/
Namespace.prototype.flushCacheEntry = function(name, cb) {
return this._namespace.flushCacheEntry(this._rootCtx, name, cb);
};
/*
* Disables the resolution cache when set to true and enables if false.
* @param {boolean} disable Whether to disable or enable cache.
* @param {function} cb(error) Optional callback
* @return {Promise} A promise to be resolved when disableCache is complete or
* rejected when there is an error
*/
Namespace.prototype.disableCache = function(disable, cb) {
disable = !!disable; // Cast to bool
return this._namespace.disableCache(this._rootCtx, disable, cb);
};
/**
* Returns the currently configured roots. An empty array is returned if no
* roots are configured.
* @param {function} cb(error, string[]) Optional callback
* @return {Promise<string[]>} A promise to be resolved with an array of root
* object names when getRoots is complete or rejected when there is an error
*/
Namespace.prototype.roots = function(cb) {
return this._namespace.roots(this._rootCtx, cb);
};
/**
* Sets the roots that the local Namespace is relative to.
* All relative names passed to the methods above will be interpreted as
* relative to these roots.
* The roots will be tried in the order that they are specified in the parameter
* list for setRoots.
* @param {...string} roots object names for the roots
* @param {function} cb(error) Optional callback
* @return {Promise} A promise to be resolved when setRoots is complete or
* rejected when there is an error
*/
Namespace.prototype.setRoots = function(roots, cb) {
if (!Array.isArray(roots)) {
roots = Array.prototype.slice.call(arguments);
if (typeof roots[roots.length - 1] === 'function') {
cb = roots.pop();
} else {
cb = undefined;
}
}
return this._namespace.setRoots(this._rootCtx, roots, cb);
};
/**
* Sets the Permissions on a namespace.
* If version is specified and is different from the current version on the
* Permissions, an error will be returned.
* Note that setPermissions will completely replace the Permissions on the
* name. If you want to update only a part of the Permissions, you must first
* call getPermissions, modify the returned Permissions, and then call
* setPermissions with the modified Permissions. You should use the version
* parameter in this case to ensure that the Permissions has not been modified
* in between read and write.
* @param {module:vanadium.context.Context} ctx The rpc context.
* @param {string} name name to set the Permissions of
* @param {Map} perms Permissions to set on the name
* @param {string} version Optional version of the Permissions
* @param {function} cb(error) Optional callback
* @return {Promise} A promise to be resolved when setPermissions is complete
* or rejected when there is an error.
*/
Namespace.prototype.setPermissions = function(ctx, name, perms, version, cb) {
// TODO(nlacasse): Should we provide an updatePermissions helper method that
// wraps getPermissions/setPermissions? It's not clear exactly how it would
// work (what to overwrite, what to append), but we should consider it.
if (typeof version === 'function') {
cb = version;
version = '';
}
if (typeof version === 'undefined') {
version = '';
}
return this._namespace.setPermissions(ctx, name, perms, version, cb);
};
/**
* Gets the Permissions on a namespace.
* @param {module:vanadium.context.Context} ctx The rpc context.
* @param {string} name name to get the Permissions of
* @param {function} cb(error, perms, version) Optional callback
* @return {Promise} A promise to be resolved when getPermissions is complete
* or rejected when there is an error.
*/
Namespace.prototype.getPermissions = function(ctx, name, cb) {
return this._namespace.getPermissions(ctx, name, cb);
};
/**
* Deletes a name from the namespace, and possibly all names in subtree.
* @param {module:vanadium.context.Context} ctx The rpc context.
* @param {string} name name to delete
* @param {boolean} deleteSubtree whether to delete all decendent names in
* subtree. If deleteSubtree is false and the name has decendents, then the
* deletion will fail.
* @param {function} cb(error) Optional callback
* @return {Promise} A promise to be resolved when delete is complete or
* rejected when there is an error.
*/
Namespace.prototype.delete = function(ctx, name, deleteSubtree, cb) {
return this._namespace.delete(ctx, name, deleteSubtree, cb);
};