Skip to content

Network Communication Philosophy (Or, How I Learned to Stop Worrying and Love UDP)

akersten edited this page Mar 25, 2013 · 6 revisions

The network layout looks kind of like this:

[Fountain Hardware] <--- Analog Magic ---> [cRIO] [cRIO] <--- Fragile UDP Protocol ---> [enlight-backend] [enlight-backend] <--- Robust UDP Protocol ---> [enlight-webfront] [enlight-webfront] <--- User Interaction ---> [enlight-human]

Because the cRIO is very sensitive to malformed input (side note: it's written in LabView and someone should make it better), we want to abstract away most of the interaction as far as possible. Each of these steps is documented below. See the actual protocol details here.

Analog Magic

Don't know anything about this. Probably some very basic 24V stuff. Thankfully whoever was here before us already abstracted this away into the cRIO (albeit with a protocol sensitive to bad input, it crashes if you tell it the wrong thing).

Fragile UDP Protocol

This is the communication protocol between the cRIO and the actual server which will tell it what to do. This is mostly already documented here but any important notes can be added to this page. In fact, someone should probably back up this documentation into Legacy pages here on the GitHub wiki just so it's consolidated.

Anyway, most of this protocol is the same as what has been in use, so we're just going to be re-implementing it from the C# project into the C++ one.

This protocol is completely handled between the cRIO and the native server - the webfront doesn't get to touch this other than from a very high level of abstraction.

Robust UDP Protocol

This is the important part, the new stuff that we're introducing with this project. Essentially, the webfront and native server need a way to exchange information, and there's two aspects to this:

####Information the webfront sends to the server Requests made to the native server from the Webfront will all be prefaced with the Service Master Key which you should change from the testing/debug value, otherwise anyone will be able to control the server. This key should never be visible to anyone and you should probably run the Webfront and backend on the same machine because it gets transmitted over the 'network' in plaintext.

Any API users (kiosk, phone apps, etc.) will have their own API keys, but these are authorized and checked by the Webfront which then communicates with the backend on their behalf. The only key the backend ever sees is the Service Master Key.

These requests will all have corresponding opcodes documented on the other page which correspond to actions that the webfront desires.

####Information the native server sends to the webfront (State Updates) The only information the webfront gets back from the native server will be in the form of state updates, which are rudimentary key-value tuples of the form <Key>Data</>

Each of these state updates contains the entire state of the fountain as far as the webfront is concerned and they are triggered when the native server receives a certain opcode corresponding to a state update request from the webfront.

These tuples are parsed by the webfront and used to update its internal state tracking, which is then converted into a JSON object to be transmitted to the client.

User Interaction

The fountain state updates will propagate from the webfront to the client's web browser by means of periodic (1Hz or about) Ajax requests from the client, which will then cause the web server to issue a state update request to the native server, update the webfront's state, and then the client will receive this updated state.

We use knockout.js's mapping pluggin to keep naming consistent over the whole chain of events (our 'XML' keys have the same name as the eventual data bindings clientside) and this makes integration of new fields easy.

The actual implementation is just a run-of-the-mill MVVM, but using automatic binding (although you do have to set default values for each data element in core.js).