PSEC: Defining a Data Protocol

SUMMARY: After creating some skeleton code to move ints, strings, arrays, and objects from javascript to server and back again, I define PROTOCOL 0001. This defines the “commands” that are sent to the server and the return response. It also lays the groundwork for error checking and multi-user support. Next step will be to implement the protocol to support the actual functions of the web app.

After getting the AJAX calls to work reliably last night, I can now focus on getting the front end to work. It’s probably good to review the order of initialization of the program once more:

  1. WordPress page with my special template page visited in browser.
  2. Template page sets Javascript variables and loads Javascript file
  3. Javascript file executes after page is loaded and DOM is complete
  4. Javascript file dynamically loads additional scripts using variables set in step 2.
  5. READY TO ROCK

At this point, Javascript is running the show. We’re looking at a website which should be loaded with interactive goodies. There are two approaches to this: we could render the goodies in the HTML, or we could load them dynamically and add them to the HTML. It’s the latter approach I’m thinking of using.

But first, I have to define the command protocol…here’s a basic starting list:

  • init – load models and layout structures
  • load – load all models and layout structures. Parameters: what to load,
  • save – save all models and layout structures. Parameters: what to save, and data to save
  • add – add a new “item”. Parameters: item type. Returns new item ID
  • delete – delete an item. Parameters: item ID

These functions are not really well defined, and will probably change. So, I should include a protocol version number as well.

I’m referring to “model” and “layout” structures, as they would be accessed by a “controller” that coordinates actions between everyone.

  • The model is just the Javascript data structure I’ll use to hold task information, indexed by ID. I think it will probably mirror the database data structure, though it holds only a subset of what’s displayed on the screen. The
  • The layout is a list of visual objects, in order they should appear on the screen, with associated visual attributes. They contain a reference to a task ID, which is used to query the model via the controller.
  • The controller is what holds everything together. It’s kind of like a line manager.

Review of Data Sending and Receiving

I think I’ll take a crack at first loading the models from the server, since that’s fresh on my mind from yesterday. Then, I can write the code to draw them.

Before I can do that, though, I need to define the protocol. Let’s review how the data packets are sent to the server:

$.post( DS_AjaxURL, {
    action: 'ajax_action',
    an_int: 1999,
    a_string: 'hello there',
    an_array: [1,2,3,4,5],
    an_object: { param:'value', url:'http://davidseah.com' }
}, function(response) {
    DBG.Out('Success: ' + response.success);
    DBG.Out('An Int: ' + response.an_int);
    DBG.Out('A String: ' + response.a_string);
    DBG.Out('An Array: ' + response.an_array.toString());
    DBG.Out('An Object: ' + response.an_object.toString());
});

On the server side, this is the code that receives the packet:

function ajax_ajax_action() {
    // received data is defined in $_POST
    $an_int = (int) $_POST['an_int'];
    $a_string = (string) $_POST['a_string'];
    $an_array = (array) $_POST['an_array'];
    $an_object = (object) $_POST['an_object'];
    
// response output
    $response = json_encode( array( 'success' => true, 'an_int' => $an_int, 'a_string' => $a_string, 'an_array' => $an_array, 'an_object' => $an_object ) );
    header( "Content-Type: application/json" );
    die ($response);
}

