AMF-Connection

 view release on metacpan or  search on metacpan

examples/amfclient.pl  view on Meta::CPAN

$json->ascii(1);
$json->utf8(1);
$json->pretty(1);
$json->allow_blessed(1);
$json->convert_blessed(1);
my $json_data = $json->encode( $response->getData );

if ( $response->is_success ) {
        print $json_data;
} else {
        die "Can not send remote request for $service.$method method with params on $endpoint using AMF".$client->getEncoding()." encoding:\n".$json_data."\n";
        };

examples/get-brightcove-videos-metadata.pl  view on Meta::CPAN


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

# $client->config( ... ); # LWP::UserAgent extra params (proxy, auth etc... )

#$client->setEncoding(3);
#$client->setHTTPProxy('http://127.0.0.1:8888');
#$client->setHTTPCookieJar( HTTP::Cookies->new(file => "/tmp/lwpcookies.txt", autosave => 1, ignore_discard => 1 ) );

# eg taken from http://link.brightcove.com/services/player/bcpid34762914001?bctid=672454611001
# works only with AMF0 encoding - at least it seems so - because using openamf ?
#
my $player_id = '34762914001';
my $videoId = '672454611001';

my $params = [
                                                       $player_id, # param 1 - playerId
                                                       {
                                                         'fetchInfos' => [
                                                                           {
                                                                             'fetchLevelEnum' => '1',

examples/get-brightcove-videos-metadata.pl  view on Meta::CPAN

$json->ascii(1);
$json->utf8(1);
$json->pretty(1);
$json->allow_blessed(1);
$json->convert_blessed(1);
my $json_data = $json->encode( $response->getData );

if ( $response->is_success ) {
	print $json_data;
} else {
	die "Can not send remote request for $service.$method method with params on $endpoint using AMF".$client->getEncoding()." encoding:\n".$json_data."\n";
	};

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

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 ), 

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

	$class->{'ua'}->proxy( [qw(http https)] => $class->{'http_proxy'} );
	};

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

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

sub setEncoding {
	my ($class, $encoding) = @_;

	croak "Unsupported AMF encoding $encoding"
		unless( $encoding==0 or $encoding==3 );

	$class->{'encoding'} = $encoding;
	};

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

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

sub addHeader {
	my ($class, $header, $value, $required) = @_;

	if( ref($header) ) {
		croak "Not a valid header $header"
			unless( $header->isa("AMF::Connection::MessageHeader") );
	} else {
		$header = new AMF::Connection::MessageHeader( $header, $value, ($required==1) ? 1 : 0  );

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

					"arguments" => $arguments,
					"destination" => $destination });

	return (wantarray) ? @call : $call[0];
	};

sub callBatch {
	my ($class, @batch) = @_;

	my $request = new AMF::Connection::Message;
	$request->setEncoding( $class->{'encoding'} );

	# add AMF any request headers
	map { $request->addHeader( $_ ); } @{ $class->{'headers'} };

	# TODO - prepare HTTP/S request headers based on AMF headers received/set if any - and credentials

	foreach my $call (@batch)
          {
	    next
              unless (defined $call && ref ($call) =~ m/HASH/
		      && defined $call->{'operation'} && defined $call->{'arguments'});

	    my $operation = $call->{'operation'};
	    my $arguments = $call->{'arguments'};

	    my $body = new AMF::Connection::MessageBody;
	    $class->{'response_counter'}++;
	    $body->setResponse( "/".$class->{'response_counter'} );

	    if( $class->{'encoding'} == 3 ) { # AMF3
		$body->setTarget( 'null' );

		my (@operation) = split('\.',$operation);
		my $method = pop @operation;
		my $service = join('.',@operation);
		my $destination = (defined $call->{'destination'}) ? $call->{'destination'} : $service;

		my $remoting_message = $class->_brew_flex_remoting_message( $service, $method, {}, $arguments, $destination);

		$body->setData( [ $remoting_message ] ); # it seems we need array ref here - to be checked

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

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

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

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 encod...

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.

=head1 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") timezo...

 use Storable::AMF qw(new_date perl_date);

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

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 C<call>. The commands are called and responses returned i...

=head2 setEndpoint ($endpoint)

Set the AMF service endpoint.

=head2 getEndpoint ()

Return the AMF service endpoint.

=head2 setEncoding ($encoding)

Set the AMF encoding to use.

=head2 getEncoding ()

Return the AMF encoding in use.

=head2 setHTTPProxy ($proxy)

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

=head2 getHTTPProxy ()

Return the HTTP/S procy in use if any.

=head2 addHeader ($header[, $value, $required])

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

	my ($class) = @_;

	my $type = $class->readByte();

	# Storable::AMF will take care of deparsing the right AMF format
	$class->{'cursor'}--;

	local $@ = undef;

        my ($obj, $len);
	my $encoding=0;
	if($type == 0x11) {
		$encoding=3;
		$class->{'cursor'}++;
		if ($storable_with_options  == 0
		    || not defined $class->{'options'})
		  {
        	    ($obj, $len) = Storable::AMF3::deparse_amf( substr($class->{'stream'},$class->{'cursor'}));
		  }
  		else
		  {
        	    ($obj, $len) = Storable::AMF3::deparse_amf( substr($class->{'stream'},$class->{'cursor'}), $class->{'options'});
		  }

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

		    || not defined $class->{'options'})
		  {
        	    ($obj, $len) = Storable::AMF0::deparse_amf( substr($class->{'stream'},$class->{'cursor'}));
		  }
		else
		  {
        	    ($obj, $len) = Storable::AMF0::deparse_amf( substr($class->{'stream'},$class->{'cursor'}), $class->{'options'});
		  }
		};

	croak "Can not read AMF".$encoding." data starting from position ".$class->{'cursor'}." of input - reason: ".$@ ."\n"
		if($@);

	if(defined $obj) {
		$class->{'cursor'}+=$len
			unless( $len + $class->{'cursor'} > length($class->{'stream'}) );	
		};

	return $obj;
	};

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

use AMF::Connection::InputStream;

use AMF::Connection::MessageBody;
use AMF::Connection::MessageHeader;

sub new {
	my $proto = shift;
	my $class = ref($proto) || $proto;
	
	my $self = {
		'encoding' => 0, # default is AMF0 encoding
		'bodies' => [],
		'headers' => []
		};

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

sub serialize {
	my ($class, $stream) = @_;

	croak "Stream $stream is not a valid output stream"
		unless(ref($stream) and $stream->isa("AMF::Connection::OutputStream"));

	# we default to AMF0 encoding
	$stream->writeByte(0x00);
	$stream->writeByte($class->getEncoding());

	$stream->writeInt(scalar(@{$class->{'headers'}}));
	foreach my $header (@{$class->{'headers'}}) {
		my $name =$header->getName();
		$stream->writeInt(length($name));
		$stream->writeBuffer($name);

		$stream->writeByte($header->isRequired());

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

	}; 

sub deserialize {
	my ($class, $stream) = @_;

	$class->{'headers'} = [];
	$class->{'bodies'} = [];

        $stream->readByte();

        my $sent_encoding = $stream->readByte();
	# need to make AMF1 returned encoding the same as AMF0 - see more about the bug at http://balazs.sebesteny.com/footprints-in-blazeds/
        $class->setEncoding( ( $sent_encoding!=0 and $sent_encoding!=3 ) ? 0 : $sent_encoding );

        my $totalHeaders = $stream->readInt();
	for(my $i=0;$i<$totalHeaders;$i++) {
		my $header = new AMF::Connection::MessageHeader();

		my $strLen = $stream->readInt();
		$header->setName( $stream->readBuffer($strLen) );

		$header->setRequired( $stream->readByte() );

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

	my $totalBodies = $stream->readInt();
	for(my $i=0;$i<$totalBodies;$i++) {
		my $body = new AMF::Connection::MessageBody();

		my $strLen = $stream->readInt();
		$body->setTarget( $stream->readBuffer($strLen) );

		$strLen = $stream->readInt();
		$body->setResponse( $stream->readBuffer($strLen) );

		# TODO - make sure we deal properly with avm+ object marker stuff here - and have message containing multiple encodings
                $stream->readLong();
		$body->setData( $stream->readAMFData() ); # we deparse the next read value out

                $class->addBody( $body );
		};
	}; 

sub addBody {
	my ($class, $body) = @_;

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

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

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

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

sub setEncoding {
        my ($class, $encoding) = @_;

	croak "Unsupported AMF encoding $encoding"
		unless( $encoding==0 or $encoding==3 );

        $class->{'encoding'} = $encoding;
        };

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

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


1;
__END__

=head1 NAME

AMF::Connection::Message - Encapsulates a request or response protocol packet/message

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

	};

sub getStreamData {
	my ($class) = @_;
	
	return $class->{'stream'};
	};

# wrtie an AMF entity
sub writeAMFData {
        my ($class,$encoding,$data) = @_;

	local $@ = undef;

	my $bytes;
        if($encoding == 3 ) {
		if ($storable_with_options  == 0
		    || not defined $class->{'options'})
                  {
		    $bytes = Storable::AMF3::freeze($data);
		  }
		else
		  {
		    $bytes = Storable::AMF3::freeze($data, $class->{'options'});
		  }
		$class->writeByte(0x11);

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

		    || not defined $class->{'options'})
                  {
		    $bytes = Storable::AMF0::freeze($data);
		  }
		else
		  {
		    $bytes = Storable::AMF0::freeze($data, $class->{'options'});
		  }
                };

	croak "Can not write AMF".$encoding." data starting from position ".$class->{'cursor'}." of input - reason: ".$@ ."\n"
		if($@);

	$class->writeBuffer($bytes);
        };

1;
__END__

=head1 NAME



( run in 0.266 second using v1.01-cache-2.11-cpan-a5abf4f5562 )