Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[Script] apicmd - API command processing with option parsing

November 12 (11 years ago)

Edited January 24 (11 years ago)
UPDATE: PLEASE READ THIS FIRST
Make sure you're using the latest version of this script. That means you need to follow the link to Github, you can't just copy the Gist from the Roll20 forum. Those Gists get cached and can be out of date. The latest version of this script includes everything in a single file so you don't need the two parts described in the first post.

https://gist.github.com/goblinHordes/7424738



This is a little rushed and rough, but ready enough. Standardized API command processing has come up a few times in the last couple of days so I'll throw my hat in the ring. This script uses a stripped down version of Optparse.js to handle options and flags used in an API call. It also offers a method for registering API functions and configuring their options. I don't do any processing on themessage object beside parsing the parameters, the message is forwarded intact if the receiving function wants to do anything with it. I'll probably end up creating some sort of better defined object to wrap all the message details in.

It comes in two parts, the first containing the main functionality. It doesn't depend on the Roll20 API, though it does use the Underscore.js library. There are still a few bugs I'd like to work out (escaped quotes within quoted arguments chief among them, then adding filters for things like Characters - not sure how to keep it decoupled at that point though) but the interface shouldn't change too much.
https://gist.github.com/goblinHordes/7424738

The second part has the on('chat:message') handler - you'd never need to write one again if you use this script. It also has an example of a registered function, apicmd, with a single flag, --echo, that echoes any additional arguments sent to it. This script does rely on the Roll20 API, since it is the glue.
https://gist.github.com/goblinHordes/7424756

Having installed those two scripts, you can define a new API function:

apicmd.on('myFunction', 'describes the myFunction usage',
	[['-h', '--help', 'displays help for myFunction']],
	function (msg, args){
		if(args.opts.help){
			sendChat('API', '/desc Not very helpful, is it?');
		}
});
You could then run this function using !myFunction --help in the chat.
November 12 (11 years ago)
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Oh this is brilliant! I am traveling next two days but I am sure to put this to use as soon as I get back!!!!
November 16 (11 years ago)
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
I have actually started to use this with great success so far.
November 16 (11 years ago)
Can you share an example Stephen? It would help me in learning to see it?
November 16 (11 years ago)
I'm really glad to hear that you've found this useful, Stephen. I'm actually working on it tonight and might have an update before the evening is over. At least sometime this weekend.
November 16 (11 years ago)
If you can show me an example of plugging in a couple of the scripts, I can begin working on adding the various scripts out there to it and do some testing.

I would like to plugin the Character Sheet I did Big Mike's PFRPG Character Sheet Generator, Stephen's Language and Blind GM Roll, and Josh's Auto Initiative.

I have been looking at this and looking at this, and this is where my inexperience stalls me out...
November 16 (11 years ago)

Edited November 16 (11 years ago)
This script has been updated on Github. I've done away with decoupling the Optparse from Roll20 functionality since I wanted to get closer integration anyway. This means that you only need the main apicmd.js script, as everything has been folded in. There is only one change to the interface:
  • There is a new required parameter to the apicmd.on function, called usage - this is for displaying usage information
There is a couple new features:
  • Command listing - use !apicmd --list to get a listing of the registered commands
  • Integrated help - use !apicmd --help to get help on how to use the !apicmd command. You can also pass another command name to get help for that function, !apicmd --help objtool
  • Another example command, !objtool. It doesn't do a whole lot, can echo an ID or center one object on another. This was really just a test of the object filters in Optparse.
  • Gross error handling around command calls - just a try block that will capture errors and report failure.
Future plans are mostly cleaning up the code, some better error handling. Right now the help functions pollute the public chat since we can't format whispers, don't know when that could be addressed. I still may change the msg object that gets passed to the called functions, so be prepared for that if you use this code.

Mike, I'll implement Stephen's Language stuff this weekend to give you an example of how it works.
November 16 (11 years ago)
Absolutely Awesome Man! You are a code ninja! Big Mike, gives a "BIG" title to John M. ----> Big John !