If all works well, then the round trip should preserve all the values and types (though both PHP and Javascript are loosely-typed interpreted languages, but I like to be explicit in my coding. This is the output I get when I run the code, emitted from the anonymous function(response) of the callback:

second-main.js:7[JS] Success: true
second-main.js:7[JS] An Int: 1999
second-main.js:7[JS] A String: hello there
second-main.js:7[JS] An Array: 1,2,3,4,5
second-main.js:7[JS] An Object: [object Object]

That confirms that I can send data and receive data, and everything works great.

Defining the Protocol

This really is just a matter of defining a set of allowed actions, and a protocol version number. Additionally, we need to define the parameters that go with each action. And of course, we define the responses we expect to get.



## PSEC BASIC DATA PROTOCOL
## version 0001

## SEND PACKET via HTTPD POST

   REQUIRED: 'protocol'    - (int) protocol version number
             'action'      - (string) command
             'user_id'     - (int) wordpress user id
             'session_id'  - (int) unique session ID
             'timestamp'   - (string) client generated timestamp
             'nonce'       - (string) form submission verification

   OPTIONAL PARAMETERS
             'debug'       - (bool) set to TRUE for debug info

   ADDITIONAL PARAMETERS are defined based on command


## RECEIVE PACKET via HTTPD CONTENT-TYPE JSON/APPLICATION

   A response object is sent via json_encode(). 
   Object parameters are defined below: 

   RESPONSE. success      - (bool) true/false
             scode        - (int) status code. Nonzero for error.
             stext        - (string) text description of error, if any.
             debug        - (string) debug information, if any
             timestamp    - (int) returned timestamp
             alert        - (bitfield) server-side "something has changed" codes

   ADDITIONAL PARAMETERS are defined based on the type of action


I’m anticipating multiple users, out-of-date clients (particularly ones that are not web-based), and single users using multiple clients to access the same account simultaneously. My initial pass at this will probably not implement all these features as I just try to load stuff from the server, but it will be important when I release for public testing. It’s good to define and implement a solid framework first.

Defining Protocol Actions

With the basic protocol framework defined, let’s look at the basic commands we need: init, load, save, add, delete. I’ll define the additional parameters now, along with any other commands that come to mind.



## COMMAND: INIT
   Used by client to fetch complete application state

   SEND:     'action'      - 'init'
   RECEIVE:  tasks         - task table, array of objects indexed by task_id
             actions       - action table, array of objects indexed by action_id
             v_tasks       - visual components, array of objects in display order

   NOTES:
   . Task Objects are a straight representation of the Tasks Table in MySQL
   . Action Objects are a straight representation of the Actions Table in MySQL
   . VTask Objects contain the associated TaskID plus visual state


## COMMAND: LOADMODEL
   Used by client to fetch model info

   SEND:     'action'      - 'loadmodel'
             'tasklist'    - array of taskIDs to load
             'actionlist'  - array of actionIDs to load
   RECEIVE:  tasks         - task table, array of objects indexed by task_id
             actions       - action table, array of objects indexed by action_id


## COMMAND: LOADVISUAL
   Used by client to refresh visual layout, if it has changed

   SEND:     'action'      - 'loadvisual'
   RECEIVE:  v_tasks       - visual components, array of objects in display order


## COMMAND: KEEPALIVE
   Used by client to poll server for changes via alert parameter

   SEND:     'action'      - 'keepalive'
   RECEIVE:  alert         - non-zero bitfield if something response-worthy has happened

   
## COMMAND: SAVEALL
   Used by client to save the state of the app to the server

   SEND:     'action'      - 'saveall'
             'tasks'       - task table, array of objects indexed by task_id
             'actions'     - action table, array of objects indexed by action_id
             'v_tasks'     - visual components, array of objects in display order


## COMMAND: SAVEMODEL
   Used by client to save specified data items

   SEND:     'action'      - 'savemodel'
             'tasks'       - task table, array of objects indexed by task_id
             'actions'     - action table, array of objects indexed by action_id


## COMMAND: SAVEVISUAL
   Used by client to save the current layout of the screen

   SEND:     'action'      - 'savevisual'
             'v_tasks'     - visual components, array of objects in display order


## COMMAND: DELETE-REQUEST
   Used by client to request to delete particular pieces of data.  

   SEND:     'action'      - 'del-check'
             'type'        - (string) delete an action, task, etc?
             'idlist'      - array of ids to delete
   RECEIVE:  success       - if OK, the delete is allowed
             dependents    - array of dependent objects of this type
             message       - any warnings from server about the deletion
             timestamp     - echoed timestamp
             key           - hash to be provided to DELETE-CONFIRM command

   NOTES:
   . This is a "smart" command in which it tries to make sure the delete is safe,
     providing warnings if there are side effects.
   . The key that is returned is used to unlock the DEL-UNLOCK command, which is
     what actually deletes the data. Not provided if success != true.
   

## COMMAND: DELETE-COMPLETE
   Used by client to actually delete the data, if it has the key from DELETE-REQUEST
             
   SEND:     'action'      - 'del-complete'
             'type'        - (string) delete an action, task, etc?
             'idlist'      - array of ids to delete
             'timecheck'   - timestamp of previous DEL-OK command
             'key'         - hash from previous DEL-OK command
   RECEIVE:  success       - if OK, the delete is allowed
             dependents    - array of dependent objects of this type
             message       - any warnings from server about the deletion

   NOTES:
   . This is what actually deletes the data, if the key is provided.


## COMMAND: NEW
   Used by client to request a brand new data item.

   SEND:     'action'      - 'new'
             'type'        - (string) type of item to add to database
   RECEIVE:  obj_id        - object_id suitable for indexing into array
             obj_data      - object data suitable for storing in array
             type          - type of object that was created

   NOTES:
   . Creates one object at a time
   . Associated visuals should be created by client


Whew! I think that covers everything I need for an initial pass. Copying the text into a document and printing it out for reference.