Skip to content

Instantly share code, notes, and snippets.

@photofroggy
Last active December 29, 2015 21:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save photofroggy/7732930 to your computer and use it in GitHub Desktop.
Save photofroggy/7732930 to your computer and use it in GitHub Desktop.
Proof of concept for a different kind of command binding API. Could this be done in Go? idk
/* Concept idea for command binding.
*
* This concept shows an idea for a way to bind commands
* and subcommands. A fairly simple API, if a little object
* heavy. Having this sort of system could make it easier to
* do things like have privilege levels for subcommands.
*/
/**
* Kind of a brief example using a simple handler.
*/
function Main() {
var app = new Application();
// Simple command handler. Just print out event data.
var handle = function( event ) {
console.log( event );
};
// Very simple command.
app.cmd( 'about', handle );
// Example with sub commands
app.cmd( 'example', handle )
.cmd( 'sub', handle );
// Example of how to set privileges and help info.
var ex = app.cmd( 'example2', handle );
ex.access( 1 );
ex.help( 'Just an example of privileges and help strings being set.' );
// Sub commands and how things cascade.
var cascade = app.cmd( 'cascade', handle );
cascade.help( 'Cascading privileges. Anyone can access this command.' );
var csub = cascade.cmd( 'sub', handle );
csub.access( 1 );
csub.help( 'Only operators and up have access to this sub command.' );
var csubsub = csub.cmd( 'sub', handle );
csubsub.access( 2 );
csubsub.help( 'Only Admins can access this one.' );
// Now make the events happen.
var base = {
ns: 'chat:example',
user: 'some-guy',
message: '!about'
};
app.on_msg( base );
base.message = '!example with arguments maybe';
app.on_msg( base );
base.message = '!example.sub subcommand with arguments woooo';
app.on_msg( base );
// Try to use a command we do not have access to
// We don't even get the help message if we don't have access.
base.message = '!example2 ?';
app.on_msg( base );
// Change the user to an operator.
base.user = 'deviant-garde';
app.on_msg( base );
// Lets see how things change for the cascade command.
base.user = 'some-guy';
base.message = '!cascade ?';
app.on_msg( base );
// Try the sub command and fail.
base.message = '!cascade.sub ?';
app.on_msg( base );
// Get it to work by setting an op.
base.user = 'deviant-garde';
app.on_msg( base );
// Next sub command
base.message = '!cascade.sub.sub ?';
app.on_msg( base );
// Get it to work.
base.user = 'photofroggy';
app.on_msg( base );
}
/**
* Simple application object to use as an example.
*
* @class Application
*/
function Application() {
this.events = new EventEmitter();
this.ctrig = '!';
this.csep = '.';
this.privs = {
'photofroggy': 2, // Admin
'deviant-garde': 1, // Operator
'cthom06': 1
};
}
/**
* Retrieve a user's privilege level.
* @method access
*/
Application.prototype.access = function( user ) {
user = user.toLowerCase();
if( !this.privs.hasOwnProperty( user ) )
return 0; // Guest
return this.privs[user];
};
/**
* Set a handler for a command.
* @method cmd
*/
Application.prototype.cmd = function( name, method ) {
name = name.toLowerCase();
var command = new Command( this, name, method );
this.events.addListener( 'cmd.' + name, function(event, app) { command.run( event, app); } );
return command;
};
/**
* Run a command.
* @method trigger
*/
Application.prototype.trigger = function( event, data ) {
this.events.emit( event, data, this );
};
/**
* Handle a command.
* @method handle
*/
Application.prototype.handle = function( data ) {
this.trigger( 'cmd.' + data.cmd[0], data );
};
/**
* Take in a message, see if there's a command that needs handling.
* @method on_msg
*/
Application.prototype.on_msg = function( data ) {
var cdata = {
ns: data.ns,
user: data.user,
access: this.access( data.user ),
message: data.message,
args: [],
cmd: [],
rawcmd: ''
};
cdata.args = cdata.message.split( ' ' );
cdata.rawcmd = cdata.args.shift().toLowerCase();
if( cdata.rawcmd.substr( 0, this.ctrig.length ) != this.ctrig )
return;
cdata.cmd = cdata.rawcmd.substr( this.ctrig.length ).split( this.csep );
this.handle( cdata );
};
/**
* Object representing a command binding.
* @class Command
* @constructor
*/
function Command( app, name, method ) {
this.name = name;
this.method = method;
this.app = app;
this.command = {};
this.priv = 0;
this.helps = '';
}
/**
* Set the access level for this command.
* @method access
*/
Command.prototype.access = function( level ) {
this.priv = level;
};
/**
* Set a help string for this command.
* @method help
*/
Command.prototype.help = function( help ) {
this.helps = help;
};
/**
* Set a handler for a sub command.
* @method cmd
*/
Command.prototype.cmd = function( name, method ) {
name = name.toLowerCase();
var cmd = new Command( this.app, name, method );
this.command[name] = cmd;
return cmd;
};
/**
* Run the command handler.
* @method run
*/
Command.prototype.run = function( event, app, index ) {
index = index || 0;
var next = index + 1;
if( next == 0 )
console.log("Wrong handler called: " + this.name + '; ' + event.rawcmd);
if( event.access < this.priv ) {
console.log(event.user + " does not have access to " + event.rawcmd);
console.log(this.priv + " required. " + event.user + " has " + event.access);
return;
}
if( next < event.cmd.length ) {
if( !this.command.hasOwnProperty( event.cmd[next] ) ) {
console.log( "No such command: " + event.cmd.join(app.csep) );
return;
}
this.command[event.cmd[next]].run( event, app, next );
return;
}
if( event.args[0] == '?' ) {
if( this.helps == '' ) {
console.log(event.user + ': No help available for ' + event.rawcmd);
return;
}
console.log(event.user + ': Help for ' + event.rawcmd);
console.log(this.helps);
return;
}
this.method( event, app );
};
// Taken from dAmnAIR by philo23
// dAmnAIR - http://botdom.com/wiki/DAmnAIR
// philo23 on deviantART - http://philo23.deviantart.com/
/*
* EventEmitter
* Simple event framework, based off of NodeJS's EventEmitter
* @class EventEmitter
* @constructor
**/
/**
* Event emitter object emits events and stuff.
*
* @class EventEmitter
* @constructor
*/
function EventEmitter() {
var events = {}, self = this;
function addListener(event, listener) {
var callbacks = events[event] || false;
if(callbacks === false) {
events[event] = [listener];
return self;
}
events[event].push(listener);
return self;
}
function removeListeners(event) {
events[event] = [];
return self;
}
function emit() {
var args = Array.prototype.slice.call(arguments);
var event = args.shift();
var callbacks = events[event] || false;
var called = 0;
if(callbacks === false) {
return called;
}
for(var i in callbacks) {
if(callbacks.hasOwnProperty(i)) {
bubble = callbacks[i].apply({}, args);
called++;
if( bubble === false )
break;
}
}
return called;
}
function listeners(event) {
return events[event] || [];
}
this.addListener = addListener;
this.removeListeners = removeListeners;
this.emit = emit;
this.listeners = listeners;
}
Main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment