http://www.perlmonks.org?node_id=693747

PetaMem has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks,

I'm writing a class for accessing/modifying trac contents via XML::RPC.

It's working ok when I create or update tickets, wiki etc. I also can get/download attachments. No problem. The problem appears as soon as I try to add attachments to a ticket. It seems base64-encoding the data is not enough. The call to the specific remote procedure gives a "object has no 'data' attribute error":

use XML::RPC; use MIME::Base64; my $xmlrpc = XML::RPC->new('https://user:pass@some.server.com/trac/pro +ject/xmlrpc'); my $result = $xmlrpc->call('ticket.putAttachment', 2, 'Filename', 'Some Description', encode_base64('data, data - it is always th +e data') ); Dumpering $result gives: $VAR1 = { 'faultString' => '\'\'str\' object has no attribute \'data\' +\' while executing \'ticket.putAttachment()\'', 'faultCode' => '2' };
Unfortunately I do not quite understand the XML::RPC documentation and its talk about the CODEREF to create custom data types (which base64 and time seem to be). Has anyone an example of how to achieve feeding trac with binary data? Any help would be greatly appreciated.

Bye
 PetaMem
    All Perl:   MT, NLP, NLU

Replies are listed 'Best First'.
Re: Accessing Trac via XML::RPC
by Corion (Patriarch) on Jun 24, 2008 at 15:12 UTC

    While googling, I found this discussion of the XML RPC Plugin for Trac. I'm not sure how/whether this plugin is the one you use, but it lists the following Python code as sample code:

    import xmlrpclib server = xmlrpclib.ServerProxy("http://athomas:password@localhost:8080 +/trunk/login/xmlrpc") server.wiki.putAttachment('WikiStart/t.py', xmlrpclib.Binary(open('t.p +y').read()))

    So, likely, you can use that Python code to get a sample of what you have to send using XML::RPC. It seems to send a different number of paramters than your scample does, though, so maybe it's the wrong end in the tree.

    From my cursory look at XML::RPC, your approach of simply sending the base64-encoded data should be OK, but maybe you need to replace it by:

    my $result = $xmlrpc->call('ticket.putAttachment', 2, 'Filename', 'Some Description', sub { +{base64 => encode_base64('data, data + - it is always the data')} }, );

    ... which is what the "Custom Types" section at the end of the documentation suggests.

      Corion,
      sub { +{base64 => encode_base64('data, data - it is always the data')} + },

      that actually did the trick. Thank you very much.

      Bye
       PetaMem
          All Perl:   MT, NLP, NLU

Re: Accessing Trac via XML::RPC
by pc88mxer (Vicar) on Jun 24, 2008 at 15:27 UTC
    This example in the XML::RPC documentation:
    my $result = $xmlrpc->call( 'examples.getStateStruct', { state1 => 12, state2 => 28 } );
    may also be written:
    my $result = $xmlrpc->call('examples.getStateStruct', { state1 => sub { {i4 => 12} }, state2 => 28 }
    The i4 designates the XML::RPC data type (4-byte integer).

    This example:

    $xmlrpc->call( 'method_name', { name => sub { {'base64' => encode_base64($data)} } } );
    will add a named parameter called 'name' with a data type of 'base64'. This is a way of passing arbitrary binary data.

    Since perl doesn't have a special way to designate boolean values, you have to do this to pass boolean typed parameters:

    $xmlrpc->call(..., { name => sub { {boolean => $value} } });
    It would be a good idea to make sure that $value is either 0 or 1.

    Here's a succinct overview of XML-RPC data types: http://www.xmlrpc.com/spec

    To learn more about anonymous subroutines (aka CODEREFs), have a look at perldoc perlsub.