/**
* @copyright 2015 Tridium, Inc. All Rights Reserved.
* @author Gareth Johnson
*/
/**
* Network Communications for BajaScript.
*
* @author Gareth Johnson
* @version 2.0.0.0
*/
define([
"bajaPromises",
"bajaScript/sys",
"bajaScript/baja/sys/BaseBajaObj",
"bajaScript/baja/comm/Batch",
"bajaScript/baja/comm/BoxError",
"bajaScript/baja/comm/BoxFrame",
"bajaScript/baja/comm/Callback",
"bajaScript/baja/comm/ServerError",
"bajaScript/baja/comm/ServerSession" ], function (
bajaPromises,
baja,
BaseBajaObj,
Batch,
BoxError,
BoxFrame,
Callback,
ServerError,
ServerSession) {
// Use ECMAScript 5 Strict Mode
"use strict";
// Create local for improved minification
var strictArg = baja.strictArg;
//need Contract for station root, and Month, Weekday needed for BDate
var TYPES_TO_ALWAYS_IMPORT = [ 'baja:Station', 'baja:StatusValue',
'baja:Month', 'baja:Weekday', 'baja:Link' ];
/**
* Baja Communications
* @namespace baja.comm
*/
baja.comm = new BaseBajaObj();
baja.comm.ServerError = ServerError;
baja.comm.BoxError = BoxError;
baja.comm.BoxFrame = BoxFrame;
baja.comm.Batch = Batch;
baja.comm.Callback = Callback;
////////////////////////////////////////////////////////////////
// Comms
////////////////////////////////////////////////////////////////
var defaultPollRate = 2500,
eventModePollRate = 30000,
pollRate = defaultPollRate, // Rate at which the Server Session is polled for events
serverSession = null, // The main server session
pollTicket = baja.clock.expiredTicket, // The ticket used to poll for events in the comms layer
commFail = function (err) { // Comm fail handler
baja.outln("Comms failed: " + err.name);
if (!err.noReconnect) {
baja.outln("Attempting reconnect...");
}
},
requestIdCounter = 0, // Number used for generating unique request ids for each BOX message.
frameIdCounter = 0; // Number used for generating unique frame ids for each BOX frame.
/**
* Increment the request id counter and returns its incremented value.
* This is used on each outgoing BOX message in a BOX frame.
*
* @private
*
* @return {Number} The newly incremented request id value.
*/
baja.comm.incrementRequestId = function () {
return ++requestIdCounter;
};
/**
* Increment the frame id counter and returns its incremented value.
* This is used on each outgoing BOX frame.
*
* @private
*
* @return {Number} The newly incremented frame id value.
*/
baja.comm.incrementFrameId = function () {
return ++frameIdCounter;
};
/**
* Set the comm fail function that gets called when the
* communications layer of BajaScript fails.
*
* @private
* @param func the comm fail error
*/
baja.comm.setCommFailCallback = function (func) {
strictArg(func, Function);
commFail = func;
};
/**
* Attempts a reconnection
*
* @abstract
* @private
*/
baja.comm.reconnect = function () {
throw new Error("baja.comm.reconnect not implemented");
};
/**
* @private
* @returns {boolean} true if BajaScript is operating over a secure channel
* @since Niagara 4.14
*/
baja.comm.$isSecure = function () {
return false;
};
function serverCommFail(err) {
// If BajaScript has stopped then don't try to reconnect...
if (baja.isStopping()) {
return;
}
// Nullify the server session as this is no longer valid...
serverSession = null;
try {
// Signal that comms have failed
commFail(err);
} catch (ignore) {
}
// Stop any further polling...
pollTicket.cancel();
function detectServer() {
var cb = new Callback(function ok() {
// If we can get a connection then reconnect
baja.comm.reconnect();
},
function fail(err) {
if (!err.noReconnect) {
// If the BOX Service is unavailable or we can't connect at all then schedule another
// server test to detect when it comes back online...
if (err.delayReconnect) {
// Schedule another test to try and detect the Server since we've got nothing back...
baja.clock.schedule(detectServer, 1000);
} else {
// If we've got some sort of status code back then the server could be there
// so best attempt a refresh
baja.comm.reconnect();
}
}
});
cb.addReq("sys", "hello", {});
cb.commit();
}
// Unless specified otherwise, attempt a reconnect...
if (!err.noReconnect) {
detectServer();
}
}
//TODO: catch unrecoverable error from batch commit. this isn't so great
baja.comm.serverCommFail = serverCommFail;
////////////////////////////////////////////////////////////////
// Server Session Comms Calls
////////////////////////////////////////////////////////////////
baja.comm.getServerSessionId = function () {
return serverSession && serverSession.$id;
};
/**
* Makes the ServerSession.
*
* @private
*
* @param {baja.comm.Callback} cb
*/
baja.comm.makeServerSession = function (cb) {
// Add intermediate callbacks
cb.addOk(function (ok, fail, id) {
try {
serverSession = new ServerSession(id);
ok(id);
} finally {
pollTicket = baja.clock.schedule(baja.comm.poll, pollRate);
}
});
cb.addFail(function (ok, fail, err) {
try {
fail(err);
} finally {
serverCommFail(err);
}
});
// Make the ServerSession
ServerSession.make(cb);
// commit if we can
cb.autoCommit();
};
/**
* Make a Server Session Handler on the Server.
*
* A Server Session represents the session between a BajaScript Client and
* the Server. Components can be created and mounted under the Server's
* Server Session. These are called Server Session Handler Components.
* Server Session Handler Components provide an architecture for Session
* based Components that can receive requests and responses. A Server
* Session Handler can also dispatch events to a BajaScript client for
* further processing. A good example of a Server Session Handler is the
* local Component Space BajaScript is connected to. The Server Session
* Handler API represents a useful abstract layer for other Space subsystems
* to be plugged into (e.g. Virtual Component Spaces).
*
* Currently, the Server Session API is considered to be private and should
* only be used by Tridium framework developers.
*
* @private
*
* @param {String} serverHandlerId a unique String that will identify the Server Session Handler under the Server Session.
* @param {String} serverHandlerTypeSpec the type spec (moduleName:typeName) of the Server Session Handler that will be mounted
* under the Server Session.
* @param serverHandlerArg an initial argument to be passed into the Server Session Handler when it's created. This argument will be
* encoded to standard JSON.
* @param {Function} eventHandler an event handler callback function that will be called when any events are dispatched from the
* Server Session Handler.
* @param {baja.comm.Callback} cb the callback handler.
* @param {Boolean} [makeInBatch] set to true if the batch being used has the make present (hence the server session creation
* is part of this network call.
*/
baja.comm.makeServerHandler = function (serverHandlerId, serverHandlerTypeSpec, serverHandlerArg, eventHandler, cb, makeInBatch) {
var arg;
// If ServerSession isn't available then throw the appropriate error
if (!serverSession) {
// If this flag is true then the Server Session creation is part of this network request
// hence the server session id will be picked up in the Server via the BoxContext
if (makeInBatch) {
arg = ServerSession.addReq("makessc", cb, {});
} else {
throw new Error("ServerSession not currently available!");
}
} else {
arg = serverSession.addReq("makessc", cb);
}
ServerSession.addEventHandler(serverHandlerId, eventHandler);
// Fill out other arguments
arg.scid = serverHandlerId;
arg.scts = serverHandlerTypeSpec;
arg.scarg = serverHandlerArg;
// commit if we can
cb.autoCommit();
};
/**
* Return true if the Server Handler is already registered.
*
* @private
* @param {String} id The event handler id to test for.
* @returns {Boolean} Return true if found.
*/
baja.comm.hasServerHandler = function (id) {
return !!ServerSession.findEventHandler(id);
};
/**
* Remove a Server Session Handler from the Server.
*
* @private
*
* @see baja.comm.makeServerHandler
*
* @param {String} serverHandlerId the id of the Server Session Handler to remove from the Server.
* @param {baja.comm.Callback} cb the callback handler.
*/
baja.comm.removeServerHandler = function (serverHandlerId, cb) {
// If ServerSession isn't available then throw the appropriate error
if (!serverSession) {
throw new Error("ServerSession not currently available!");
}
ServerSession.removeEventHandler(serverHandlerId);
// Make Server Session Request
var arg = serverSession.addReq("removessc", cb);
// Fill out other arguments
arg.scid = serverHandlerId;
// commit if we can
cb.autoCommit();
};
/**
* Represents an object that has a `ServerSessionHandler` residing server-side
* that accepts server handler calls. For instance, a `ComponentSpace` will
* have a corresponding `BComponentSpaceSessionHandler` on the server.
* @private
* @interface ServerHandlerProxy
* @memberOf baja.comm
*/
/**
* @function
* @name baja.comm.ServerHandlerProxy#getServerHandlerId
* @returns {string} the ID of the `ServerSessionHandler` on which server
* handler calls should be made.
*/
/**
* Make an RPC call to the Server Session Handler on the Server.
*
* @private
*
* @see baja.comm.makeServerHandler
*
* @param {String|baja.comm.ServerHandlerProxy} serverHandlerId the ID of the
* Server Session Handler, or an object from whom the server handler ID can be
* requested.
* @param {String} serverHandlerKey the key of the request handler to invoke on the Server Session Handler.
* @param serverHandlerArg the argument to pass into the request handler invoked on the Server Session Handler.
* This argument is encoded to JSON.
* @param {baja.comm.Callback} cb the callback handler.
* @param {Boolean} [makeInBatch] set to true if the batch being used has the make present (hence the server session creation
* is part of this network call).
*/
baja.comm.serverHandlerCall = function (serverHandlerId, serverHandlerKey, serverHandlerArg, cb, makeInBatch) {
var arg;
// If ServerSession isn't available then it's request make be in this batch so
// allow it anyway
if (!serverSession) {
// If this flag is true then the Server Session creation is part of this network request
// hence the server session id will be picked up in the Server via the BoxContext
if (makeInBatch) {
arg = ServerSession.addReq("callssc", cb, {});
} else {
throw new Error("ServerSession not currently available!");
}
} else {
arg = serverSession.addReq("callssc", cb);
}
// Fill out other arguments
if (typeof serverHandlerId === 'string') {
arg.scid = serverHandlerId;
} else if (typeof serverHandlerId.getServerHandlerId === 'function') {
arg.scid = serverHandlerId.getServerHandlerId();
}
arg.sck = serverHandlerKey;
arg.scarg = serverHandlerArg;
// commit if we can
cb.autoCommit();
};
////////////////////////////////////////////////////////////////
// Server Session Event Polling
////////////////////////////////////////////////////////////////
function schedulePoll() {
pollTicket.cancel();
if (serverSession && !baja.isStopping()) {
pollTicket = baja.clock.schedule(baja.comm.poll, pollRate);
}
}
function processEvents(ok, fail, resp) {
var length = resp.length,
i,
handler;
if (baja.isStopping()) {
return;
}
function handlerCb() {
if (--length <= 0) {
ok();
}
}
if (length > 0) {
for (i = 0; i < resp.length; ++i) {
// Look up the event handler using the Server Side Component Id
handler = ServerSession.findEventHandler(resp[i].scid);
if (typeof handler === "function") {
// Handle the events
handler(resp[i].evs, handlerCb);
}
}
} else {
handlerCb();
}
}
/**
* Polls the ServerSession for Changes.
*
* @private
*
* @param {Object} [cb] callback
*/
baja.comm.poll = function (cb) {
// Cancel any existing poll timers
pollTicket.cancel();
// Bail if we're stopping
if (baja.isStopping()) {
return;
}
// Flag indicating whether this was called from the poll timer.
var fromTimer = false;
// Ensure we have a callback
if (!cb) {
cb = new Callback(baja.ok, baja.error);
fromTimer = true;
}
// Bail if we haven't got a serverSession
if (!serverSession) {
throw new Error("No Server Session available");
}
// Process the events
cb.addOk(processEvents);
// Schedule the next poll
cb.getBatch().addCallback(new Callback(schedulePoll, schedulePoll));
cb.addFail(function (ok, fail, err) {
// TODO: Could make this more robust by explicitly checking for server id not existing?
if (fromTimer) {
// Delay raising this error by a second (just in case we're trying to shutdown at the time)...
baja.clock.schedule(function () {
// If there's an error from a timer poll then something must have screwed up
// really badly...
try {
fail(err);
} finally {
serverCommFail(err);
}
}, 1000);
} else {
fail(err);
}
});
serverSession.addReq("pollchgs", cb);
// Commit if we're able to
cb.autoCommit();
};
////////////////////////////////////////////////////////////////
// Comms Unsolicited Event Mode
////////////////////////////////////////////////////////////////
baja.comm.startEventMode = function () {
// Switch to a lower poll rate
pollRate = eventModePollRate;
if (serverSession) {
baja.comm.poll();
}
};
baja.comm.stopEventMode = function () {
// Switch back to the standard poll rate
pollRate = defaultPollRate;
schedulePoll();
};
baja.comm.handleEvents = function (events) {
// Process the events
processEvents(baja.ok, baja.fail, events);
};
////////////////////////////////////////////////////////////////
// Comms Start and Stop
////////////////////////////////////////////////////////////////
/**
* Start the Comms Engine.
*
* This is called to start BajaScript.
*
* @private
*
* @param {Object} obj the Object Literal for the method's arguments.
* @param {Function} [obj.started] function called once BajaScript has started.
* @param {Array} [obj.typeSpecs] an array of type specs (moduleName:typeName) to import
* on start up. This will import both Type and Contract information.
* @param {Function} [obj.commFail] function called if the BOX communications fail.
* @param {Boolean} [obj.navFile] if true, this will load the nav file for the user on start up.
*/
baja.comm.start = function (obj) {
commFail = obj.commFail || commFail;
var started = obj.started || baja.ok,
typeSpecs = obj.typeSpecs || [],
batch = new baja.comm.Batch();
// Get the System Properties...
var propsCb = new Callback(baja.initFromSysProps, baja.fail, batch);
propsCb.addReq("sys", "props", {});
TYPES_TO_ALWAYS_IMPORT.forEach(function (type) {
if (typeSpecs.indexOf(type) < 0) { typeSpecs.push(type); }
});
// If specified, load the Nav File on start up
if (obj.navFile) {
baja.nav.navfile.load({ batch: batch });
}
// Import all of the requested Type Specification
baja.importTypes({ "typeSpecs": typeSpecs, "batch": batch });
// Don't open a local Station connection if BajaScript is running in offline mode.
if (!baja.$offline) {
// Once we have a ServerSession, we can start off our connection to
// to the local Component Space.
baja.station.init(batch);
}
// Call this once everything has finished
batch.addCallback(new Callback(started));
// Commit all comms messages in one request
batch.commit();
};
/**
* Stop the Comms Engine.
*
* @private
*
* @param {Object} obj the Object Literal for the method's arguments.
* @param {Function} [obj.stopped] function to invoke after the comms have stopped.
* @param {Function} [obj.preStop] function to invoke just before the comms have stopped.
*/
baja.comm.stop = function (obj) {
var postStopFunc = obj.stopped || baja.ok;
// Cancel the Ticket
pollTicket.cancel();
// Delete the ServerSession if it exists
if (serverSession) {
var batch = new baja.comm.Batch(),
cb = new Callback(postStopFunc, baja.ok, batch);
serverSession.addReq("del", cb);
// Set hidden synchronous network call flag to 'beacon' so it can be
// safely sent from window unload event handlers.
batch.$sync = 'beacon';
batch.commit();
serverSession = null;
}
// TODO: Need to unsubscribe Components
};
////////////////////////////////////////////////////////////////
// Registry Channel Comms
////////////////////////////////////////////////////////////////
/**
* Makes a network call for loading Type information.
*
* @private
*
* @param {String|Array} types the TypeSpecs needed to be resolved.
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.loadTypes = function (types, cb) {
if (typeof types === "string") {
types = [ types ];
}
// Add a request message to the Builder
cb.addReq("reg", "loadTypes", { t: types, ec: /*encodeContracts*/true });
// commit if we can
cb.autoCommit();
};
/**
* Makes a network call for getting concrete Type information.
*
* @private
*
* @param {String} typeSpec the TypeSpec used for querying the concrete types.
* @param {baja.comm.Callback} cb the callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.getConcreteTypes = function (typeSpec, cb) {
// Add a request message to the Builder
cb.addReq("reg", "getConcreteTypes", typeSpec);
// Commit if we're able too...
cb.autoCommit();
};
/**
* Makes a network call for getting a list of agent information.
*
* @private
*
* @param {Object} arg An object to be used as the argument for the
* `getAgents` call.
* @param {baja.comm.Callback} cb The callback handler.
*/
baja.comm.getAgents = function (arg, cb) {
cb.addReq("reg", "getAgents", arg);
cb.autoCommit();
};
////////////////////////////////////////////////////////////////
// ORD Channel Comms
////////////////////////////////////////////////////////////////
/**
* Resolve an ORD.
*
* @private
*
* @param {baja.Ord} ord the ORD to be resolved.
* @param {baja.Ord} baseOrd the base Ord.
* @param {Object} cb the callback handler.
* @param {Object} options Object Literal options.
*/
baja.comm.resolve = function (ord, baseOrd, cb, options) {
var bd = { // ORD Resolve Message Body
o: String(ord), // ORD
bo: String(baseOrd), // Base ORD
sp: options.sp !== false // Flag to indicate OrdChannel to respond only with SlotPath
};
var cursor = options.cursor;
// If cursor options are defined then use them...
if (cursor) {
bd.c = {
of: cursor.offset,
lm: cursor.limit
};
}
// Add Request Message
cb.addReq("ord", "resolve", bd);
// Commit if we're able too
cb.autoCommit();
};
/**
* Resolve Cursor data for a Collection (or Table).
*
* @private
*
* @param {Object} bd the body of the Comms message.
* @param {baja.comm.Callback} cb the callback handler.
* @param {Object} options Object Literal options.
*/
baja.comm.cursor = function (bd, cb, options) {
bd.of = options.offset;
bd.lm = options.limit;
// Add Request Message
cb.addReq("ord", "cursor", bd);
// Commit if we're able too
cb.autoCommit();
};
////////////////////////////////////////////////////////////////
// Sys Channel Comms
////////////////////////////////////////////////////////////////
/**
* Makes a network call for the nav file.
*
* @private
*
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.navFile = function (cb) {
// Add a request message to the Builder
cb.addReq("sys", "navFile", {});
// commit if we can
cb.autoCommit();
};
/**
* Make a network call with the specified error. This will Log the error
* in the Server.
*
* @private
*
* @param {String} error the error message to be logged in the Server.
*/
baja.comm.error = function (error) {
// Make a network call but don't report back any errors if this doesn't work
var cb = new Callback(baja.ok, baja.ok);
// Add a request message to the Builder
cb.addReq("sys", "error", error);
// commit if we can
cb.commit();
};
/**
* Make an RPC network call with the specified arguments to the Server.
*
* @private
*
* @param {baja.Ord|String} ord The ORD used to resolve the RPC call on the Server.
* @param {String} methodName The name of the method to invoke.
* @param {Array} args The arguments to send to encode to the Server.
* @param {baja.comm.Callback} cb The callback comms object.
*/
baja.comm.rpc = function (ord, methodName, args, cb) {
cb.addReq("sys", "rpc", {
o: ord.toString(),
m: methodName,
a: args
});
cb.autoCommit();
};
////////////////////////////////////////////////////////////////
// Transfer Channel Comms
////////////////////////////////////////////////////////////////
/**
* Performs a move operation on the station using the Transfer API.
* If there is a naming conflict, names will be auto-generated.
*
* @private
* @param {Object} config
* @param {Array.<String|baja.Ord>} config.sourceOrds ORDs of the source
* nodes to be copied
* @param {Array.<baja.NavNode>} [config.sourceBases] Base objects used to
* resolve the source ORDs; any missing bases will use localhost
* @param {baja.NavNode} config.target a mounted target nav node to receive
* the copied nodes
* @param {baja.comm.Callback} cb
* @returns {Promise.<{ undoKey: string, insertNames: string[] }>} promise to
* be resolved after the copy operation completes; if the target is a
* Component, its component space will also be synced. Promise will be
* resolved with an array of the node names of the newly inserted nodes and a
* key for a future call to `undo`.
*
* @see com.tridium.box.BTransferChannel
*/
baja.comm.move = function (config, cb) {
var sourceOrds = config.sourceOrds,
sourceBases = config.sourceBases || [],
target = config.target,
origin = config.origin;
var obj = {
sources: sourceOrds.map(function (sourceOrd, i) {
return toOrdObject(sourceOrd, sourceBases[i]);
}),
target: toOrdObject(target.getNavOrd())
};
if (origin) { obj.origin = origin; }
cb.addReq('transfer', 'move', obj);
if (baja.hasType(target, 'baja:Component')) {
cb.addOk(function (ok, fail, resp) {
target.getComponentSpace().sync({
ok: function () { ok(resp); }, fail: fail
});
});
}
cb.addOk(function (ok, fail, resp) {
ok(resp);
});
cb.autoCommit();
return cb.promise();
};
/**
* Performs a copy operation on the station using the Transfer API.
*
* @private
* @param {Object} config
* @param {Array.<String|baja.Ord>} config.sourceOrds ORDs of the source
* nodes to be copied
* @param {Array.<baja.NavNode>} [config.sourceBases] Base objects used to
* resolve the source ORDs; any missing bases will use localhost
* @param {baja.NavNode} config.target a mounted target nav node to receive
* the copied nodes
* @param {Array.<String>} [config.names] desired names for the copied nodes.
* If omitted, auto-generated names will be used.
* @param {boolean} [config.keepLinks=false] set to true to have links
* copied over from the source nodes
* @param {boolean} [config.keepRelations=false] set to true to have
* relations copied over from the source nodes
* @param {string} [config.origin] set to `compute` to compute the origin
* based off the position of the source nodes (as Paste Special does), or
* set it to a `WsAnnotation` encoding such as `2,2,8` to specify exactly
* what point on the wiresheet the copied nodes should go. If omitted, no
* annotation will be added to the copied nodes.
* @param {number} [config.numCopies=1] set how many times the nodes should
* be duplicated
* @param {baja.comm.Callback} cb
* @returns {Promise.<{ undoKey: string, insertNames: string[] }>} promise to
* be resolved after the copy operation completes; if the target is a
* Component, its component space will also be synced. Promise will be
* resolved with an array of the node names of the newly inserted nodes and a
* key for a future call to `undo`.
*
* @see com.tridium.box.BTransferChannel
*/
baja.comm.copy = function (config, cb) {
var sourceOrds = config.sourceOrds,
sourceBases = config.sourceBases || [],
target = config.target,
names = config.names,
keepLinks = config.keepLinks,
keepRelations = config.keepRelations,
numCopies = config.numCopies,
origin = config.origin;
var obj = {
sources: sourceOrds.map(function (sourceOrd, i) {
return toOrdObject(sourceOrd, sourceBases[i]);
}),
target: toOrdObject(target.getNavOrd())
};
if (names) { obj.names = names; }
if (typeof keepLinks === 'boolean') { obj.keepLinks = keepLinks; }
if (typeof keepRelations === 'boolean') { obj.keepRelations = keepRelations; }
if (typeof numCopies === 'number') { obj.numCopies = numCopies; }
if (typeof origin === 'string') { obj.origin = origin; }
cb.addReq('transfer', 'copy', obj);
if (baja.hasType(target, 'baja:Component')) {
cb.addOk(function (ok, fail, resp) {
target.getComponentSpace().sync({
ok: function () { ok(resp); }, fail: fail
});
});
}
cb.addOk(function (ok, fail, resp) {
ok(resp);
});
cb.autoCommit();
return cb.promise();
};
/**
* Performs a delete operation on the station using the Transfer API.
*
* @private
* @param {Object} config
* @param {Array.<String|baja.Ord>} config.deleteOrds ORDs of the nodes to be
* deleted
* @param {Array.<baja.NavNode>} [config.deleteBases] Base objects used to
* resolve the delete ORDs; any missing bases will use localhost
* @param {baja.comm.Callback} cb
* @returns {Promise.<string>} promise to be resolved after the delete operation
* completes. Promise will be resolved with a string key that may be used for a
* future undelete operation.
*
* @see com.tridium.box.BTransferChannel
* @since Niagara 4.11
*/
baja.comm.delete = function (config, cb) {
var deleteOrds = config.deleteOrds;
var deleteBases = config.deleteBases || [];
var obj = {
deletes: deleteOrds.map(function (deleteOrd, i) {
return toOrdObject(deleteOrd, deleteBases[i]);
})
};
cb.addReq('transfer', 'delete', obj);
cb.addOk(function (ok, fail, resp) {
var undoKey = resp.undoKey;
var spaceOrds = resp.spaceOrds || [];
bajaPromises.all(spaceOrds.map(function (spaceOrd) {
return baja.Ord.make(spaceOrd).get()
.then(function (space) {
return space.sync();
});
}))
.then(function () {
ok(undoKey);
})
.catch(fail);
});
cb.autoCommit();
return cb.promise();
};
/**
* Performs an undo operation on the station using the Transfer API.
*
* @private
* @param {Object} config
* @param {string} config.undoKey an undo key from a previous transfer
* @param {baja.comm.Callback} cb
* @returns {Promise} promise to be resolved after the undo operation
* completes.
*
* @see com.tridium.box.BTransferChannel
* @since Niagara 4.11
*/
baja.comm.undo = function (config, cb) {
var undoKey = config.undoKey;
if (!undoKey) {
cb.fail(new Error('undo key required'));
return cb.promise();
}
cb.addReq('transfer', 'undo', undoKey);
cb.addOk(function (ok, fail, resp) {
var spaceOrds = resp.spaceOrds || [];
bajaPromises.all(spaceOrds.map(function (spaceOrd) {
return baja.Ord.make(spaceOrd).get()
.then(function (space) {
return space.sync();
});
}))
.then(ok, fail);
});
cb.autoCommit();
return cb.promise();
};
function toOrdObject(ord, base) {
return {
o: String(ord),
bo: String((base || baja.nav.localhost).getNavOrd())
};
}
////////////////////////////////////////////////////////////////
// History Channel Comms
////////////////////////////////////////////////////////////////
/**
* Makes a network call to clear all the history records.
*
* @private
*
* @param {Array<String>} ords An array of ORDs to histories to clear.
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.clearAllRecords = function (ords, cb) {
cb.addReq("history", "clearAllRecords", ords);
cb.autoCommit();
};
/**
* Makes a network call to clear all the history records before
* a certain point in time.
*
* @private
*
* @param {Object} obj An object literal containing the arguments.
* @param {Array<String>} obj.ords An array of ORDs to histories to clear.
* @param {String} obj.before The encoded before date absolute date time.
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.clearOldRecords = function (obj, cb) {
cb.addReq("history", "clearOldRecords", obj);
cb.autoCommit();
};
/**
* Makes a network call to delete a number of histories.
*
* @private
*
* @param {Array<String>} ords An array of ORDs to histories to clear.
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.deleteHistories = function (ords, cb) {
cb.addReq("history", "deleteHistories", ords);
cb.autoCommit();
};
////////////////////////////////////////////////////////////////
// Alarm Channel Comms
////////////////////////////////////////////////////////////////
/**
* Makes a network call to query the alarm database for alarms within the supplied
* time range argument. A null argument returns all alarms in the database
*
* @private
*
* @param {Object} obj literal containing timeRange (obj.t), limit (obj.l), offset (obj.o)
* and [obj.a] is passed to indicate whether the view is invoked
* from the alarm archive space (true) or alarm space (false)
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.queryAlarmDatabase = function (obj, cb) {
cb.addReq("alarm", "queryAlarmDatabase", obj);
cb.autoCommit();
};
/**
* Makes a network call to clear all the alarm records.
*
* @private
*
* @param obj
* {boolean} [obj.a] is passed to indicate whether the view is invoked
* from the alarm archive space (true) or alarm space (false)
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.clearAllAlarmRecords = function (obj, cb) {
cb.addReq("alarm", "clearAllRecords", obj);
cb.autoCommit();
};
/**
* Makes a network call to get the number of alarms in the alarm database
* @private
* @param timeRange
* @param cb
*/
baja.comm.getRecordCount = function (timeRange, cb) {
cb.addReq("alarm", "getRecordCount", timeRange);
cb.autoCommit();
};
/**
* Makes a network call to clear alarm records before a given baja.AbsTime
*
* @private
* @param {baja.AbsTime} [obj.time] beforeTime The earliest time to keep in the result. Records
* before this time will be removed.
* @param {boolean} [obj.a] is passed to indicate whether the view is invoked
* from the alarm archive space (true) or alarm space (false)
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.clearOldAlarmRecords = function (obj, cb) {
cb.addReq("alarm", "clearOldRecords", obj);
cb.autoCommit();
};
/**
* Makes a network call to clear an alarm record for a given uuid
*
* @private
*
* @param {Array} [obj.uuids] the Uuids of the Alarm Records to remove from the database.
* @param {boolean} [obj.a] is passed to indicate whether the view is invoked
* from the alarm archive space (true) or alarm space (false)
*
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.clearAlarmRecords = function (obj, cb) {
cb.addReq("alarm", "clearRecords", obj);
cb.autoCommit();
};
/**
* Makes a network call to add a note to the specified alarm record
*
* @private
*
* @param {String} alarm A BSON encoded representation of the alarm record
* @param {String} notes The notes to add to the alarm
*
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.addNote = function (alarm, notes, cb) {
cb.addReq("alarm", "addNote", { alarm: alarm, notes: notes });
cb.autoCommit();
};
/**
* Makes a network call to retrieve a map of alarm class names to alarm class display names
* @private
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.getDisplayNamesMap = function (cb) {
cb.addReq("alarm", "getDisplayNamesMap", {});
cb.autoCommit();
};
/**
* Makes a network call to retrieve a map of alarm class names to alarm class permissions
* @private
*
* @since Niagara 4.9
*
* @param {String} alarmClasses A BSON encoded representation of the alarm class name array
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.getPermissionsMap = function (alarmClasses, cb) {
cb.addReq("alarm", "getPermissionsMap", alarmClasses);
cb.autoCommit();
};
/**
* Makes a network call to retrieve an array of declared fields in an alarm record
* @private
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.getAlarmFields = function (cb) {
cb.addReq("alarm", "getAlarmFields", {});
cb.autoCommit();
};
/**
* Makes a network call to acknowledge a set of alarms specified by uuid and/or source
* @private
* @param {Object} params the object literal that contains the method's arguments.
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.ackAlarms = function (params, cb) {
cb.addReq("alarm", "ackAlarms", params);
cb.autoCommit();
};
/**
* Makes a network call to a notes to a set of alarms specified by uuid and/or source.
* @private
* @param {Object} params the object literal that contains the method's arguments.
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.addNoteToAlarms = function (params, cb) {
cb.addReq("alarm", "addNoteToAlarms", params);
cb.autoCommit();
};
/**
* Makes a network call to force clear a set of alarms specified by uuid and/or source
* @private
* @param {Object} params the object literal that contains the method's arguments.
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.forceClear = function (params, cb) {
cb.addReq("alarm", "forceClear", params);
cb.autoCommit();
};
/**
* Makes a network call to query alarms details specified by uuid and/or source.
* @private
* @param {Object} params the object literal that contains the method's arguments.
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.getSingleSourceSummary = function (params, cb) {
cb.addReq("alarm", "getSingleSourceSummary", params);
cb.autoCommit();
};
/**
* Makes a network call to query an alarm's notes.
* @private
* @param {Object} params the object literal that contains the method's arguments.
* @param {baja.comm.Callback} cb callback handler. If the callback had a
* batch object originally defined then the network call
* will be made.
*/
baja.comm.getNotes = function (params, cb) {
cb.addReq("alarm", "getNotes", params);
cb.autoCommit();
};
return baja;
});