PSEC: Implementing the Protocol

SUMMARY: After defining the rudimentary command protocol for loading and saving data, I have to implement at least the “init” command to provide data to the Javascript side of things. That means implementing a simple command building interface with an optional serial command queue, which forces each command to complete before the next command is sent. Along the way, I am introduced to Javascript-style object-oriented syntax.

Just when I think I’m ready to start writing GUI code, I end up writing more server code. Sigh! Today’s chore is to write the code that initializes the javascript side of things with actual data that will be used to draw the GUI. As it turns out, this isn’t a trivial matter.

Handling Commands

Yesterday, I defined a draft data protocol. Today, I have to implement the “init” command. This requires building the code that creates a “command packet” to transmit to the server for parsing. This is easy enough, but then it occurred to me that since the AJAX requests are asynchronous, I have to make sure that the following order is obeyed:

  1. Send the INIT packet to the server, and await a callback
  2. Receive the MODEL data first
  3. Receive the VISUAL data (that is, the widget layout) after the MODEL data has been parsed
  4. Only then can I enable events for the GUI.

I had defined my INIT packet to provide both model and visual layout in the same packet, but I decided to implement both a regular asynchronous loader with a synchronous one because I imagined this might be useful in the future. The synchronous one accepts queued command requests, which dispatches AJAX commands and waits for the response to succeed before dispatching the next AJAX request in the queue. If the response fails, the callback function gets a chance to handle it and requeue to retry.

NOTE: There’s an interesting book called Eloquent Javascript that’s available online and as a revised printed book. It sounds like it’s aimed at experienced programmers.

Anyway, I spent about two hours writing and debugging the Dispatcher object, make sure it worked with the server. The commands are:

  • GetNewCommandPacket ( action ) – returns an initialized “command object” with action, protocol, user_id, session_id, and timestamp filled in. Nonces and other data need to be added.

  • SendCommand ( cmdPacket, callbackFunction ) – sends an asynchronous AJAX request. The callback gets called with a response object.

  • QueueCommand ( cmdPacket, callbackFunction ) – used to send commands that MUST complete before the next command in the sequence is sent.

  • ReQueueCommand ( cmdPacket, callbackFunction ) – used to requeue a command if it had failed. The callbackFunction can inspect the response packet it gets for SUCCESS or FAILURE and decide what to do.

  • DispatchQueue() – “private” function that kicks off the command queue. It’s automatically invoked when QueueCommand() or ReQueueCommand() is called.

Ensuring Command Consistency

<

p>To ensure consistency in action naming, I defined a CMD object, with things like CMD.INIT = ‘init’. I also renamed the commands to have “sec_” as a prefix, so “init” becomes “sec_init”. This is to avoid conflicts with WordPress’ built-in AJAX actions.

Defining Manager Objects

Javascript doesn’t have classes, but there are two syntax styles that help in creating object-oriented code modules:

// EXAMPLE 1: create an object and then assign additional properties
Dispatcher = {};                                                // create an object
Dispatcher.command_queue = [];                  // create an array in Dispatcher
Dispatcher.SendCommand = function() {}  // create a function in Dispatcher

// EXAMPLE 2: create an object with properties
Dispatcher = {
    command_queue = [],
    SendCommand = function() {}
}

I am using the second one because it’s slightly easier to read, resembling a class declaration though it has all those extra commas.

Initializing

On initialization of the Javascript App, I need to put some values into the Dispatcher structure: the ajax_url, user_id, and session_id. This information needs to come from the Server, so I’m going to create an object that has this information in it.

The very first AJAX call will be to the server to load the model and visual. This will look something like this:

var cmd = Dispatcher.GetNewCommandObject ( CMD.INIT );
Dispatcher.QueueCommand ( cmd, InitFromPacket );

On the server side of things, I’ll need to create a AJAX handler that does all the exciting database pulls into an object of some kind.

NOTE: It took a while to debug this code, as any errors in your PHP result in a “500 Server Unavailable” error with no helpful error messages. If you get this message, assume that it’s a bug in your PHP, not a problem with the server. I discovered this was the case through Googling the error with AJAX and WORDPRESS as additional keywords.

Steps:

  • Added the ‘sec_init’ action to my AJAX action hooker routine.
  • Defined a function called ‘dseah_ajax_sec_init()’ to handle the AJAX call.
  • Wrote a function called ‘dseah_parse_protocol()’ that returns an array with the protocol values to be echoed back to the Javascript.
  • Wrote additional code on the Javascript side to compare timestamps, ensuring that they match (this is a sequence number integrity check) and check for success.

It took another hour or so to debug this code because the “500 Server Unavailable” error I mentioned earlier was masking the true cause of my problem: I had used = instead of => in an associative array definition. Then I was getting back the wrong object types because I’d forgotten to add the “header(Content_Type: application/json)” command before returning the json-encoded response. But now it works.

Yet one more step in the client-server round-trip defined! The skeleton protocol is now in place, so all that is left to do is write the database code to extract the values to send to javascript! Which means I get to write SQL statements…wheee.

I’ll probably get back to this on Sunday. I’m getting closer to making something appear on the browser screen!