Seriously though what an investment, thanks John!
November 27 (11 years ago)
John,

I've been using Alex's chat command handler and wondering if I should switch to yours. Are you still working on creating an example on how it works?

Thanks.
November 27 (11 years ago)

Edited November 27 (11 years ago)
Sorry guys, I've just been swamped with work this past week+. Let's see what I can come up with for examples and documentation.

Let's start with the apicmd.on function definition. apicmd.on is going to register your command to trigger whenever it is used in an API message:

apicmd.on(command, banner, usage, optdefs, function);

Cleaning it up like that makes it look a bit easier to understand. You've got five parameters that you need to pass in:
  • command - (string) The string that will be used in the chat to activate this function. It will need to be used in an API message, so prepended with the exclamation mark (!command).
  • banner - (string) A description of the function. This will appear in the apicmd -h listing.
  • usage - (string) A list of expected parameters to the command. This isn't well used at the moment, but eventually will enforce parameters.
  • optdefs - (array) An array of arrays. The inner arrays contain three items, in order:
    • short option - (string) The single letter short name of the option (ie -h for --help). The first character must be a hyphen (-) and the short option must be a single character. Technically this is optional.
    • long option - (string) The long name of the option (ie --help). The first two characters must be hyphens (--). You can also include a list of parameters that the option is expecting (ie --help COMMAND). The content of the parameter definition is not only descriptive, it actually determines some routines for validating the user input. Follow up documentation will better describe how that works.
    • description - (string) A description of this option. This will appear in the apicmd -h command listing.
  • function - (function) The function that will be called when the API command is issued. It will be passed the following parameters:
    • argv - (object) An object containing two elements
      • opts- (object) An object containing each of the options passed to the command and its values. Those values will either be the values of its expected parameters or a true value if no parameters are defined.
      • args - (array) An array of arguments left over after parsing the options. They will be in the same order as they were given.
    • msg - (message object) The complete message object as passed to



November 27 (11 years ago)

Edited November 27 (11 years ago)
By way of example, I'm feeling mighty lazy tonight, so I'll use the one that is included in the script.

apicmd.on('objtool', 'helpers for managing objects', '[OPTIONS] OBJECT',
    [['-i', '--id', 'return the object\'s id'],
     ['-c', '--center OBJECT', 'center the object on another object']],
    function (argv, msg){
        var targetObj;
        
        if(!(argv.args[0] && (targetObj = findObjs({_id: argv.args[0]})[0]))){
          sendChat('api', 'invalid object id');
          return
        }
 
        if(argv.opts.id){
            sendChat('api', targetObj.id)
            return;
        }
 
        if(argv.opts.center){
            
            var targetX = targetObj.get('top');
            var targetY = targetObj.get('left');
            
            targetObj.set({left: targetX, top: targetY})
            return;
        }
})

Here we're creating the command objtool with two options, --id and --center. These options have short versions as well, -i and -c respectively. There is a single function that receives the argv and msg parameters. Notice the command is expecting an OBJECT; since that parameter stands alone from any option it will appear in the argv.args array.

In fact the first if block of the function is validating the object to ensure it is a real, existing object.

Following the function further, there is an if block to check if the --id option exists. --id doesn't except any parameters, so its just a true value if it does exist and will return the id of the passed object.

Finally, the script checks for the --center option. --center does expect a parameter, another object. If that object is defined, the script will attempt to center it over the object passed as the primary parameter.
January 24 (11 years ago)
I updated the Gist to fix the missing semicolon at the end. Also added a note to the original post to inform new readers of the updates.
January 24 (11 years ago)

Edited January 24 (11 years ago)
Alex L.
Pro
Sheet Author

John M. said:

I updated the Gist to fix the missing semicolon at the end. Also added a note to the original post to inform new readers of the updates.


You can fix the caching problem by linking to the revision not the main gist page. And thanks for the update.