Skip to content

Commit

Permalink
Merge pull request #11 from teem2/plugins
Browse files Browse the repository at this point in the history
Adding plugin support to dreem2
  • Loading branch information
gnovos committed Jul 27, 2015
2 parents 9a4ead6 + a233910 commit b95e486
Show file tree
Hide file tree
Showing 159 changed files with 13,680 additions and 966 deletions.
4 changes: 2 additions & 2 deletions compositions/smoke/requestor.dre
Expand Up @@ -97,10 +97,10 @@ SOFTWARE. -->
assert.isUndefined(req1.success_data, 'Request did not succeed so the success method should not be called.');

assert.equal(req1.error_status, 404, 'Request to bad url should fail as a 404.');
assert.equal(req1.error_data, "NOT FOUND", 'Server response will be "NOT FOUND".');
assert.equal(req1.error_data, "FILE NOT FOUND", 'Server response will be "NOT FOUND".');

assert.equal(req1.always_status, 404, 'Request to bad url should trigger always method as a 404.');
assert.equal(req1.always_data, "NOT FOUND", 'Server response for always method will be "NOT FOUND".');
assert.equal(req1.always_data, "FILE NOT FOUND", 'Server response for always method will be "NOT FOUND".');


// Success with json (Removing \r is needed for Windows)
Expand Down
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
162 changes: 162 additions & 0 deletions core/pluginloader.js
@@ -0,0 +1,162 @@
/*
The MIT License (see LICENSE)
Copyright (C) 2014-2015 Teem2 LLC
*/
/**
* @class PluginLoader {Internal}
* Reads plugins and injects them into compositins when requested.
*/
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 (!pluginDirs) {
pluginDirs = []
}
if (!Array.isArray(pluginDirs)) {
pluginDirs = [pluginDirs]
}

var errors = [];
for (var i=0;i<pluginDirs.length;i++) {
var pdir = pluginDirs[i];
if (pdir) {
var dir = path.resolve(pdir);
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-a37746aac934b3d2a6c0cdbec3ea731a.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.

0 comments on commit b95e486

Please sign in to comment.