218 lines
5.0 KiB
Perl
218 lines
5.0 KiB
Perl
package XML::RPC;
|
|
|
|
use strict;
|
|
use XML::TreePP;
|
|
use Data::Dumper;
|
|
use vars qw($VERSION $faultCode);
|
|
no strict 'refs';
|
|
|
|
$VERSION = 0.5;
|
|
|
|
sub new {
|
|
my $package = shift;
|
|
my $self = { };
|
|
bless $self, $package;
|
|
$self->{url} = shift;
|
|
$self->{tpp} = XML::TreePP->new(@_);
|
|
return $self;
|
|
}
|
|
|
|
sub call {
|
|
my $self = shift;
|
|
my ( $methodname, @params ) = @_;
|
|
|
|
die 'no url' if ( !$self->{url} );
|
|
|
|
$faultCode = 0;
|
|
my $xml = $self->create_call_xml( $methodname, @params );
|
|
#print STDERR $xml;
|
|
my $result = $self->{tpp}->parsehttp(
|
|
POST => $self->{url},
|
|
$xml,
|
|
{
|
|
'Content-Type' => 'text/xml',
|
|
'User-Agent' => 'XML-RPC/' . $VERSION,
|
|
'Content-Length' => length($xml)
|
|
}
|
|
);
|
|
|
|
my @data = $self->unparse_response($result);
|
|
return @data == 1 ? $data[0] : @data;
|
|
}
|
|
|
|
sub receive {
|
|
my $self = shift;
|
|
my $result = eval {
|
|
my $xml = shift || die 'no xml';
|
|
my $handler = shift || die 'no handler';
|
|
my $hash = $self->{tpp}->parse($xml);
|
|
my ( $methodname, @params ) = $self->unparse_call($hash);
|
|
$self->create_response_xml( $handler->( $methodname, @params ) );
|
|
};
|
|
return $self->create_fault_xml($@) if ($@);
|
|
return $result;
|
|
|
|
}
|
|
|
|
sub create_fault_xml {
|
|
my $self = shift;
|
|
my $error = shift;
|
|
chomp($error);
|
|
return $self->{tpp}
|
|
->write( { methodResponse => { fault => $self->parse( { faultString => $error, faultCode => $faultCode } ) } } );
|
|
}
|
|
|
|
sub create_call_xml {
|
|
my $self = shift;
|
|
my ( $methodname, @params ) = @_;
|
|
|
|
return $self->{tpp}->write(
|
|
{
|
|
methodCall => {
|
|
methodName => $methodname,
|
|
params => { param => [ map { $self->parse($_) } @params ] }
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
sub create_response_xml {
|
|
my $self = shift;
|
|
my @params = @_;
|
|
|
|
return $self->{tpp}->write( { methodResponse => { params => { param => [ map { $self->parse($_) } @params ] } } } );
|
|
}
|
|
|
|
sub parse {
|
|
my $self = shift;
|
|
my $p = shift;
|
|
my $result;
|
|
|
|
if ( ref($p) eq 'HASH' ) {
|
|
$result = $self->parse_struct($p);
|
|
}
|
|
elsif ( ref($p) eq 'ARRAY' ) {
|
|
$result = $self->parse_array($p);
|
|
}
|
|
else {
|
|
$result = $self->parse_scalar($p);
|
|
}
|
|
|
|
return { value => $result };
|
|
}
|
|
|
|
sub parse_scalar {
|
|
my $self = shift;
|
|
my $scalar = shift;
|
|
local $^W = undef;
|
|
|
|
if ( ( $scalar =~ m/^[\-+]?\d+$/ )
|
|
&& ( abs($scalar) <= ( 0xffffffff >> 1 ) ) )
|
|
{
|
|
return { i4 => $scalar };
|
|
}
|
|
elsif ( $scalar =~ m/^[\-+]?\d+\.\d+$/ ) {
|
|
return { double => $scalar };
|
|
}
|
|
else {
|
|
return { string => \$scalar };
|
|
}
|
|
}
|
|
|
|
sub parse_struct {
|
|
my $self = shift;
|
|
my $hash = shift;
|
|
my @members;
|
|
while ( my ( $k, $v ) = each(%$hash) ) {
|
|
push @members, { name => $k, %{ $self->parse($v) } };
|
|
}
|
|
return { struct => { member => \@members } };
|
|
}
|
|
|
|
sub parse_array {
|
|
my $self = shift;
|
|
my $array = shift;
|
|
|
|
return { array => { data => { value => [ map { $self->parse($_)->{value} } $self->list($array) ] } } };
|
|
}
|
|
|
|
sub unparse_response {
|
|
my $self = shift;
|
|
my $hash = shift;
|
|
|
|
my $response = $hash->{methodResponse} || die 'no data';
|
|
|
|
if ( $response->{fault} ) {
|
|
return $self->unparse_value( $response->{fault}->{value} );
|
|
}
|
|
else {
|
|
return map { $self->unparse_value( $_->{value} ) } $self->list( $response->{params}->{param} );
|
|
}
|
|
}
|
|
|
|
sub unparse_call {
|
|
my $self = shift;
|
|
my $hash = shift;
|
|
|
|
my $response = $hash->{methodCall} || die 'no data';
|
|
|
|
my $methodname = $response->{methodName};
|
|
my @args =
|
|
map { $self->unparse_value( $_->{value} ) } $self->list( $response->{params}->{param} );
|
|
return ( $methodname, @args );
|
|
}
|
|
|
|
sub unparse_value {
|
|
my $self = shift;
|
|
my $value = shift;
|
|
my $result;
|
|
|
|
return $value if ( ref($value) ne 'HASH' ); # for unspecified params
|
|
if ( $value->{struct} ) {
|
|
$result = $self->unparse_struct( $value->{struct} );
|
|
return !%$result
|
|
? undef
|
|
: $result; # fix for empty hashrefs from XML::TreePP
|
|
}
|
|
elsif ( $value->{array} ) {
|
|
return $self->unparse_array( $value->{array} );
|
|
}
|
|
else {
|
|
return $self->unparse_scalar($value);
|
|
}
|
|
}
|
|
|
|
sub unparse_scalar {
|
|
my $self = shift;
|
|
my $scalar = shift;
|
|
my ($result) = values(%$scalar);
|
|
return ( ref($result) eq 'HASH' && !%$result )
|
|
? undef
|
|
: $result; # fix for empty hashrefs from XML::TreePP
|
|
}
|
|
|
|
sub unparse_struct {
|
|
my $self = shift;
|
|
my $struct = shift;
|
|
|
|
return { map { $_->{name} => $self->unparse_value( $_->{value} ) } $self->list( $struct->{member} ) };
|
|
}
|
|
|
|
sub unparse_array {
|
|
my $self = shift;
|
|
my $array = shift;
|
|
my $data = $array->{data};
|
|
|
|
return [ map { $self->unparse_value($_) } $self->list( $data->{value} ) ];
|
|
}
|
|
|
|
sub list {
|
|
my $self = shift;
|
|
my $param = shift;
|
|
return () if ( !$param );
|
|
return @$param if ( ref($param) eq 'ARRAY' );
|
|
return ($param);
|
|
}
|
|
|
|
1;
|