Ruby xml-talking to rtorrent

I haven’t had very much time to write some ruby code to communicate with rtorrent through the local domain socket. But i got something that starts to work.

The main problem is that Ruby XMLRPC library is unfriendly with user with special needs. There is no way to get the xml data, send it the way i want and get it back and let the library parse it!
To solve this i had to modify the library, with a patch that when is ready i’ll subit to the ruby developers.
I have added a class that represents a socket factory! the easy way to solve the problem. In less then 30 lines it just works. There is a new method to initialize the Client class too, and even the hashed (new3) method will work if the field socket is specified.

  class SocketFactory
      def issue() # returns a new socket to be used with the library
          raise "This class must be subclassed"
      end
  end
  def new4( socket )
      self.new(nil,nil,nil,nil,nil,nil,nil,nil,nil,socket)
  end
  alias new_with_socket new4

After these modifications to the initialization code i had to modify the private method do_rpc adding this at the beginning of the method

      data = nil
      if @socket != nil then # using user socket
          # must do the same things, send the same things
          # but to the socket! not to a http/https server
          sock = @socket.issue()
          if sock.write(request) != request.length then
              raise "Not all the data has been sent"
          end
          # read the whole data until the socket is closed
          data = sock.read()
          # after any answer the socket is closed
          return data # return data to the parser
      else

and an end just after the return statement of the original method. There is an additional check to verify that the socket object is a subclass of the SocketFactory class.

I wrote a simple socket factory to test the communications with rtorrent itself in the real world. I had to write to it using the SCGI protocol, which obviously is supported in ruby, but it doesn’t support local domain socket, for no real reasons, since it is indistinguishable from any other kind of socket, but that was the statement in rdoc

One thing that SCGI doesn‘t support is using UNIX Domain sockets in addition to TCP/IP sockets. This isn‘t really needed, but it is handy in a shared hosting situation where you don‘t want others connecting to your processes or if you have to request open ports. Sorry, no UNIX Domain sockets in SCGI.

It’s crazy… so i wrote a simple scgi wrapper. which is incredibly simple

    def self.wrap( content, uri, method="POST" )
        null=""
        header = "CONTENT_LENGTH #{content.length} SCGI#{null}1
                  REQUEST_METHOD #{method} REQUEST_URI #{uri} "
        return "#{header.length}:#{header},#{content}"
    end

There are some missing chars (many “\0”), in the string header and the null string are just “\0”, but can’t be shown here as in any my previous post, the files in the git repository are ok.

To use this wrapper i have to write a socket factory that will create sockets that will wrap the xmldata in a scgi header.
So i wrote a class SCGIFactory, which is still incomplete (no error checking) but is working.

    def issue()
        if @method != nil
            SCGIWrappedSocket.new(UNIXSocket.new(@path),@uri,@method)
        else
            SCGIWrappedSocket.new(UNIXSocket.new(@path),@uri)
        end
    end
    def write(x)
        @sock.write(SCGI.wrap(x,@uri,@method))
    end 

    def read()
        data = @sock.read()
        # receiving an html response (very dumb parsing)
        # divide in 2
        # 1 -> status + headers
        # 2 -> data
        return data.split("\r\n\r\n").last
    end

As you can see the read method need many enhancements. I need a way to parse http data from a string in any default library, but no default library do this. If anybody knows hot to do that, please tell me.

I wrote this test

require 'xmlrpc/client'
require 'SCGIFactory'

f=SCGIFactory::Unix.new("/rtorrent.sock","/RPC2")
c=XMLRPC::Client.new_with_socket(f)
puts "#{c.call("system.listMethods")}"

And I can get the whole list of the supported methods directly from the program itself

All the code is available in a git repository, different from the ruby upnp one.. Git repository can be found in the code page

[Continued by: XMLRPC sockets changes]

Advertisements

, , , , , ,

  1. #1 by hydraulic floor jacks on March 14, 2009 - 2:40 pm

    This is the first time I comment here and I must say you give genuine, and quality information for bloggers! Good job.
    p.s. You have a very good template for your blog. Where have you got it from?

    • #2 by Dario on March 14, 2009 - 2:48 pm

      Thanks.
      The theme shoul be kubrik or something like that. It’s one of the wordpress.com available themes

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: