[Examples] #359 Updated to attempt connection to remote data source and fallback to local if unavailable

Minor change to readme

Fixed JSLint errors

More JSLint errors

[Example] Rems data integration - disabled bundle by default.

[Examples] REMS data integration - added newlines at end of files

[Example] Added time conductor support to REMS data integration

Added caching of results

[Examples] Added domain format to REMS data #359

[Example] #637 Added local proxy to app.js to allow cross-origin requests

Updated readme
This commit is contained in:
Henry 2016-01-22 12:37:50 -08:00
parent c091063b83
commit 4674918b4b
12 changed files with 119 additions and 70 deletions

11
app.js
View File

@ -14,7 +14,8 @@
options = require('minimist')(process.argv.slice(2)), options = require('minimist')(process.argv.slice(2)),
express = require('express'), express = require('express'),
app = express(), app = express(),
fs = require('fs'); fs = require('fs'),
request = require('request');
// Defaults // Defaults
options.port = options.port || options.p || 8080; options.port = options.port || options.p || 8080;
@ -61,6 +62,14 @@
res.send(JSON.stringify(bundles)); res.send(JSON.stringify(bundles));
}); });
app.use('/proxyUrl', function proxyRequest(req, res, next) {
console.log('Proxying request to: ', req.query.url);
req.pipe(request({
url: req.query.url,
strictSSL: false
}).on('error', next)).pipe(res);
});
// Expose everything else as static files // Expose everything else as static files
app.use(express['static']('.')); app.use(express['static']('.'));

View File

@ -1,7 +1,16 @@
To use this bundle, add the following paths to /main.js -
'./platform/features/conductor/bundle',
'./example/msl/bundle',
An example plugin that integrates with public data from the Curiosity rover. An example plugin that integrates with public data from the Curiosity rover.
The data shown used by this plugin is published by the Centro de The data shown used by this plugin is published by the Centro de
Astrobiología (CSIC-INTA) at http://cab.inta-csic.es/rems/ Astrobiología (CSIC-INTA) at http://cab.inta-csic.es/rems/
Fetching data from this source requires a cross-origin request which will
fail on most modern browsers due to restrictions on such requests. As such,
it is proxied through a local proxy defined in app.js. In order to use this
example you will need to run app.js locally.
This example shows integration with an historical telemetry source, as This example shows integration with an historical telemetry source, as
opposed to a real-time data source that is streaming back current information opposed to a real-time data source that is streaming back current information
about the state of a system. This example is atypical of a historical data about the state of a system. This example is atypical of a historical data

View File

@ -26,7 +26,8 @@ define([
"./src/RemsTelemetryInitializer", "./src/RemsTelemetryInitializer",
"./src/RemsTelemetryModelProvider", "./src/RemsTelemetryModelProvider",
"./src/RemsTelemetryProvider", "./src/RemsTelemetryProvider",
'legacyRegistry' 'legacyRegistry',
"module"
], function ( ], function (
RemsTelemetryServerAdapter, RemsTelemetryServerAdapter,
RemsTelemetryInitializer, RemsTelemetryInitializer,
@ -35,7 +36,6 @@ define([
legacyRegistry legacyRegistry
) { ) {
"use strict"; "use strict";
legacyRegistry.register("example/notifications", { legacyRegistry.register("example/notifications", {
"name" : "Mars Science Laboratory Data Adapter", "name" : "Mars Science Laboratory Data Adapter",
"extensions" : { "extensions" : {
@ -61,19 +61,20 @@ define([
"domains": [ "domains": [
{ {
"name": "Time", "name": "Time",
"key": "timestamp" "key": "timestamp",
"format": "utc"
} }
] ]
} }
} }
], ],
"constants": [ "constants": [
{ {
"key": "REMS_WS_URL", "key": "REMS_WS_URL",
"value": "http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php" "value": "/proxyUrl?url=http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php"
} }
], ],
"roots": [ "roots": [
{ {
"id": "msl:curiosity", "id": "msl:curiosity",
"priority" : "preferred", "priority" : "preferred",
@ -84,20 +85,20 @@ define([
} }
} }
], ],
"services": [ "services": [
{ {
"key":"rems.adapter", "key":"rems.adapter",
"implementation": RemsTelemetryServerAdapter, "implementation": RemsTelemetryServerAdapter,
"depends": ["$q", "$http", "REMS_WS_URL"] "depends": ["$q", "$http", "$log", "REMS_WS_URL"]
} }
], ],
"runs": [ "runs": [
{ {
"implementation": RemsTelemetryInitializer, "implementation": RemsTelemetryInitializer,
"depends": ["rems.adapter", "objectService"] "depends": ["rems.adapter", "objectService"]
} }
], ],
"components": [ "components": [
{ {
"provides": "modelService", "provides": "modelService",
"type": "provider", "type": "provider",
@ -114,3 +115,4 @@ define([
} }
}); });
}); });

File diff suppressed because one or more lines are too long

View File

@ -74,5 +74,6 @@ define(
] ]
} }
] ]
} };
}); }
);

