hlc-server
Version:
Serves real-time real-world context at a human scale by combining RFID, RTLS and M2M with structured, linked data on the web. We believe in an open Internet of Things.
137 lines (115 loc) • 4.06 kB
JavaScript
/**
* Copyright reelyActive 2016-2020
* We believe in an open Internet of Things
*/
let cormorant = (function() {
// Internal constants
const STATUS_OK = 200;
const SIGNATURE_SEPARATOR = '/';
// Internal variables
let associations = {};
let stories = {};
// Extract the JSON-LD, if present, from the given HTML
function extractFromHtml(html) {
let tagIndex = html.search(/(<script\s*?type\s*?=\s*?"application\/ld\+json">)/);
if(tagIndex < 0) {
return null;
}
let startIndex = html.indexOf('>', tagIndex) + 1;
let stopIndex = html.indexOf('</script>', startIndex);
let jsonString = html.substring(startIndex, stopIndex);
return parseAsStory(jsonString);
}
// Parse the given stringified JSON as a standardised story
function parseAsStory(jsonString) {
let json = null;
try {
json = JSON.parse(jsonString);
// Handle standard reelyActive API response case
if(json.hasOwnProperty('stories')) {
let storyId = Object.keys(json.stories)[0];
let story = json.stories[storyId];
return story;
}
}
catch(e) { }
return json;
}
// Perform a HTTP GET on the given URL with the given accept headers
function retrieve(url, acceptHeaders, callback) {
let httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if(httpRequest.readyState === XMLHttpRequest.DONE) {
let contentType = httpRequest.getResponseHeader('Content-Type');
return callback(httpRequest.status, httpRequest.responseText,
contentType);
}
};
httpRequest.open('GET', url);
httpRequest.setRequestHeader('Accept', acceptHeaders);
httpRequest.send();
}
// Get the associations for the given device identifier
function retrieveAssociations(serverUrl, deviceId, isStoryToBeRetrieved,
callback) {
let url = serverUrl + '/associations/' + deviceId;
retrieve(url, 'application/json', function(status, responseText) {
let deviceAssociations = null;
let isStoryBeingRetrieved = false;
if(status === STATUS_OK) {
let response = JSON.parse(responseText);
let returnedDeviceId = null;
if(response.hasOwnProperty('associations')) { // chickadee v1.x
returnedDeviceId = Object.keys(response.associations)[0];
deviceAssociations = response.associations[returnedDeviceId];
}
else if(response.hasOwnProperty('devices')) { // chickadee v0.x
returnedDeviceId = Object.keys(response.devices)[0];
deviceAssociations = response.devices[returnedDeviceId];
}
associations[deviceId] = deviceAssociations;
associations[returnedDeviceId] = deviceAssociations;
if(isStoryToBeRetrieved && deviceAssociations.url) {
isStoryBeingRetrieved = true;
retrieveStory(deviceAssociations.url, function(story) {
return callback(deviceAssociations, story);
});
}
}
if(!isStoryBeingRetrieved) {
return callback(deviceAssociations);
}
});
}
// Get the story for the given URL
function retrieveStory(storyUrl, callback) {
if(stories.hasOwnProperty(storyUrl)) {
return callback(stories[storyUrl]);
}
retrieve(storyUrl, 'application/json, text/plain',
function(status, responseText, contentType) {
if(status !== STATUS_OK) {
return callback(null);
}
let isJson = (contentType.indexOf('application/json') === 0);
let story;
if(isJson) {
story = parseAsStory(responseText);
}
else {
story = extractFromHtml(responseText);
}
if(story) {
stories[storyUrl] = story;
}
return callback(story);
});
}
// Expose the following functions and variables
return {
retrieveAssociations: retrieveAssociations,
retrieveStory: retrieveStory,
associations: associations,
stories: stories
}
}());