NL:Potlatch/Development overview/AMF

From OpenStreetMap Wiki
Jump to: navigation, search

Potlatch maakt gebruik van het AMF (Action Message Format) binair transport formaat om te communiceren tussen de client en de server.

AMF is de standaard Flash client-server communicatie formaat. Een open formaat die al verscheidene jaren geimplementeerd is in PHP, Perl, Ruby etc. Het zou weinig verrassingen moeten bieden aan een ieder die deze als SOAP/RPC heeft gebruikt.

Enkele van de voordelen van AMF zijn:

  • Compact, snel binair formaat
  • Converteerd automatisch variables aan zowel de client als de server kant - geen verdere parsing is nodig
  • De Flash Player groepeert batch verzoeken efficient, daardoor de HTTP overhead minimaliserend

Coderen/decoderen aan de client kant wordt door de Flash Player gedaan, terwijl dit aan de server zijde erg eenvoudig is (maar iets van 120 code regels) en stabiel, dus hoeft het niet te wijzigen.

Hoe het werkt

als de initieele verbinding eenmaal is gelegd, is de communcatie eenvoudig:

  • Potlatch client SWF stuurt een boodschap:
 remote.call('whichways',whichresponder,_root.edge_l,_root.edge_b,_root.edge_r,_root.edge_t,baselong,basey,masterscale);
    • 'whichways' is de naam van de methode (binnen amf_controller.rb) die aangeroepen wordt
    • whichresponder is de functie (binnen de SWF) waarnaar de resultaten verstuurd zouden moeten worden zodra ze klaar zijn
    • _root.edge_l,_root.edge_b,_root.edge_r,_root.edge_t,baselong,basey,masterscale are simply parameters for this method
    • Alle codering naar het AMF binary formaat wordt afgehandeld door de Flash Player
  • Boodschap is ontvangen door amf_controller.rb
    • Decodering van AMF binary formaat wordt afgehandeld door het laatste stukje code (ruwweg vanaf amf_controller.rb#L755 en verder)
    • de amf_controller loopt langs alle verzoeken in deze batch, and voer ze een voor een uit, het resultaat opslaand:
 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))
    • Als laatste worden de resultaten gecodeerd als AMF en teruggestuurd als het HTTP antwoord
  • De Potlatch 'responder' functie (zie boven) wordt aangeroepen met de resultaten
    • Alle decodering van AMF binair formaat wordt afgehandeld door de Flash Player
    • Responder doet wat dan ook maar nodig of gewenst is om te doen!

Voorbeeldje

Om erachter te komen welke ways en nodes zich binnen een bounding box bevinden:

  • De gebruiker schuift de kaart, daarmee de whichWays() functie aanroepend in de SWF (tegen het eind van potlatch.as)
  • Potlatch definieert een responder functie:
 whichresponder=function() {};
 whichresponder.onResult=function(result) {
   _root.whichreceived+=1;
   waylist  =result[0];
   pointlist=result[1];
  • Potlatch roept de remote 'whichways' aan, onderwijl de bounding box en root scale/location als parameters meegevend:
 remote.call('whichways',whichresponder,_root.edge_l,_root.edge_b,_root.edge_r,_root.edge_t,baselong,basey,masterscale);
  • amf_controller.rb ontvangt het verzoek, pakt de binaire data uit, en roept zijn whichways methode aan:
 when 'whichways'; results[index]=putdata(index,whichways(args))
  • De whichways methode vuurt de SQL queries af, verzamelt de resultaten in 'ways' en 'points' arrays, en geeft ze terug:
   ways = waylist.collect {|a| a['wayid'].to_i } # haal een array van way IDs
   [ways,points]
 end
  • Deze worden dan gecodereerd naar AMF binaire data (dat is wat putdata doet) en teruggestuurd als HTTP response
  • Zodra de Flash Player deze ontvangt roept het de responder functie aan die we eerder al definieerden
  • De responder functie werkt zich door de lijst van ways, and vraagt alle op (weer gebruik makend van AMF!) die momenteel niet in het geheugen aanwezig zijn:
 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;
   }
 }