AMF-Connection

 view release on metacpan or  search on metacpan

lib/AMF/Connection.pm  view on Meta::CPAN

package AMF::Connection;

use AMF::Connection::Message;
use AMF::Connection::MessageBody;
use AMF::Connection::OutputStream;
use AMF::Connection::InputStream;

use LWP::UserAgent;
use HTTP::Cookies;

#use Data::Dumper; #for debug

use Carp;
use strict;

our $VERSION = '0.32';

our $HASMD5 = 0;
{
local $@;
eval { require Digest::MD5; };
$HASMD5 = ($@) ? 0 : 1 ;
};

our $HASUUID;
{
local $@;
eval { require Data::UUID; };
$HASUUID = ($@) ? 0 : 1 ;
}

our $HAS_LWP_PROTOCOL_SOCKS;
{
local $@;
eval { require LWP::Protocol::socks };
$HAS_LWP_PROTOCOL_SOCKS = ($@) ? 0 : 1 ;
}

sub new {
	my ($proto, $endpoint) = @_;
        my $class = ref($proto) || $proto;

	my $self = {
		'endpoint' => $endpoint,
		'headers' => [],
		'http_headers' => {},
		'http_cookie_jar' => new HTTP::Cookies(),
		'response_counter' => 0,
		'encoding' => 0, # default is AMF0 encoding
		'ua'	=> new LWP::UserAgent(),
		'append_to_endpoint' => ''
		};

	$self->{'ua'}->cookie_jar( $self->{'http_cookie_jar'} );

        return bless($self, $class);
	};

# plus add paramters, referer, user agent, authentication/credentials ( see also SecureAMFChannel stuff ), 
# plus timezone on retunred dates to pass to de-serializer - see AMF3 spec saying "it is suggested that time zone be queried independnetly as needed" - unelss local DateTime default to right locale!

# we pass the string, and let Storable::AMF to parse the options into a scalar - see Input/OutputStream and Storable::AMF0 documentation

sub setInputAMFOptions {
	my ($class, $options) = @_;

	$class->{'input_amf_options'} = $options;
	};

sub setOutputAMFOptions {
	my ($class, $options) = @_;

	$class->{'output_amf_options'} = $options;
	};

# useful when input and output options are the same
sub setAMFOptions {
	my ($class, $options) = @_;

	$class->setInputAMFOptions ($options);
	$class->setOutputAMFOptions ($options);
	};

sub getInputAMFOptions {
	my ($class) = @_;

	return $class->{'input_amf_options'};
	};

sub getOutputAMFOptions {
	my ($class) = @_;

	return $class->{'output_amf_options'};
	};

lib/AMF/Connection.pm  view on Meta::CPAN


	#print STDERR Dumper( $response )."\n";

	# process AMF response headers
	$class->_process_response_headers( $response );

	my @all = @{ $response->getBodies() };

	# we make sure the main response is always returned first
	return (wantarray) ? @all : $all[0];
	};

# TODO
#
# sub command { } - to send "flex.messaging.messages.CommandMessage" instead
#

sub setCredentials {
	my ($class, $username, $password) = @_;

	$class->addHeader( 'Credentials', { 'userid' => $username,'password' => $password }, 0 );
	};


sub _process_response_headers {
	my ($class,$message) = @_;

	foreach my $header (@{ $message->getHeaders()}) {
		if($header->getName eq 'ReplaceGatewayUrl') { # another way used by server to keep cookies-less sessions
			$class->setEndpoint( $header->getValue )
				unless( ref($header->getValue) );
		} elsif($header->getName eq 'AppendToGatewayUrl') { # generally used for cokies-less sessions E.g. ';jsessionid=99226346ED3FF5296D08146B02ECCA28'
			$class->{'append_to_endpoint'} = $header->getValue
				unless( ref($header->getValue) );
			};
		};
	};

# just an hack to avoid rewrite class mapping local-to-remote and viceversa and make Storable::AMF happy
sub _brew_flex_remoting_message {
	my ($class,$source,$operation,$headers,$body,$destination) = @_;

	return bless( {
		'clientId' => _generateID(),
                'destination' => $destination,
                'messageId' => _generateID(),
                'timestamp' => time() . '00',
                'timeToLive' => 0,
                'headers' => ($headers) ? $headers : {},
                'body' => $body,
                'correlationId' => undef,
                'operation' => $operation,
		'source' => $source # for backwards compatibility - google for it!
                 }, 'flex.messaging.messages.RemotingMessage' );
        };

sub _generateID {
        my $uniqueid;

        if($HASUUID) {
                eval {
                        my $ug = new Data::UUID;
                        $uniqueid = $ug->to_string( $ug->create() );
                        };
        } elsif ($HASMD5) {
                eval {
                        $uniqueid = substr(Digest::MD5::md5_hex(Digest::MD5::md5_hex(time(). {}. rand(). $$)), 0, 32);
                        };
        } else {
                $uniqueid  ="";
                my $length=16;

                my $j;
                for(my $i=0 ; $i< $length ;) {
                        $j = chr(int(rand(127)));

                        if($j =~ /[a-zA-Z0-9]/) {
                                $uniqueid .=$j;
                                $i++;
                                };
                        };
                };

        return $uniqueid;
        };

1;
__END__

=head1 NAME

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

=head1 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 }, ... );

=head1 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.



( run in 2.961 seconds using v1.01-cache-2.11-cpan-98e64b0badf )