View File

@ -57,7 +57,7 @@ define(
model.name = dictionary.name; model.name = dictionary.name;
model.composition = dictionary.instruments.map(makeId); model.composition = dictionary.instruments.map(makeId);
} }
) );
} }
objectService.getObjects([TAXONOMY_ID]) objectService.getObjects([TAXONOMY_ID])
@ -67,4 +67,5 @@ define(
initializeTaxonomy(adapter.dictionary); initializeTaxonomy(adapter.dictionary);
} }
return RemsTelemetryInitializer; return RemsTelemetryInitializer;
}); }
);

View File

@ -30,7 +30,7 @@ define(
float: "number", float: "number",
integer: "number", integer: "number",
string: "string" string: "string"
} };
function RemsTelemetryModelProvider(adapter){ function RemsTelemetryModelProvider(adapter){
@ -83,4 +83,5 @@ define(
}; };
} }
return RemsTelemetryModelProvider; return RemsTelemetryModelProvider;
}); }
);

View File

@ -43,7 +43,7 @@ define (
*/ */
RemsTelemetryProvider.prototype.requestTelemetry = function (requests) { RemsTelemetryProvider.prototype.requestTelemetry = function (requests) {
var packaged = {}, var packaged = {},
relevantReqs = requests.filter(matchesSource), relevantReqs,
adapter = this.adapter; adapter = this.adapter;
function matchesSource(request) { function matchesSource(request) {
@ -56,26 +56,28 @@ define (
} }
function handleRequest(request) { function handleRequest(request) {
var key = request.key; return adapter.history(request).then(addToPackage);
return adapter.history(key).then(addToPackage);
} }
relevantReqs = requests.filter(matchesSource);
packaged[SOURCE] = {}; packaged[SOURCE] = {};
return this.$q.all(relevantReqs.map(handleRequest)) return this.$q.all(relevantReqs.map(handleRequest))
.then(function () { .then(function () {
return packaged; return packaged;
}); });
} };
/** /**
* This data source does not support real-time subscriptions * This data source does not support real-time subscriptions
*/ */
RemsTelemetryProvider.prototype.subscribe = function (callback, requests) { RemsTelemetryProvider.prototype.subscribe = function (callback, requests) {
return function() {}; return function() {};
}, };
RemsTelemetryProvider.prototype.unsubscribe = function (callback, requests) { RemsTelemetryProvider.prototype.unsubscribe = function (callback, requests) {
return function() {}; return function() {};
} };
return RemsTelemetryProvider; return RemsTelemetryProvider;
} }
); );

View File

