Skip to content

Instantly share code, notes, and snippets.

@query
Created April 2, 2011 17:25
Show Gist options
  • Select an option

  • Save query/899683 to your computer and use it in GitHub Desktop.

Select an option

Save query/899683 to your computer and use it in GitHub Desktop.

Revisions

  1. query revised this gist Apr 3, 2011. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion rtorrent_xmlrpc.py
    Original file line number Diff line number Diff line change
    @@ -96,7 +96,7 @@ def single_request(self, host, handler, request_body, verbose=0):

    try:
    if host:
    host, port = urllib.splitport(netloc)
    host, port = urllib.splitport(host)
    addrinfo = socket.getaddrinfo(host, port, socket.AF_INET,
    socket.SOCK_STREAM)
    sock = socket.socket(*addrinfo[0][:3])
    @@ -153,6 +153,9 @@ def __init__(self, uri, transport=None, encoding=None, verbose=False,
    self.__encoding = encoding
    self.__verbose = verbose
    self.__allow_none = allow_none

    def __close(self):
    self.__transport.close()

    def __request(self, methodname, params):
    # call a method on the remote server
  2. query created this gist Apr 2, 2011.
    198 changes: 198 additions & 0 deletions rtorrent_xmlrpc.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,198 @@
    #!/usr/bin/python

    # rtorrent_xmlrpc
    # (c) 2011 Roger Que <[email protected]>
    #
    # Python module for interacting with rtorrent's XML-RPC interface
    # directly over SCGI, instead of through an HTTP server intermediary.
    # Inspired by Glenn Washburn's xmlrpc2scgi.py [1], but subclasses the
    # built-in xmlrpclib classes so that it is compatible with features
    # such as MultiCall objects.
    #
    # [1] <http://libtorrent.rakshasa.no/wiki/UtilsXmlrpc2scgi>
    #
    # Usage: server = SCGIServerProxy('scgi://localhost:7000/')
    # server = SCGIServerProxy('scgi:///path/to/scgi.sock')
    # print server.system.listMethods()
    # mc = xmlrpclib.MultiCall(server)
    # mc.get_up_rate()
    # mc.get_down_rate()
    # print mc()
    #
    #
    #
    # This program is free software; you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation; either version 2 of the License, or
    # (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program; if not, write to the Free Software
    # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    #
    # In addition, as a special exception, the copyright holders give
    # permission to link the code of portions of this program with the
    # OpenSSL library under certain conditions as described in each
    # individual source file, and distribute linked combinations
    # including the two.
    #
    # You must obey the GNU General Public License in all respects for
    # all of the code used other than OpenSSL. If you modify file(s)
    # with this exception, you may extend this exception to your version
    # of the file(s), but you are not obligated to do so. If you do not
    # wish to do so, delete this exception statement from your version.
    # If you delete this exception statement from all source files in the
    # program, then also delete it here.
    #
    #
    #
    # Portions based on Python's xmlrpclib:
    #
    # Copyright (c) 1999-2002 by Secret Labs AB
    # Copyright (c) 1999-2002 by Fredrik Lundh
    #
    # By obtaining, using, and/or copying this software and/or its
    # associated documentation, you agree that you have read, understood,
    # and will comply with the following terms and conditions:
    #
    # Permission to use, copy, modify, and distribute this software and
    # its associated documentation for any purpose and without fee is
    # hereby granted, provided that the above copyright notice appears in
    # all copies, and that both that copyright notice and this permission
    # notice appear in supporting documentation, and that the name of
    # Secret Labs AB or the author not be used in advertising or publicity
    # pertaining to distribution of the software without specific, written
    # prior permission.
    #
    # SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
    # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
    # ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
    # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
    # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
    # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
    # OF THIS SOFTWARE.

    import re
    import socket
    import urllib
    import xmlrpclib


    class SCGITransport(xmlrpclib.Transport):
    def single_request(self, host, handler, request_body, verbose=0):
    # Add SCGI headers to the request.
    headers = {'CONTENT_LENGTH': str(len(request_body)), 'SCGI': '1'}
    header = '\x00'.join(('%s\x00%s' % item for item in headers.iteritems())) + '\x00'
    header = '%d:%s' % (len(header), header)
    request_body = '%s,%s' % (header, request_body)

    sock = None

    try:
    if host:
    host, port = urllib.splitport(netloc)
    addrinfo = socket.getaddrinfo(host, port, socket.AF_INET,
    socket.SOCK_STREAM)
    sock = socket.socket(*addrinfo[0][:3])
    sock.connect(addrinfo[0][4])
    else:
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.connect(handler)

    self.verbose = verbose

    sock.send(request_body)
    return self.parse_response(sock.makefile())
    finally:
    if sock:
    sock.close()

    def parse_response(self, response):
    p, u = self.getparser()

    response_body = ''
    while True:
    data = response.read(1024)
    if not data:
    break
    response_body += data

    # Remove SCGI headers from the response.
    response_header, response_body = re.split(r'\n\s*?\n', response_body,
    maxsplit=1)

    if self.verbose:
    print 'body:', repr(response_body)

    p.feed(response_body)
    p.close()

    return u.close()


    class SCGIServerProxy(xmlrpclib.ServerProxy):
    def __init__(self, uri, transport=None, encoding=None, verbose=False,
    allow_none=False, use_datetime=False):
    type, uri = urllib.splittype(uri)
    if type not in ('scgi'):
    raise IOError('unsupported XML-RPC protocol')
    self.__host, self.__handler = urllib.splithost(uri)
    if not self.__handler:
    self.__handler = '/'

    if transport is None:
    transport = SCGITransport(use_datetime=use_datetime)
    self.__transport = transport

    self.__encoding = encoding
    self.__verbose = verbose
    self.__allow_none = allow_none

    def __request(self, methodname, params):
    # call a method on the remote server

    request = xmlrpclib.dumps(params, methodname, encoding=self.__encoding,
    allow_none=self.__allow_none)

    response = self.__transport.request(
    self.__host,
    self.__handler,
    request,
    verbose=self.__verbose
    )

    if len(response) == 1:
    response = response[0]

    return response

    def __repr__(self):
    return (
    "<SCGIServerProxy for %s%s>" %
    (self.__host, self.__handler)
    )

    __str__ = __repr__

    def __getattr__(self, name):
    # magic method dispatcher
    return xmlrpclib._Method(self.__request, name)

    # note: to call a remote object with an non-standard name, use
    # result getattr(server, "strange-python-name")(args)

    def __call__(self, attr):
    """A workaround to get special attributes on the ServerProxy
    without interfering with the magic __getattr__
    """
    if attr == "close":
    return self.__close
    elif attr == "transport":
    return self.__transport
    raise AttributeError("Attribute %r not found" % (attr,))