AMF::Connection(3p)

NAME
AMF::Connection - A simple library to write AMF clients.

SYNOPSIS
  use AMF::Connection;

  my $endpoint = 'http://myserver.com/flex/amf/'; #AMF server/gateway

  my $service = 'myService';
  my $method = 'myMethod';

  my $client = new AMF::Connection( $endpoint );

  $client->setEncoding(3); # use AMF3 default AMF0

  $client->setHTTPCookieJar( HTTP::Cookies->new(file => "/tmp/mycookies.txt", autosave => 1, ignore_discard => 1 ) );

  my @params = ( 'param1', { 'param2' => 'value2' } );
  my $response = $client->call( "$service.$method", \@params );

  if ( $response->is_success ) {
        my $result_object = $response->getData();
        # ...
  } else {
        die "Can not send remote request for $service.$method method on $endpoint\n";
        };

  my @response = $client->callBatch ( { "operation" => $service.$method", "arguments" => \@params }, ... );

DESCRIPTION
I was looking for a simple Perl module to automate data extraction from an existing Flash+Flex/AMS application, and I could not find a decent client implementation. So, this module was born based on available online documentation.

This module has been inspired to SabreAMF PHP implementation of AMF client libraries.

AMF::Connection is meant to provide a simple AMF library to write client applications for invocation of remote services as used by most flex/AIR RIAs.

The module includes basic support for synchronous HTTP/S based RPC request-response access, where the client sends a request to the server to be processed and the server returns a response to the client containing the processing outcome. Data is sent back and forth in AMF binary format (AMFChannel). Other access patterns such as pub/sub and channels transport are out of scope of this inital release.

AMF0 and AMF3 support is provided using the Storable::AMF module. While HTTP/S requestes to the AMF endpoint are carried out using the LWP::UserAgent module. The requests are sent using the HTTP POST method as AMF0 encoded data by default. AMF3 encoding can be set using the setEncoding() method. Simple AMF3 Externalized Object support is provided on returned objects from the server. Objects returned are simply left in bless( { ... }, 'something') form and they could be mapped to local to the client abstractions if needed.

If encoding is set to AMF3 the Flex Messaging framework is used on returned responses content (I.e. objects casted to "flex.messaging.messages.AcknowledgeMessage" and "flex.messaging.messages.ErrorMessage" are returned).

Simple batch requests and responses is provided also.

See the sample usage synopsis above to start using the module.

DATE TYPE SUPPORT
The latest 0.79 version of Storable::AMF added basic date support with the new_date() and perl_date() utilitiy functions. This is just great. Internally an AMF Date Type represents a timestamp in milliseconds since the epoch in UTC ("neutral") timezone, and since Storable::AMF version 0.79 the module shields the user from that by automatically converting Date values to Perl double (number) scalar values. Users which require AMF Date support should import the new_date() and perl_date() date manipulation functions into their code like:

 use Storable::AMF qw(new_date perl_date);

and make sure any date passed to an AMF::Connection as parameter is encoded with new_date().

  OPEN ISSUES AND SHORTCOMINGS
There is still an issue when arbitrary Date structures are returned from an AMF server to an AMF::Connection (E.g. as part of values of structured AMF Objects). In this case, the AMF::Connection does not try to reparse the Perl object structure returned by Storable::AMF (see thaw()), plus the Storable::AMF module thaw() function does simply deserialise AMF Date Type as number (double) of *milli* seconds since the epoch, and the perl_date() function must be called on each returned value instead. The Storable::AMF module author says that there were other issues in enoforcing a conversion (division by 1000) of the AMF server side (and controlled) timestamp values on each thaw() automatically; hopefully future releases of the module will address this problem.

All this means that an AMF::Connection client application can not rely on those Date returned by the server as being Perl timestamps (seconds since the epoch) and will need explicitly call perl_date() or divide the timestamp by 1000 *explicitly*.

  USING OLD Storable::AMF VERSIONS
In older versions (pre 0.79) of Storable::AMF there was no support for the AMF0/AFM3 Date Type, and everything was being passed as string to the server (E.g. "2010-09-22T02:34:00"). Or as double (number) if the date was in timestamp seconds since the epoch. This meant that an AMF::Connection in order to send a date (E.g. as parameter) had to multiply (or divide) by 1000 the timestamp (E.g. for $perl_timestamp=time(); my $amf_timestamp = $perl_timestamp*1000 vs. my $perl_timestamp = $amf_timestamp/1000), plus rely on the AMF server to cast timestamp AMF Numbers to Dates (I.e. which seems to work on most AMF servers in Java which cast Number to java.util.Date() or similar).

MAPPING OBJECTS
By combining the power of Perl bless {}, $package_name syntax and the Storable::AMF freeze()/thaw() interface, it is possible to pass arbitrary structured AMF Objects the corresponding AMF server can interpret. This is possible due a simple Perl object reference to an hash is serialised to an AMF Object and can be mapped back on the server side.

This means that an AMF::Connection application can wrap all ActionScript / Flex AMF Objects around Perl Objects and get them sent; and returned into a Perl object BLOB using the power of Storable::AMF freeze()/thaw().A

For example to send a SearchQueryFx AMF Object to the server an AMF::Connection advanced search call(), the following code could be used:

my $client = new AMF::Connection ( ... );

# ... prepare parameters...

my $searchAMFObject = bless( {
                   'searchId' => $searchId,
                   'startHit' => int($startHit),
                   'searchString' => $searchString,
                   'hitsPerPage' => ($hitsPerPage) ? int($hitsPerPage) : 20,
                   'sortId' => $sortId,
       }, 'com.mycompany.application.flex.data.SearchQueryFx');

my $response = $client->call( "MySearchSevice.searchAdvanced", [ $searchAMFObject ] );

#....

For other Java to ActionScript type mappings possibilities see http://livedocs.adobe.com/blazeds/1/javadoc/flex/messaging/io/amf/ActionMessageOutput.html#writeObject(java.lang.Object)

For PHP gateways at the moment there is not a known/documented way to map client to server objects.

Future versions of AMF::Connection may add a proper configurable factory for application specific ActionScript/Flex object mappings.

METHODS

  new ($endpoint)
Create new AMF::Connection object. An endpoint can be specified as the only parameter. Or set in a second moment with the setEndpoint() method.

  call ($operation, $arguments)
Call the remote service method with given parameters/arguments on the set endpoint and return an AMF::Connection::MessageBody response. Or an array of responses if requsted (wantarray call scope). The $arguments is generally an array reference, but this version of the AMF::Connection code allows other object types too.

  callBatch (@batch)
Call the remote service once in batch. Each element of @batch must be an hash like { "operation" => $operation, "arguments" => $arguments }, where $operation and $arguments are as specified in "call". The commands are called and responses returned in order as in @batch.

  setEndpoint ($endpoint)
Set the AMF service endpoint.

  getEndpoint ()
Return the AMF service endpoint.

  setEncoding ($encoding)
Set the AMF encoding to use.

  getEncoding ()
Return the AMF encoding in use.

  setHTTPProxy ($proxy)
Set the HTTP/S proxy to use. If LWP::Protocol is installed SOCKS proxies are supported.

  getHTTPProxy ()
Return the HTTP/S procy in use if any.

  addHeader ($header[, $value, $required])
Add an AMF AMF::Connection::MessageHeader to the requests. If $header is a string the header value $value and $required flag can be specified.

  addHTTPHeader ($name, $value)
Add an HTTP header to sub-sequent HTTP requests.

  setUserAgent ($ua)
Allow to specify an alternative LWP::UserAgent. The $ua must support the post() method, proxy() and cookie_jar() if necessary.

  setHTTPCookieJar ($cookie_jar)
Allow to specify an alternative HTTP::Cookies jar. By default AMF::Connection keeps cookies into main-memory and the cookie jar is reset when a new connection is created. When a new cookies jar is set, any existing AMF::Connection cookie is copied over.

  getHTTPCookieJar ()
Return the current HTTP::Cookies jar in use.

  setCredentials ($username,$password)
Minimal support for AMF authentication. Password seems to be wanted in clear.

  setInputAMFOptions ($options)
Set input stream parsing options. See Storable::AMF0 for available options.

  setOutputAMFOptions ($options)
Set output stream serialization options. See Storable::AMF0 for available options.

  setAMFOptions ($options)
Set input and output options the same. See Storable::AMF0 for available options.

  getInputAMFOptions ()
Get input stream parsing options.

  getOutputAMFOptions ()
Get output stream serialization options.

CODE
See http://github.com/areggiori/AMF-Connection

SEE ALSO
 AMF::Connection::MessageBody
 Storable::AMF, Storable::AMF0, LWP::UserAgent

 Flex messaging framework / LiveCycle Data Services
  http://livedocs.adobe.com/blazeds/1/javadoc/flex/messaging/io/amf/client/package-summary.html
  http://livedocs.adobe.com/blazeds/1/javadoc/flex/messaging/io/amf/client/AMFConnection.html
  http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/net/NetConnection.html
  http://help.adobe.com/en_US/LiveCycleDataServicesES/3.1/Developing/lcds31_using.pdf
  http://help.adobe.com/en_US/Flex/4.0/AccessingData/flex_4_accessingdata.pdf
  http://www.adobe.com/support/documentation/en/livecycledataservices/documentation.html

 Specifications
  http://download.macromedia.com/pub/labs/amf/amf0_spec_121207.pdf (AMF0)
  http://opensource.adobe.com/wiki/download/attachments/1114283/amf3_spec_05_05_08.pdf (AMF3)

 SabreAMF
  http://code.google.com/p/sabreamf/

AUTHOR
Alberto Attilio Reggiori, <areggiori at cpan dot org>

THANKS
Anatoliy Grishayev for prompt support and developments on Storable::AMF

COPYRIGHT AND LICENSE
Copyright (C) 2010-2011 by Alberto Attilio Reggiori

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.0 or, at your option, any later version of Perl 5 you may have available.