@ -19,7 +19,7 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
/*global define */
define( define(
function () { function () {
"use strict"; "use strict";
@ -77,8 +77,8 @@ define(
*/ */
RemsTelemetrySeries.prototype.getRangeValue = function(index) { RemsTelemetrySeries.prototype.getRangeValue = function(index) {
return this.data[index].value; return this.data[index].value;
} };
return RemsTelemetrySeries; return RemsTelemetrySeries;
} }
) );

View File

@ -20,13 +20,18 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
/*global define*/ /*global define*/
/*jslint es5: true */
define( define(
["./MSLDataDictionary"], [
function (MSLDataDictionary) { "./MSLDataDictionary",
"module"
],
function (MSLDataDictionary, module) {
"use strict"; "use strict";
var TERRESTRIAL_DATE = "terrestrial_date"; var TERRESTRIAL_DATE = "terrestrial_date",
LOCAL_DATA = "../data/rems.json";
/** /**
* Fetches historical data from the REMS instrument on the Curiosity * Fetches historical data from the REMS instrument on the Curiosity
@ -37,12 +42,14 @@ define(
* @param REMS_WS_URL The location of the REMS telemetry data. * @param REMS_WS_URL The location of the REMS telemetry data.
* @constructor * @constructor
*/ */
function RemsTelemetryServerAdapter($q, $http, REMS_WS_URL) { function RemsTelemetryServerAdapter($q, $http, $log, REMS_WS_URL) {
this.historyData = {}, this.localDataURI = module.uri.substring(0, module.uri.lastIndexOf('/') + 1) + LOCAL_DATA;
this.deferreds = {}; this.deferreds = {};
this.REMS_WS_URL = REMS_WS_URL; this.REMS_WS_URL = REMS_WS_URL;
this.$q = $q; this.$q = $q;
this.$http = $http; this.$http = $http;
this.$log = $log;
this.cache = undefined;
} }
/** /**
@ -56,43 +63,64 @@ define(
* given request ID. * given request ID.
* @private * @private
*/ */
RemsTelemetryServerAdapter.prototype.requestHistory = function(id) { RemsTelemetryServerAdapter.prototype.requestHistory = function(request) {
var self = this; var self = this,
id = request.key,
deferred = this.$q.defer();
return this.$http.get(this.REMS_WS_URL).then(function(response){ function processResponse(response){
var data = [];
/* /*
* Refresh history data on each request so that it's always * Currently all data is returned for entire history of the mission. Cache response to avoid unnecessary re-queries.
* current.
*/ */
self.historyData = {}; self.cache = response;
/* /*
* History data is organised by Sol. Iterate over sols... * History data is organised by Sol. Iterate over sols...
*/ */
response.data.soles.forEach(function(solData){ response.data.soles.forEach(function(solData){
/* /*
* Each sol contains a number of properties for each * Check that valid data exists
* piece of data available, eg. min ground temperature,
* avg air pressure, etc.
*/ */
Object.keys(solData).forEach(function (prop) { if (!isNaN(solData[id])) {
self.historyData[prop] = self.historyData[prop] || [];
/* /*
* Check that valid data exists * Append each data point to the array of values
* for this data point property (min. temp, etc).
*/ */
if (!isNaN(solData[prop])) { data.unshift({
/* date: Date.parse(solData[TERRESTRIAL_DATE]),
* Append each data point to the array of values value: solData[id]
* for this data point property (min. temp, etc). });
*/ }
self.historyData[prop].unshift({
date: Date.parse(solData[TERRESTRIAL_DATE]),
value: solData[prop]
});
}
});
}); });
self.deferreds[id].resolve({id: id, values: self.historyData[id]}); return data;
}); }
function fallbackToLocal() {
self.$log.warn("Loading REMS data failed, probably due to" +
" cross origin policy. Falling back to local data");
return self.$http.get(self.localDataURI);
}
//Filter results to match request parameters
function filterResults(results) {
return results.filter(function(result){
return result.date >= (request.start || Number.MIN_VALUE) &&
result.date <= (request.end || Number.MAX_VALUE);
});
}
function packageAndResolve(results){
deferred.resolve({id: id, values: results});
}
this.$q.when(this.cache || this.$http.get(this.REMS_WS_URL))
.catch(fallbackToLocal)
.then(processResponse)
.then(filterResults)
.then(packageAndResolve);
return deferred.promise;
}; };
/** /**
@ -103,16 +131,12 @@ define(
* @param id The telemetry data point key to be queried. * @param id The telemetry data point key to be queried.
* @returns {Promise | Array<RemsTelemetryValue>} that resolves with an Array of {@link RemsTelemetryValue} objects for the request data key. * @returns {Promise | Array<RemsTelemetryValue>} that resolves with an Array of {@link RemsTelemetryValue} objects for the request data key.
*/ */
RemsTelemetryServerAdapter.prototype.history = function(id) { RemsTelemetryServerAdapter.prototype.history = function(request) {
this.deferreds[id] = this.deferreds[id] || this.$q.defer(); var id = request.key;
if (this.historyData[id]) { return this.requestHistory(request);
this.deferreds[id].resolve({id: id, values: this.historyData[id]});
} else {
this.historyData = {};
this.requestHistory(id);
}
return this.deferreds[id].promise;
}; };
return RemsTelemetryServerAdapter; return RemsTelemetryServerAdapter;
}); }
);

View File

@ -60,7 +60,6 @@ define([
'./platform/features/layout/bundle', './platform/features/layout/bundle',
'./platform/features/pages/bundle', './platform/features/pages/bundle',
'./platform/features/plot/bundle', './platform/features/plot/bundle',
'./platform/features/conductor/bundle',
'./platform/features/scrolling/bundle', './platform/features/scrolling/bundle',
'./platform/features/timeline/bundle', './platform/features/timeline/bundle',
'./platform/forms/bundle', './platform/forms/bundle',
@ -75,7 +74,6 @@ define([
'./example/imagery/bundle', './example/imagery/bundle',
'./example/eventGenerator/bundle', './example/eventGenerator/bundle',
'./example/msl/bundle',
'./example/generator/bundle' './example/generator/bundle'
], function (Main, legacyRegistry) { ], function (Main, legacyRegistry) {
'use strict'; 'use strict';

View File

@ -4,7 +4,8 @@
"description": "The OpenMCTWeb core platform", "description": "The OpenMCTWeb core platform",
"dependencies": { "dependencies": {
"express": "^4.13.1", "express": "^4.13.1",
"minimist": "^1.1.1" "minimist": "^1.1.1",
"request": "^2.69.0"
}, },
"devDependencies": { "devDependencies": {
"glob": ">= 3.0.0", "glob": ">= 3.0.0",