Reworking resource loader to be completly driven by node-cmu

This commit is contained in:
140b8f67-ec51-4b64-9606-bff2dffa0170 2016-04-11 23:48:11 -07:00
parent 2fbbddc878
commit 55310971c8
3 changed files with 198 additions and 173 deletions

View file

@ -0,0 +1,8 @@
/**
* Test Worker
*/
module.exports = function(input, done) {
};

View file

@ -34,10 +34,12 @@ const VERSION = "0.0.1";
* @const * @const
*/ */
const _webSocketServer = require("ws").Server; const _socket = require("ws").Server;
const _extend = require("./cmu-utils").extend; const _extend = require("./cmu-utils").extend;
const _spawn = require('threads').spawn;
const fs = require("fs"); const fs = require("fs");
/** /**
* Minimal Command * Minimal Command
* @constants * @constants
@ -45,7 +47,7 @@ const fs = require("fs");
const REQUEST_VERSION = "version"; const REQUEST_VERSION = "version";
const REQUEST_PING = "ping"; const REQUEST_PING = "ping";
const REQUEST_APPDRIVE = "appdrive"; const REQUEST_SETUP = "setup";
const RESULT_OK = 200; const RESULT_OK = 200;
const RESULT_PONG = 201; const RESULT_PONG = 201;
@ -121,10 +123,10 @@ cmu.prototype = {
__construct: function() __construct: function()
{ {
// initial app drive // initial app drive
this.findAppDrive(); this.updateAppDrive();
// create webserver // create webserver
this.__socket = new _webSocketServer({ this.__socket = new _socket({
port: this.network.port port: this.network.port
}); });
@ -151,69 +153,24 @@ cmu.prototype = {
// assing // assing
this.client.on('message', function(message) { this.client.on('message', function(message) {
this._log('client:message', message);
this.handleClientData(client, message); this.handleClientData(client, message);
}.bind(this)); }.bind(this));
this.client.on('close', function() { this.client.on('close', function() {
// do nothing this._log('client:closed');
}); }.bind(this));
this.client.on('error', function(e) { this.client.on('error', function(e) {
// do nothing this._log('client:error', e.message);
}); }.bind(this));
// let's try this
this.requestLoadJavascript(['test.js']);
}, },
/**
* [requestLoadJavascript description]
* @param {[type]} files [description]
* @param {[type]} path [description]
* @return {[type]} [description]
*/
requestLoadJavascript: function(files, path) {
return this.sendCommand(COMMAND_LOAD_JS, {
filenames: files,
path: path
});
},
/**
* [requestLoadCSS description]
* @param {[type]} files [description]
* @param {[type]} path [description]
* @return {[type]} [description]
*/
requestLoadCSS: function(files, path) {
return this.sendCommand(COMMAND_LOAD_CSS, {
filenames: files,
path: path
});
},
/**
* Sends a command to the client
* @param {[type]} command [description]
* @param {[type]} payload [description]
* @param {[type]} client [description]
* @return {[type]} [description]
*/
sendCommand: function(command, attributes, client) {
this.sendFromPayload(client || this.client, {
command: command,
attributes: attributes,
});
},
/** /**
* Handles a client message * Handles a client message
* @param object client The client instance * @param object client The client instance
@ -223,7 +180,7 @@ cmu.prototype = {
handleClientData: function(client, message, flags) { handleClientData: function(client, message, flags) {
try { try {
var payload = JSON.parse(message); let payload = JSON.parse(message);
// process minimal command interfae // process minimal command interfae
if(payload.request) { if(payload.request) {
@ -253,14 +210,20 @@ cmu.prototype = {
break; break;
/** /**
* Finds the AppDrive * Setup
* @type REQUEST_APPDRIVE * @type REQUEST_SETUP
*/ */
case REQUEST_APPDRIVE: case REQUEST_SETUP:
this.sendFromPayload(client, payload, { if(this.appdrive && this.appdrive.enabled) {
appdrive: this.appdrive
}); // load javascripts
this.requestLoadJavascript(this.resources.js);
// load css
this.requestLoadCSS(this.resources.css);
}
break; break;
@ -289,7 +252,7 @@ cmu.prototype = {
*/ */
sendFromPayload: function(client, payload, data, resultCode) { sendFromPayload: function(client, payload, data, resultCode) {
var final = JSON.stringify(_extend({}, payload, data, { let final = JSON.stringify(_extend({}, payload, data, {
result: resultCode || RESULT_OK result: resultCode || RESULT_OK
})); }));
@ -297,6 +260,70 @@ cmu.prototype = {
}, },
/**
* Sends a command to the client
* @param {[type]} command [description]
* @param {[type]} payload [description]
* @param {[type]} client [description]
* @return {[type]} [description]
*/
sendCommand: function(command, attributes, client) {
this.sendFromPayload(client || this.client, {
command: command,
attributes: attributes,
});
},
/**
* [requestLoadJavascript description]
* @param {[type]} files [description]
* @return {[type]} [description]
*/
requestLoadJavascript: function(files) {
return this.invokeLoadCommand(COMMAND_LOAD_JS, files);
},
/**
* [requestLoadCSS description]
* @param {[type]} files [description]
* @return {[type]} [description]
*/
requestLoadCSS: function(files) {
return this.invokeLoadCommand(COMMAND_LOAD_CSS, files);
},
/**
* [invokeLoadCommand description]
* @param {[type]} command [description]
* @param {[type]} files [description]
* @return {[type]} [description]
*/
invokeLoadCommand: function(command, files) {
let source = files instanceof Array ? files : ([].push(files)),
data = [];
source.forEach(function(filename) {
if(this._isFile(filename)) {
data.push({
contents: (fs.readFileSync(filename)).toString(),
location: filename
});
}
}.bind(this));
this.sendCommand(command, {
data
});
},
/** /**
* Returns the version * Returns the version
* @getter * @getter
@ -312,21 +339,27 @@ cmu.prototype = {
* @param function callback A callback * @param function callback A callback
* @return void * @return void
*/ */
findAppDrive: function(callback) { updateAppDrive: function(callback) {
this.appdrive = { this.appdrive = {
locations: {}, locations: {},
applications: {}, applications: {},
enabled: false,
};
this.workers = {};
this.resources = {
js: [], js: [],
css: [], css: [],
}; };
var result = [], let result = [],
mountPoints = ['sd_nav', 'sda', 'sdb', 'sdc', 'sdd', 'sde', 'sdf']; mountPoints = ['sd_nav', 'sda', 'sdb', 'sdc', 'sdd', 'sde', 'sdf'];
mountPoints.forEach(function(mountPoint) { mountPoints.forEach(function(mountPoint) {
var appDrivePath = [MOUNTROOT_PATH, mountPoint, APPDRIVE_PATH].join(""), let appDrivePath = [MOUNTROOT_PATH, mountPoint, APPDRIVE_PATH].join(""),
appDriveFilename = [appDrivePath, APPDRIVE_JSON].join(""), appDriveFilename = [appDrivePath, APPDRIVE_JSON].join(""),
@ -359,9 +392,11 @@ cmu.prototype = {
* Load Framework * Load Framework
*/ */
this.appdrive.js.push([systemPath, SYSTEM_FRAMEWORK_PATH, SYSTEM_FRAMEWORK_JS].join("")); this.resources.js.push([systemPath, SYSTEM_FRAMEWORK_PATH, SYSTEM_FRAMEWORK_JS].join(""));
this.appdrive.css.push([systemPath, SYSTEM_FRAMEWORK_PATH, SYSTEM_FRAMEWORK_CSS].join("")) this.resources.css.push([systemPath, SYSTEM_FRAMEWORK_PATH, SYSTEM_FRAMEWORK_CSS].join(""))
this.appdrive.enabled = true;
/** /**
* Prepare system mount * Prepare system mount
@ -379,7 +414,7 @@ cmu.prototype = {
* Find Applications * Find Applications
*/ */
var appFiles = fs.readdirSync(applicationsPath); let appFiles = fs.readdirSync(applicationsPath);
if(appFiles.length) appFiles.forEach(function(appId) { if(appFiles.length) appFiles.forEach(function(appId) {
@ -390,11 +425,11 @@ cmu.prototype = {
if(!this.appdrive.applications[appId]) { if(!this.appdrive.applications[appId]) {
var applicationPath = [applicationsPath, appId, "/"].join(""); let applicationPath = [applicationsPath, appId, "/"].join("");
if(this._isDir(applicationPath)) { if(this._isDir(applicationPath)) {
var profile = { let profile = {
id: appId, id: appId,
path: applicationPath, path: applicationPath,
files: {}, files: {},
@ -404,7 +439,7 @@ cmu.prototype = {
parts.forEach(function(filename) { parts.forEach(function(filename) {
var fullFilename = [applicationPath, filename].join(""); let fullFilename = [applicationPath, filename].join("");
if(this._isFile(fullFilename)) { if(this._isFile(fullFilename)) {
@ -423,6 +458,8 @@ cmu.prototype = {
if(found >= 1) { if(found >= 1) {
this.appdrive.applications[appId] = profile; this.appdrive.applications[appId] = profile;
this.registerWorker(appId);
} }
} }
} }
@ -435,6 +472,30 @@ cmu.prototype = {
if(callback) callback(this.appdrive); if(callback) callback(this.appdrive);
}, },
/**
* Registers a worker to the appid
* @param {[type]} appId [description]
* @return {[type]} [description]
*/
registerWorker: function(appId) {
// ensure applications is registered
if(!this.appdrive.applications[appId]) return false;
// ensure worker is eligible
if(!this._isFile(this.appdrive.applications[appId].files[APPLICATION_WORKER])) return false;
// create worker
this.workers[appId] = {
appId: appId,
thread: _spawn(this.appdrive.applications[appId].files[APPLICATION_WORKER])
};
},
/** /**
* Checks if the file exists * Checks if the file exists
* @param string path A string that represents a file path * @param string path A string that represents a file path
@ -473,6 +534,27 @@ cmu.prototype = {
return false; return false;
}, },
/**
* [__log description]
* @param {[type]} name [description]
* @param {[type]} description [description]
* @param {[type]} attributes [description]
* @return {[type]} [description]
*/
_log: function(name, description, attributes) {
console.log("[" + name + "]", description, attributes ? function() {
let result = [];
Object.keys(attributes).forEach(function(element, key, _array) {
result.push("[" + element + "=" + _array[key] + "]");
});
return result.join(" ");
}.call() : "");
},
}; };
/** /**

View file

@ -46,7 +46,7 @@ window.CMU = {
requests: { requests: {
REQUEST_PING: 'ping', REQUEST_PING: 'ping',
REQUEST_APPDRIVE: 'appdrive', REQUEST_SETUP: 'setup',
}, },
/** /**
@ -80,7 +80,7 @@ window.CMU = {
this.initialized = true; this.initialized = true;
this.requests = {}; this.requestBuffer = {};
this.obtainConnection(); this.obtainConnection();
} }
@ -125,6 +125,8 @@ window.CMU = {
this.__log("connection open"); this.__log("connection open");
this.requestSetup();
}.bind(this); }.bind(this);
/** /**
@ -175,6 +177,15 @@ window.CMU = {
} }
}, },
/**
* [requestSetup description]
* @return {[type]} [description]
*/
requestSetup: function() {
this.request(this.requests.REQUEST_SETUP);
},
/** /**
* [request description] * [request description]
* @return {[type]} [description] * @return {[type]} [description]
@ -186,12 +197,12 @@ window.CMU = {
// prepare id // prepare id
var id = false; var id = false;
while(!id || this.requests[id]) { while(!id || this.requestBuffer[id]) {
id = (new Date()).getTime(); id = (new Date()).getTime();
} }
// register request // register request
this.requests[id] = callback; this.requestBuffer[id] = callback;
// sanity check // sanity check
payload = payload || {}; payload = payload || {};
@ -201,6 +212,8 @@ window.CMU = {
payload.request = request; payload.request = request;
console.log(payload);
// execute // execute
return this.client.send(JSON.stringify(payload)); return this.client.send(JSON.stringify(payload));
}, },
@ -235,16 +248,16 @@ window.CMU = {
default: default:
// check against active requests // check against active requests
if(payload.requestId && this.requests[payload.requestId]) { if(payload.requestId && this.requestBuffer[payload.requestId]) {
var callback = this.requests[payload.requestId]; var callback = this.requestBuffer[payload.requestId];
if(typeof(callback) == "function") { if(typeof(callback) == "function") {
callback(payload.result == this.results.RESULT_ERROR, payload); callback(payload.result == this.results.RESULT_ERROR, payload);
} }
delete this.requests[payload.requestId]; delete this.requestBuffer[payload.requestId];
return; // all done return; // all done
} }
@ -270,117 +283,39 @@ window.CMU = {
/** @type {LOADJS} [description] */ /** @type {LOADJS} [description] */
case this.commands.LOAD_JS: case this.commands.LOAD_JS:
this.loadJavascript(attributes.filenames, attributes.path); this.__loadInvoker(attributes, 'script', 'text/javascript');
break; break;
/** @type {LOADCSS} */
case this.commands.LOAD_CSS:
this.__loadInvoker(attributes, 'style', 'text/css');
break;
} }
}, },
/**
* (loadJavascript)
*/
loadJavascript: function(scripts, path, callback, options) {
this.__loadInvoker(scripts, path, function(filename, next) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = filename;
script.onload = next;
document.body.appendChild(script);
}, callback, options);
},
/**
* (loadCSS)
*/
loadCSS: function(css, path, callback, options) {
this.__loadInvoker(css, path, function(filename, next) {
var css = document.createElement('link');
css.rel = "stylesheet";
css.type = "text/css";
css.href = filename
css.onload = async ? callback : next;
document.body.appendChild(css);
}, callback, options);
},
/** /**
* (__loadInvoker) * (__loadInvoker)
*/ */
__loadInvoker: function(input, path, build, callback, options) { __loadInvoker: function(attributes, tag, type) {
// sanity checks if(!attributes.data || !attributes.data instanceof Array) return false;
if(typeof(build) != "function") return false;
// initialize attributes.data.forEach(function(item) {
var ids = false, result = false, options = options ? options : {timeout: 1000}, timeout = false;
// items need to be an array if(item.location && item.contents) {
var items = input instanceof Array ? input : function() {
var newArray = []; var element = document.createElement(tag);
element.setAttribute("data-script-url", item.location);
element.appendChild(document.createTextNode(item.contents));
newArray.push(input); if(type) element.setAttribute("type", type);
document.head.appendChild(element);
return newArray;
}.call();
// loaded handler
var loaded = 0, next = function(failure) {
loaded++;
if(loaded >= items.length) {
if(typeof(callback) == "function") {
callback(result);
}
}
};
// process items
items.forEach(function(filename, index) {
try {
filename = (path ? path : "") + filename;
if(options.timeout) {
clearTimeout(timeout);
timeout = setTimeout(function() {
this.__error("__loadInvoker:timeout", {filename: filename});
// just do the next one
next(true);
}.bind(this), options.timeout);
}
try {
build(filename, function(resource) {
next();
}.bind(this), ids ? ids[index] : false);
} catch(error) {
next(true);
}
} catch(error) {
this.__error("__loadInvoker:loaderror", {error: error, filename: filename});
} }
}.bind(this)); });
return true;
}, },
/** /**