Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding plugin support to dreem2 #11

Merged
merged 5 commits into from Jul 27, 2015
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 31 additions & 6 deletions core/compositionserver.js
Expand Up @@ -30,7 +30,7 @@ define(function(require, exports, module) {
this.teemserver = teemserver;
this.args = args;
this.name = name;

this.busserver = new BusServer();
this.watcher = new FileWatcher();
this.watcher.onChange = function(file) {
Expand Down Expand Up @@ -166,7 +166,7 @@ define(function(require, exports, module) {
}
} else {
res.writeHead(404, {"Content-Type":"text/html"});
res.write('NOT FOUND');
res.write('NO SCREENS FOUND');
res.end();
}
}
Expand Down Expand Up @@ -233,7 +233,19 @@ define(function(require, exports, module) {
var htmlParser = new HTMLParser(),
source = data.toString(),
jsobj = htmlParser.parse(source);


if (jsobj.tag == '$root' && jsobj.child) {

var children = jsobj.child;
var composition;
for (var i=0;i<children.length;i++) {
var child = children[i];
if (child.tag == 'composition') {
this.teemserver.pluginLoader.inject(child);
}
}
}

// forward the parser errors
if (htmlParser.errors.length) {
htmlParser.errors.map(function(e) {
Expand Down Expand Up @@ -326,6 +338,7 @@ define(function(require, exports, module) {
if (root) {
jsfile = '$BUILD/' + thePath.replace(/\$/g,'').toLowerCase() + '.js';
this.compile_once[drefile] = jsfile;

this.__compileAndWriteDreToJS(root, jsfile, null, local_err, [drefile]);
ignore_watch = true;
}
Expand Down Expand Up @@ -373,8 +386,19 @@ define(function(require, exports, module) {

/** @private */
this.__getCompositionPath = function() {
var compositionName = this.name,
filepath = '$ROOT/' + compositionName + define.DREEM_EXTENSION;
var compositionName = this.name;
var filepath = '$ROOT/' + compositionName + define.DREEM_EXTENSION;

var match = /^plugins\/([^\/]+)\/examples\/([^\/]+)$/.exec(compositionName)
if (match) {
var pluginName = match[1];
var compName = match[2];
var plugin = this.teemserver.pluginLoader.plugins[pluginName];
if (plugin.rootDir) {
filepath = plugin.rootDir + '/examples/' + compName + define.DREEM_EXTENSION
}
}

if (define.EXTLIB) {
var extpath = define.expandVariables(define.EXTLIB);
if (fs.existsSync(extpath)) {
Expand All @@ -385,6 +409,7 @@ define(function(require, exports, module) {
}
}
}

return filepath;
};

Expand Down Expand Up @@ -760,7 +785,7 @@ define(function(require, exports, module) {
this.__walkChildren(child, stripeditor, insidescreen);
}
}
}
};
this.__saveEditableFile = function(filepath, data, stripeditor) {
var jsobj = JSON.parse(data);
this.__walkChildren(jsobj, stripeditor);
Expand Down
16 changes: 13 additions & 3 deletions core/dreemcompiler.js
Expand Up @@ -369,7 +369,8 @@ define(function(require, exports, module) {
var nodeChildren = node.child;
if (nodeChildren) {
var attributes = {};

var usedNames = [];

for (var i = 0; i < nodeChildren.length; i++) {
var child = nodeChildren[i],
tagName = child.tag,
Expand Down Expand Up @@ -429,8 +430,17 @@ define(function(require, exports, module) {
attrname = 'set_' + attrname;
}

if (tagName == 'handler') attrname = 'handle_' + attrname;
props += attrname + ': function(' + fn.args.join(', ') + '){' + fn.comp + '}';
if (tagName == 'handler') {
attrname = 'handle_' + attrname;
while (usedNames.indexOf(attrname) != -1) {
attrname = 'chained_' + attrname
}
usedNames.push(attrname);
if (child.origin) {
fn.comp = 'try {' + fn.comp + '} finally { if (this.chained_' + attrname + ') { this.chained_' + attrname + '(); } }'
}
}
props += attrname + ': function(' + fn.args.join(', ') + ') {' + fn.comp + '}';
}
break;
case 'attribute':
Expand Down
157 changes: 157 additions & 0 deletions core/pluginloader.js
@@ -0,0 +1,157 @@
/*
The MIT License (see LICENSE)
Copyright (C) 2014-2015 Teem2 LLC
*/
/**
* @class PluginLoader {Internal}
* Holder of the dreem <plugin> for the server
* Manages all iOT objects and the BusServer for each Plugin
*/
define(function(require, exports, module) {
module.exports = PluginLoader;

var path = require('path'),
fs = require('fs'),

HTMLParser = require('./htmlparser'),
DreemError = require('./dreemerror');

function PluginLoader(args, teemserver) {
this.teemServer = teemserver;
this.args = args;
this.plugins = {};

this.__findPlugins();
}

body.call(PluginLoader.prototype);

function body() {

this.__findPlugins = function() {
var pluginDirs = this.args['-plugin'];
if (!Array.isArray(pluginDirs)) {
pluginDirs = [pluginDirs]
}

var errors = [];
for (var i=0;i<pluginDirs.length;i++) {
var dir = path.resolve(pluginDirs[i]);
if (fs.existsSync(dir + '/index.dre')) {
if (!define['PLUGIN']) {
define['PLUGIN'] = [];
}
define['PLUGIN'].push(dir + '/node_modules/');
this.__loadPlugin(dir, errors);
}
}

this.extractedObjects = this.__extractObjects(this.plugins);
};

this.inject = function (composition) {
var objects = composition.child;
if (objects) {
for (var i=this.extractedObjects.length - 1;i >=0;i--) {
var obj = this.extractedObjects[i];

var matchingTag = undefined;
for (var j=0;j<objects.length;j++) {
if (objects[j].tag == obj.tag) {
matchingTag = objects[j];
break;
}
}

if (matchingTag) {
var children = matchingTag.child;
if (!children) {
children = matchingTag.child = [];
}
var toCopy = obj.child;
for (j=0;j<toCopy.length;j++) {
children.unshift(toCopy[j]);
}
} else {
objects.unshift(obj);
}
}
}
};

this.__extractObjects = function (plugins) {

var objects = [];
for (var n in plugins) {
var plugin = plugins[n];
var root = plugin.child;
if (root && root.length > 0) {
var children = root[0].child;
for (var j=0;j<children.length;j++) {
objects.push(children[j])
}
}
}
return objects;
};

this.__originate = function (obj, name) {
if (obj.tag) {
obj['origin'] = name;
}
if (obj.child) {
for (var i = 0;i<obj.child.length;i++) {
var child = obj.child[i];
this.__originate(child, name);
}
}
};

this.__loadPlugin = function (dir, errors) {
console.log('Found plugin in dir:', dir);

try {
var drefile = dir + '/index.dre';
var data = fs.readFileSync(drefile);

var htmlParser = new HTMLParser();
var source = data.toString();
var plugin = htmlParser.parse(source);
plugin.rootDir = dir;

// forward the parser errors
if (htmlParser.errors.length) {
htmlParser.errors.map(function(e) {
errors.push(new DreemError("HTML Parser Error: " + e.message, e.where));
});
}

plugin.source = source;

if (fs.existsSync(dir + '/package.json')) {
plugin.pkg = require(dir + '/package.json');
}
if (!plugin.pkg) {
plugin.pkg = {}
}
if (!plugin.pkg.name) {
//if no package grab the last directory and use it as the plugin name
var match = /([^\/])+\/?$/.exec(dir);
if (match.length) {
plugin.pkg.name = match[0];
}
}

this.__originate(plugin, plugin.pkg.name);

this.plugins[plugin.pkg.name] = plugin;

} catch(e) {
errors.push(new DreemError("Error during readFileSync in __loadPlugin: " + e.toString()));
}

};

}

});
11 changes: 7 additions & 4 deletions core/teemserver.js
Expand Up @@ -19,6 +19,7 @@ define(function(require, exports, module) {
ExternalApps = require('$CORE/externalapps'),
BusServer = require('$CORE/busserver'),
CompositionServer = require('$CORE/compositionserver'),
PluginLoader = require('./pluginloader'),
NodeWebSocket = require('$CORE/nodewebsocket'),
SauceRunner = require('$CORE/saucerunner');

Expand Down Expand Up @@ -103,6 +104,8 @@ define(function(require, exports, module) {
if (this.args['-web']) this.__getComposition(this.args['-web']);

this.saucerunner = new SauceRunner();

this.pluginLoader = new PluginLoader(this.args, this.name, this);
}

body.call(TeemServer.prototype)
Expand All @@ -129,7 +132,7 @@ define(function(require, exports, module) {
// Strip Query
var queryIndex = url.indexOf('?');
if (queryIndex !== -1) url = url.substring(0, queryIndex);

if (url.endsWith(define.DREEM_EXTENSION)) {
url = url.substring(0, url.length - define.DREEM_EXTENSION.length);

Expand All @@ -149,7 +152,7 @@ define(function(require, exports, module) {
}
};

/**
/**
* Handle protocol upgrade to WebSocket
* @param {Request} req
* @param {Socket} sock
Expand Down Expand Up @@ -200,7 +203,7 @@ define(function(require, exports, module) {
res.end();
} else {
res.writeHead(404);
res.write('NOT FOUND');
res.write('FILE NOT FOUND');
res.end();
console.color('~br~Error~y~ ' + filePath + '~~ In teemserver.js request handling. File not found, returning 404\n');
}
Expand Down Expand Up @@ -232,4 +235,4 @@ define(function(require, exports, module) {
}
};
}
})
});
28 changes: 25 additions & 3 deletions define.js
Expand Up @@ -87,7 +87,30 @@
/\$([^\/$]*)/g,
function(all, lut) {
if (lut in define) {
return define.expandVariables(define[lut]);
if (lut == 'PLUGIN') {

//FIXME: there is probably a better way to do this but by this point
// there's no information as to where the str came from, so we can't
// tell which plugin is asking for it's library. So just iterate
// through all the plugin directories and use the first match.
// This will cause problems someday.

if (!define.__FS) {
define.__FS = require('fs');
}
var lib = /\$PLUGIN(.*)/.exec(str)[1];
var paths = define[lut];
for (var i=0;i<paths.length;i++) {
var path = paths[0];
if (define.__FS.existsSync(path + '/' + lib)) {
return define.expandVariables(path);
}
}

throw new Error("Cannot find $PLUGIN lib " + lib + " used in require");
} else {
return define.expandVariables(define[lut]);
}
} else {
throw new Error("Cannot find $" + lut + " used in require");
}
Expand Down Expand Up @@ -135,7 +158,6 @@

if (factory === null) return null; // its not an AMD module, but accept that
if (!factory) throw new Error("Cannot find factory for module:" + abs_path);

// call the factory
var ret = factory.call(module.exports, define.localRequire(define.filePath(abs_path)), module.exports, module);
if (ret !== undefined) module.exports = ret;
Expand Down Expand Up @@ -327,7 +349,7 @@

function localRequire(name) {
if (arguments.length != 1) throw new Error("Unsupported require style");

name = define.expandVariables(name);
var full_name = Module._resolveFilename(name, module);

Expand Down
1 change: 1 addition & 0 deletions docs/api/data-4a543d7d078c3f954b43376d15934fb1.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion docs/api/data-ab1b8e3c387bdacd5b73b0388808e963.js

This file was deleted.

1 change: 1 addition & 0 deletions docs/api/guides/plugins/README.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.