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:
- WordPress page with my special template page visited in browser.
- Template page sets Javascript variables and loads Javascript file
- Javascript file executes after page is loaded and DOM is complete
- Javascript file dynamically loads additional scripts using variables set in step 2.
- 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:'https://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.
0 Comments