UNPKG

webgme-engine

Version:

WebGME server and Client API without a GUI

466 lines (391 loc) 19.3 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: common/executor/ExecutorClient.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: common/executor/ExecutorClient.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>/*globals define, WebGMEGlobal*/ /*eslint-env node, browser*/ /** * Client module for creating, monitoring executor jobs. * * @author lattmann / https://github.com/lattmann * @author ksmyth / https://github.com/ksmyth * @author pmeijer / https://github.com/pmeijer */ define(['superagent', 'q'], function (superagent, Q) { 'use strict'; /** * Client for creating, monitoring, and receiving output executor jobs. * This client is used by the Executor Workers and some of the API calls are not * meant to be used by "end users". * * @param {object} parameters * @param {object} parameters.logger * @constructor * @alias ExecutorClient */ var ExecutorClient = function (parameters) { parameters = parameters || {}; if (parameters.logger) { this.logger = parameters.logger; } else { /*eslint-disable no-console*/ var doLog = function () { console.log.apply(console, arguments); }; this.logger = { debug: doLog, log: doLog, info: doLog, warn: doLog, error: doLog }; console.warn('Since v1.3.0 ExecutorClient requires a logger, falling back on console.log.'); /*eslint-enable no-console*/ } this.logger.debug('ctor', {metadata: parameters}); this.isNodeJS = (typeof window === 'undefined') &amp;&amp; (typeof process === 'object'); this.isNodeWebkit = (typeof window === 'object') &amp;&amp; (typeof process === 'object'); //console.log(isNode); if (this.isNodeJS) { this.logger.debug('Running under node'); this.server = '127.0.0.1'; this.httpsecure = false; } this.server = parameters.server || this.server; this.serverPort = parameters.serverPort || this.serverPort; this.httpsecure = (parameters.httpsecure !== undefined) ? parameters.httpsecure : this.httpsecure; if (this.isNodeJS) { this.http = this.httpsecure ? require('https') : require('http'); } this.origin = ''; if (this.httpsecure !== undefined &amp;&amp; this.server &amp;&amp; this.serverPort) { this.origin = (this.httpsecure ? 'https://' : 'http://') + this.server + ':' + this.serverPort; } if (parameters &amp;&amp; typeof parameters.relativeUrl === 'string') { this.relativeUrl = parameters.relativeUrl; } else if (typeof WebGMEGlobal !== 'undefined' &amp;&amp; WebGMEGlobal.gmeConfig &amp;&amp; typeof WebGMEGlobal.gmeConfig.client.mountedPath === 'string') { this.relativeUrl = WebGMEGlobal.gmeConfig.client.mountedPath + '/rest/executor/'; } else { this.relativeUrl = '/rest/executor/'; } this.executorUrl = this.origin + this.relativeUrl; this.executorNonce = parameters.executorNonce; this.apiToken = parameters.apiToken; this.webgmeToken = parameters.webgmeToken; this.logger.debug('origin', this.origin); this.logger.debug('executorUrl', this.executorUrl); }; /** * Creates a new configuration object for the job execution. * * To make the worker post output either the outputInterval and/or outputSegmentSize must be specified. * &lt;br> - If both are negative (or falsy) no output will be given. * &lt;br> - When both are specified a timeout will be set at start (and after each posted output). * If the number of lines exceeds outputSegmentSize during that timeout, the output will be posted and a * new timeout will be triggered. * &lt;br> * N.B. even though a short outputInterval is set, the worker won't post new output until the responses from * previous posts have returned. Before the job returns with a "completed" status code, all queued outputs will be * posted (and the responses will be ensured to have returned). * * @param {string} cmd - command to execute. * @param {string[]} [args] - command arguments. * @param {number} [outputInterval=-1] - max time [ms] between (non-empty) output posts from worker. * @param {number} [outputSegmentSize=-1] - number of lines before new output is posted from worker. (N.B. posted * segments can still contain more number of lines). * @return {object} */ ExecutorClient.prototype.getNewExecutorConfig = function (cmd, args, outputInterval, outputSegmentSize) { var config = { cmd: cmd, resultArtifacts: [], outputSegmentSize: typeof outputSegmentSize === 'number' ? outputSegmentSize : -1, outputInterval: typeof outputInterval === 'number' ? outputInterval : -1 }; if (args) { config.args = args; } /** * * @param {string} name - name of the artifact. * @param {string[]} [patterns=[]] - inclusive pattern for files to be returned in this artifact. */ config.defineResultArtifact = function (name, patterns) { this.resultArtifacts.push({ name: name, resultPatterns: patterns || [] }); }; return config; }; /** * Creates a new job. * * @param {object} jobInfo - initial information about the job must contain the hash. * @param {object} jobInfo.hash - a unique id for the job (e.g. the hash of the artifact * containing the executor_config.json). * @param {function} [callback] - if provided no promise will be returned. * * @return {external:Promise} On success the promise will be resolved with {@link JobInfo} &lt;b>result&lt;/b>.&lt;br> * On error the promise will be rejected with {@link Error} &lt;b>error&lt;/b>. */ ExecutorClient.prototype.createJob = function (jobInfo, callback) { var deferred = Q.defer(), self = this; if (typeof jobInfo === 'string') { jobInfo = {hash: jobInfo}; // old API } this.logger.debug('createJob', {metadata: jobInfo}); this.sendHttpRequestWithData('POST', this.getCreateURL(jobInfo.hash), jobInfo, function (err, response) { if (err) { deferred.reject(err); return; } self.logger.debug('createJob - result', response); deferred.resolve(JSON.parse(response)); }); return deferred.promise.nodeify(callback); }; ExecutorClient.prototype.cancelJob = function (jobInfoOrHash, secret, callback) { var deferred = Q.defer(), hash = typeof jobInfoOrHash === 'string' ? jobInfoOrHash : jobInfoOrHash.hash, self = this; this.logger.debug('cancel', hash); this.sendHttpRequestWithData('POST', this.executorUrl + 'cancel/' + hash, {secret: secret}, function (err, response) { if (err) { deferred.reject(err); return; } self.logger.debug('cancel - result', response); deferred.resolve(response); } ); return deferred.promise.nodeify(callback); }; ExecutorClient.prototype.updateJob = function (jobInfo, callback) { var deferred = Q.defer(), self = this; this.logger.debug('updateJob', {metadata: jobInfo}); this.sendHttpRequestWithData('POST', this.executorUrl + 'update/' + jobInfo.hash, jobInfo, function (err, response) { if (err) { deferred.reject(err); return; } self.logger.debug('updateJob - result', response); deferred.resolve(response); } ); return deferred.promise.nodeify(callback); }; /** * Retrieves the current state of the job in form of a {@link JobInfo} * @param {string} hash - unique id for the job (e.g. the hash of the artifact containing the executor_config.json). * @param {function} [callback] - if provided no promise will be returned. * * @return {external:Promise} On success the promise will be resolved with {@link JobInfo} &lt;b>jobInfo&lt;/b>.&lt;br> * On error the promise will be rejected with {@link Error} &lt;b>error&lt;/b>. */ ExecutorClient.prototype.getInfo = function (hash, callback) { var deferred = Q.defer(), self = this; this.logger.debug('getInfo', hash); this.sendHttpRequest('GET', this.getInfoURL(hash), function (err, response) { if (err) { deferred.reject(err); return; } self.logger.debug('getInfo - result', response); deferred.resolve(JSON.parse(response)); }); return deferred.promise.nodeify(callback); }; ExecutorClient.prototype.getAllInfo = function (callback) { var deferred = Q.defer(), self = this; this.logger.debug('getAllInfo'); this.sendHttpRequest('GET', this.executorUrl, function (err, response) { if (err) { deferred.reject(err); return; } self.logger.debug('getAllInfo - result', response); deferred.resolve(JSON.parse(response)); }); return deferred.promise.nodeify(callback); }; ExecutorClient.prototype.getInfoByStatus = function (status, callback) { var deferred = Q.defer(), self = this; this.logger.debug('getInfoByStatus', status); this.sendHttpRequest('GET', this.executorUrl + '?status=' + status, function (err, response) { if (err) { deferred.reject(err); return; } self.logger.debug('getInfoByStatus - result', response); deferred.resolve(JSON.parse(response)); }); return deferred.promise.nodeify(callback); }; ExecutorClient.prototype.getWorkersInfo = function (callback) { var deferred = Q.defer(), self = this; this.logger.debug('getWorkersInfo'); this.sendHttpRequest('GET', this.executorUrl + 'worker', function (err, response) { if (err) { deferred.reject(err); return; } self.logger.debug('getWorkersInfo - result', response); deferred.resolve(JSON.parse(response)); }); return deferred.promise.nodeify(callback); }; /** * Retrieves the output associated with jobHash, to limit the output pass start and/or end. * The outputs are identified by 0, 1, 2, ... * @param {string} hash - hash of job related to output. * @param {number} [start] - number/id of the output segment to start from (inclusive). * @param {number} [end] - number/id of segment to end at (exclusive). * @param {function} [callback] - if provided no promise will be returned. * * @return {external:Promise} On success the promise will be resolved with {@link OutputInfo} &lt;b>result&lt;/b>.&lt;br> * On error the promise will be rejected with {@link Error} &lt;b>error&lt;/b>. */ ExecutorClient.prototype.getOutput = function (hash, start, end, callback) { var deferred = Q.defer(), url = this.executorUrl + 'output/' + hash, query = ''; if (typeof start === 'number') { query += '?start=' + start; } if (typeof end === 'number') { if (query) { query += '&amp;end=' + end; } else { query += '?end=' + end; } } url += query; this.logger.debug('getOutput, url=', url); this.sendHttpRequest('GET', url, function (err, response) { if (err) { deferred.reject(err); } else { deferred.resolve(JSON.parse(response)); } }); return deferred.promise.nodeify(callback); }; ExecutorClient.prototype.sendOutput = function (outputInfo, callback) { var deferred = Q.defer(), url = this.executorUrl + 'output/' + outputInfo.hash; this.logger.debug('sendOutput', outputInfo._id); this.sendHttpRequestWithData('POST', url, outputInfo, function (err) { if (err) { deferred.reject(err); } else { deferred.resolve(); } }); return deferred.promise.nodeify(callback); }; //&lt;editor-fold desc="Helper methods"> ExecutorClient.prototype.getInfoURL = function (hash) { return this.origin + this.getRelativeInfoURL(hash); }; ExecutorClient.prototype.getRelativeInfoURL = function (hash) { var metadataBase = this.relativeUrl + 'info'; if (hash) { return metadataBase + '/' + hash; } else { return metadataBase; } }; ExecutorClient.prototype.getCreateURL = function (hash) { return this.origin + this.getRelativeCreateURL(hash); }; ExecutorClient.prototype.getRelativeCreateURL = function (hash) { var metadataBase = this.relativeUrl + 'create'; if (hash) { return metadataBase + '/' + hash; } else { return metadataBase; } }; ExecutorClient.prototype.sendHttpRequest = function (method, url, callback) { return this.sendHttpRequestWithData(method, url, null, callback); }; ExecutorClient.prototype.sendHttpRequestWithData = function (method, url, data, callback) { var req = new superagent.Request(method, url); if (this.executorNonce) { req.set('x-executor-nonce', this.executorNonce); } if (this.apiToken) { req.set('x-api-token', this.apiToken); } if (this.webgmeToken) { req.set('Authorization', 'Bearer ' + this.webgmeToken); } if (data) { req.send(data); } req.end(function (err, res) { if (err) { callback(err); return; } if (res.status > 399) { callback(res.status, res.text); } else { callback(null, res.text); } }); }; ExecutorClient.prototype._ensureAuthenticated = function (options, callback) { //this function enables the session of the client to be authenticated //TODO currently this user does not have a session, so it has to upgrade the options always!!! // if (options.headers) { // options.headers.webgmeclientsession = this._clientSession; // } else { // options.headers = { // 'webgmeclientsession': this._clientSession // } // } callback(null, options); }; //&lt;/editor-fold> return ExecutorClient; }); </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="Server_GMEAuth.html">Server:GMEAuth</a></li><li><a href="Server_SafeStorage.html">Server:SafeStorage</a></li><li><a href="Server_UserProject.html">Server:UserProject</a></li><li><a href="module-Core.html">Core</a></li><li><a href="module-Storage.html">Storage</a></li><li><a href="module-crosscuts.html">crosscuts</a></li><li><a href="module-serialization.html">serialization</a></li></ul><h3>Externals</h3><ul><li><a href="external-Promise.html">Promise</a></li></ul><h3>Classes</h3><ul><li><a href="AddOnBase.html">AddOnBase</a></li><li><a href="AddOnUpdateResult.html">AddOnUpdateResult</a></li><li><a href="Artifact.html">Artifact</a></li><li><a href="BlobClient.html">BlobClient</a></li><li><a href="BlobMetadata.html">BlobMetadata</a></li><li><a href="BlobRunPluginClient.html">BlobRunPluginClient</a></li><li><a href="Client.html">Client</a></li><li><a href="Core.html">Core</a></li><li><a href="ExecutorClient.html">ExecutorClient</a></li><li><a href="GMENode.html">GMENode</a></li><li><a href="GmeLogger.html">GmeLogger</a></li><li><a href="InterPluginResult.html">InterPluginResult</a></li><li><a href="JobInfo.html">JobInfo</a></li><li><a href="OutputInfo.html">OutputInfo</a></li><li><a href="PluginBase.html">PluginBase</a></li><li><a href="PluginConfig.html">PluginConfig</a></li><li><a href="PluginMessage.html">PluginMessage</a></li><li><a href="PluginNodeDescription.html">PluginNodeDescription</a></li><li><a href="PluginResult.html">PluginResult</a></li><li><a href="Project.html">Project</a></li><li><a href="ProjectInterface.html">ProjectInterface</a></li><li><a href="Server_GMEAuth-GMEAuth.html">GMEAuth</a></li><li><a href="Server_SafeStorage-SafeStorage.html">SafeStorage</a></li><li><a href="Server_UserProject-UserProject.html">UserProject</a></li><li><a href="WebsocketRouter.html">WebsocketRouter</a></li><li><a href="WebsocketRouterUser.html">WebsocketRouterUser</a></li></ul><h3>Events</h3><ul><li><a href="Client.html#event:BRANCH_CHANGED">BRANCH_CHANGED</a></li><li><a href="Client.html#event:BRANCH_CLOSED">BRANCH_CLOSED</a></li><li><a href="Client.html#event:BRANCH_OPENED">BRANCH_OPENED</a></li><li><a href="Client.html#event:BRANCH_STATUS_CHANGED">BRANCH_STATUS_CHANGED</a></li><li><a href="Client.html#event:CONNECTED_USERS_CHANGED">CONNECTED_USERS_CHANGED</a></li><li><a href="Client.html#event:NETWORK_STATUS_CHANGED">NETWORK_STATUS_CHANGED</a></li><li><a href="Client.html#event:NOTIFICATION">NOTIFICATION</a></li><li><a href="Client.html#event:PLUGIN_FINISHED">PLUGIN_FINISHED</a></li><li><a href="Client.html#event:PLUGIN_INITIATED">PLUGIN_INITIATED</a></li><li><a href="Client.html#event:PLUGIN_NOTIFICATION">PLUGIN_NOTIFICATION</a></li><li><a href="Client.html#event:PROJECT_CLOSED">PROJECT_CLOSED</a></li><li><a href="Client.html#event:PROJECT_OPENED">PROJECT_OPENED</a></li></ul><h3><a href="global.html">Global</a></h3> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Fri Jun 21 2024 09:43:40 GMT-0400 (Eastern Daylight Time) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>