Last active
December 29, 2015 21:49
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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