Potlatch 1/Development overview/AMF

From OpenStreetMap Wiki
Jump to: navigation, search

Potlatch uses the AMF (Action Message Format) binary transport format to communicate between the client and server.

AMF is Flash's standard client-server communication format. An open format which has been implemented in PHP, Perl, Ruby etc. for several years now, it should pose few surprises to to anyone who has used such as SOAP/RPC.

Among the advantages of AMF are:

  • Compact, fast binary format
  • Automatically converted into variables at both client and server ends - no further parsing required
  • Flash Player efficiently batches requests together, minimising HTTP overhead

Client-side encoding/decoding is done by Flash Player, while the server-side encoding/decoding is simple (just 120 lines or so) and stable, so you won't ever need to change it.

How it works

Once the initial connection has been established, communication is simple:

  • Potlatch client SWF sends a message:
 remote.call('whichways',whichresponder,_root.edge_l,_root.edge_b,_root.edge_r,_root.edge_t,baselong,basey,masterscale);
    • 'whichways' is the name of the method (within amf_controller.rb) being called
    • whichresponder is the function (within the SWF) to which the returned results should be sent, when ready
    • _root.edge_l,_root.edge_b,_root.edge_r,_root.edge_t,baselong,basey,masterscale are simply parameters for this method
    • All encoding into AMF binary format is handled by Flash Player
  • Message is received by amf_controller.rb
    • Decoding from AMF binary format is handled by the short final part of the code (roughly amf_controller.rb#L755 onwards)
    • amf_controller loops through all requests in this batch, and executes each one in turn, storing the results:
 case message
   when 'getpresets'; results[index]=putdata(index,getpresets)
   when 'whichways'; results[index]=putdata(index,whichways(args))
   when 'getway'; results[index]=putdata(index,getway(args))
    • Finally, the results are encoded as AMF and sent back as the HTTP response
  • Potlatch 'responder' function (see above) is called with the results
    • All decoding from AMF binary format is handled by Flash Player
    • Responder does whatever it needs to do!

Example

To find which ways and nodes are in a bounding box:

  • The user pans the map, calling the whichWays() function in the SWF (towards the end of potlatch.as)
  • Potlatch defines a responder function:
 whichresponder=function() {};
 whichresponder.onResult=function(result) {
   _root.whichreceived+=1;
   waylist  =result[0];
   pointlist=result[1];
  • Potlatch then calls the remote 'whichways' call, sending the bounding box and root scale/location as parameters:
 remote.call('whichways',whichresponder,_root.edge_l,_root.edge_b,_root.edge_r,_root.edge_t,baselong,basey,masterscale);
  • amf_controller.rb receives the request, unpacks the binary data, and calls its whichways method:
 when 'whichways'; results[index]=putdata(index,whichways(args))
  • The whichways method issues the SQL queries, getting the results into 'ways' and 'points' arrays, and returns them:
   ways = waylist.collect {|a| a['wayid'].to_i } # get an array of way IDs
   [ways,points]
 end
  • These are encoded into AMF binary data (that's what putdata does) and sent back as the HTTP response
  • When Flash Player receives this, it calls the responder function that we defined earlier
  • The responder function goes through the list of ways, and requests (using AMF again!) any that aren't currently in memory:
 waylist  =result[0];
 pointlist=result[1];
 for (i in waylist) {
   way=waylist[i];
   if (!_root.map.ways[way]) {
     _root.map.ways.attachMovie("way",way,++waydepth);
     _root.map.ways[way].load(way);
     _root.waycount+=1;
     _root.waysrequested+=1;
   }
 }