Skip to content

Instantly share code, notes, and snippets.

@PatrickKennedy
Last active May 21, 2017 05:06
Show Gist options
  • Select an option

  • Save PatrickKennedy/8cda473fc0fd1a854077afae90fb01a9 to your computer and use it in GitHub Desktop.

Select an option

Save PatrickKennedy/8cda473fc0fd1a854077afae90fb01a9 to your computer and use it in GitHub Desktop.
const events = require('events');
const purgeCache = require('./util/purgeCache')
const path = require('path');
console.log("Test Space Running");
class BasePlugin {
/**
* @param {String} name - The name of the plugin, must match module name
* @param {EventEmitter} owner - any EventEmitter
* @param {string} [namespace="morty"] - The namespace used to namespace emitter events
*/
constructor(name, owner, namespace="morty") {
console.log(`[new] Constructing ${name}`);
this.name = name;
this.owner = owner;
this.namespace = namespace;
this.traps = {
apply: (target, thisArg, args) => {
return Reflect.apply(target, this, args);
}
}
this.proxies = new Map();
this.events = {};
this.registerHandler(this.unload);
}
/**
* Wrap the owner's .on() call optionally namespacing events and tracking
* event handlers to automatically unregister them when the plugin is unloaded
* @param {string} event - the event to listen for
* @param {function} handler - a handler function, ideally one bound to the
* plugin context
* @param {boolean} [namespace=true] - if true the event name will be prefixed
* with the configured namespace
*/
on(event, handler, namespace=true) {
let e = (namespace ? `${this.namespace}:` : '') + event;
if (e in this.events)
throw new Error(`Attempting to register another handler to ${e} on the ${this.name} plugin`);
this.events[e] = handler;
console.log(`[on] Registering event ${e}`);
return this.owner.on(e, handler);
}
off(event, handler, namespace=true) {
let e = (namespace ? `${this.namespace}:` : '') + event;
handler = this.events[e];
console.log(`[off] Unregistering event ${e}`);
this.owner.removeListener(event, handler);
}
emit(event, ...args) {
let e = `${this.namespace}:${event}`;
console.log(`[emit] Emitting event ${e}`);
return this.owner.emit(e, ...args);
}
proxy(handler) {
if(this.proxies.has(handler))
return this.proxies.get(handler);
let proxy = new Proxy(handler, this.traps);
this.proxies.set(handler, proxy);
return proxy;
}
registerEventTrap(handler) {
let event = handler.name;
return this.on(event, this.proxy(handler), false);
}
registerHandler(handler) {
let event = handler.name.toLowerCase();
return this.on(event, this.proxy(handler));
}
registerCommand(handler) {
let event = handler.name.replace('cmd_?', '').toLowerCase();
return this.on(`cmd:${event}`, this.proxy(handler));
}
loaded(name) {}
unload(name) {
if (name !== this.name)
return;
for (let event in this.events) {
this.off(event, this.events[event], false);
}
this.emit('unloaded', this);
}
}
class Bootstrapper extends BasePlugin {
constructor(owner, lookup_paths=['./plugins', './src/plugins']) {
super("bootstrap", owner);
this.lookup_paths = lookup_paths;
this.registerEventTrap(this.message);
this.emit('loaded', this);
}
/**
* Handle messages, specifically processing namespaced commands
* @param {string} message
*/
message(message) {
console.log(`[message] Received Message: ${message}`);
if(message.startsWith('!')) {
let [cmd, ...args] = message.split(' ');
cmd = cmd.substr(1).toLowerCase();
args = args.join(' ');
this.emit(`cmd:${cmd}`, message, args);
}
}
cmd_load(args) {
let plugins = args.split(' ');
for (let name in names) {
for (const prefix of this.lookup_paths) {
let Plugin = this._require(prefix, name);
if (typeof Plugin !== "undefined") {
new Plugin(this.owner);
break;
}
}
}
}
cmd_unload(msg, names) {
names = names.split(' ');
for (let name of names) {
this.emit('unload', name);
purgeCache(name);
}
}
_require(...paths) {
try {
return require(path.join(...paths));
} catch (e) {
return;
}
}
}
class Hello extends BasePlugin {
constructor(owner) {
super("hello", owner);
this.registerCommand(this.hello);
this.emit('loaded', this);
}
hello(name) {
console.log(`Hello, ${name}`);
}
}
const ee = new events.EventEmitter();
new Bootstrapper(ee);
new Hello(ee);
ee.emit('message', '!hello Patrick');
console.log('End of Test Space');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment