[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)),
express = require('express'),
app = express(),
fs = require('fs');
fs = require('fs'),
request = require('request');
// Defaults
options.port = options.port || options.p || 8080;
@ -61,6 +62,14 @@
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
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.
The data shown used by this plugin is published by the Centro de
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
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

View File

@ -26,7 +26,8 @@ define([
"./src/RemsTelemetryInitializer",
"./src/RemsTelemetryModelProvider",
"./src/RemsTelemetryProvider",
'legacyRegistry'
'legacyRegistry',
"module"
], function (
RemsTelemetryServerAdapter,
RemsTelemetryInitializer,
@ -35,7 +36,6 @@ define([
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/notifications", {
"name" : "Mars Science Laboratory Data Adapter",
"extensions" : {
@ -61,19 +61,20 @@ define([
"domains": [
{
"name": "Time",
"key": "timestamp"
"key": "timestamp",
"format": "utc"
}
]
}
}
],
"constants": [
"constants": [
{
"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",
"priority" : "preferred",
@ -84,20 +85,20 @@ define([
}
}
],
"services": [
"services": [
{
"key":"rems.adapter",
"implementation": RemsTelemetryServerAdapter,
"depends": ["$q", "$http", "REMS_WS_URL"]
"depends": ["$q", "$http", "$log", "REMS_WS_URL"]
}
],
"runs": [
"runs": [
{
"implementation": RemsTelemetryInitializer,
"depends": ["rems.adapter", "objectService"]
}
],
"components": [
"components": [
{
"provides": "modelService",
"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.composition = dictionary.instruments.map(makeId);
}
)
);
}
objectService.getObjects([TAXONOMY_ID])
@ -67,4 +67,5 @@ define(
initializeTaxonomy(adapter.dictionary);
}
return RemsTelemetryInitializer;
});
}
);

View File

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

View File

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

View File

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

View File

@ -20,13 +20,18 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
/*jslint es5: true */
define(
["./MSLDataDictionary"],
function (MSLDataDictionary) {
[
"./MSLDataDictionary",
"module"
],
function (MSLDataDictionary, module) {
"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
@ -37,12 +42,14 @@ define(
* @param REMS_WS_URL The location of the REMS telemetry data.
* @constructor
*/
function RemsTelemetryServerAdapter($q, $http, REMS_WS_URL) {
this.historyData = {},
function RemsTelemetryServerAdapter($q, $http, $log, REMS_WS_URL) {
this.localDataURI = module.uri.substring(0, module.uri.lastIndexOf('/') + 1) + LOCAL_DATA;
this.deferreds = {};
this.REMS_WS_URL = REMS_WS_URL;
this.$q = $q;
this.$http = $http;
this.$log = $log;
this.cache = undefined;
}
/**
@ -56,43 +63,64 @@ define(
* given request ID.
* @private
*/
RemsTelemetryServerAdapter.prototype.requestHistory = function(id) {
var self = this;
RemsTelemetryServerAdapter.prototype.requestHistory = function(request) {
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
* current.
* Currently all data is returned for entire history of the mission. Cache response to avoid unnecessary re-queries.
*/
self.historyData = {};
self.cache = response;
/*
* History data is organised by Sol. Iterate over sols...
*/
response.data.soles.forEach(function(solData){
/*
* Each sol contains a number of properties for each
* piece of data available, eg. min ground temperature,
* avg air pressure, etc.
* Check that valid data exists
*/
Object.keys(solData).forEach(function (prop) {
self.historyData[prop] = self.historyData[prop] || [];
if (!isNaN(solData[id])) {
/*
* 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])) {
/*
* Append each data point to the array of values
* for this data point property (min. temp, etc).
*/
self.historyData[prop].unshift({
date: Date.parse(solData[TERRESTRIAL_DATE]),
value: solData[prop]
});
}
});
data.unshift({
date: Date.parse(solData[TERRESTRIAL_DATE]),
value: solData[id]
});
}
});
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.
* @returns {Promise | Array<RemsTelemetryValue>} that resolves with an Array of {@link RemsTelemetryValue} objects for the request data key.
*/
RemsTelemetryServerAdapter.prototype.history = function(id) {
this.deferreds[id] = this.deferreds[id] || this.$q.defer();
if (this.historyData[id]) {
this.deferreds[id].resolve({id: id, values: this.historyData[id]});
} else {
this.historyData = {};
this.requestHistory(id);
}
return this.deferreds[id].promise;
RemsTelemetryServerAdapter.prototype.history = function(request) {
var id = request.key;
return this.requestHistory(request);
};
return RemsTelemetryServerAdapter;
});
}
);

View File

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

View File

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