diff --git a/couchpotato/core/downloaders/rtorrent_.py b/couchpotato/core/downloaders/rtorrent_.py
index d754022..d55c5c4 100644
--- a/couchpotato/core/downloaders/rtorrent_.py
+++ b/couchpotato/core/downloaders/rtorrent_.py
@@ -51,6 +51,32 @@ class rTorrent(DownloaderBase):
self.rt = None
return True
+ def getAuth(self):
+ if not self.conf('username') or not self.conf('password'):
+ # Missing username or password parameter
+ return None
+
+ # Build authentication tuple
+ return (
+ self.conf('authentication'),
+ self.conf('username'),
+ self.conf('password')
+ )
+
+ def getVerifySsl(self):
+ # Ensure verification has been enabled
+ if not self.conf('ssl_verify'):
+ return False
+
+ # Use ca bundle if defined
+ ca_bundle = self.conf('ssl_ca_bundle')
+
+ if ca_bundle and os.path.exists(ca_bundle):
+ return ca_bundle
+
+ # Use default ssl verification
+ return True
+
def connect(self, reconnect = False):
# Already connected?
if not reconnect and self.rt is not None:
@@ -68,15 +94,15 @@ class rTorrent(DownloaderBase):
if parsed.scheme in ['http', 'https']:
url += self.conf('rpc_url')
+ # Construct client
self.rt = RTorrent(
- url,
- self.conf('username'),
- self.conf('password')
+ url, self.getAuth(),
+ verify_ssl=self.getVerifySsl()
)
self.error_msg = ''
try:
- self.rt._verify_conn()
+ self.rt.connection.verify()
except AssertionError as e:
self.error_msg = e.message
self.rt = None
@@ -290,52 +316,88 @@ config = [{
'radio_group': 'torrent',
},
{
- 'name': 'host',
- 'default': 'localhost:80',
- 'description': 'RPC Communication URI. Usually scgi://localhost:5000, '
- 'httprpc://localhost/rutorrent or localhost:80'
- },
- {
'name': 'ssl',
+ 'label': 'SSL Enabled',
+ 'order': 1,
'default': 0,
'type': 'bool',
'advanced': True,
'description': 'Use HyperText Transfer Protocol Secure, or https',
},
{
- 'name': 'rpc_url',
+ 'name': 'ssl_verify',
+ 'label': 'SSL Verify',
+ 'order': 2,
+ 'default': 1,
+ 'type': 'bool',
+ 'advanced': True,
+ 'description': 'Verify SSL certificate on https connections',
+ },
+ {
+ 'name': 'ssl_ca_bundle',
+ 'label': 'SSL CA Bundle',
+ 'order': 3,
'type': 'string',
+ 'advanced': True,
+ 'description': 'Path to a directory (or file) containing trusted certificate authorities',
+ },
+ {
+ 'name': 'host',
+ 'order': 4,
+ 'default': 'localhost:80',
+ 'description': 'RPC Communication URI. Usually scgi://localhost:5000, '
+ 'httprpc://localhost/rutorrent or localhost:80',
+ },
+ {
+ 'name': 'rpc_url',
+ 'order': 5,
'default': 'RPC2',
+ 'type': 'string',
'advanced': True,
'description': 'Change if your RPC mount is at a different path.',
},
{
+ 'name': 'authentication',
+ 'order': 6,
+ 'default': 'basic',
+ 'type': 'dropdown',
+ 'advanced': True,
+ 'values': [('Basic', 'basic'), ('Digest', 'digest')],
+ 'description': 'Authentication method used for http(s) connections',
+ },
+ {
'name': 'username',
+ 'order': 7,
},
{
'name': 'password',
+ 'order': 8,
'type': 'password',
},
{
'name': 'label',
+ 'order': 9,
'description': 'Label to apply on added torrents.',
},
{
'name': 'directory',
+ 'order': 10,
'type': 'directory',
'description': 'Download to this directory. Keep empty for default rTorrent download directory.',
},
{
'name': 'remove_complete',
'label': 'Remove torrent',
+ 'order': 11,
'default': False,
- 'advanced': True,
'type': 'bool',
+ 'advanced': True,
'description': 'Remove the torrent after it finishes seeding.',
},
{
'name': 'delete_files',
'label': 'Remove files',
+ 'order': 12,
'default': True,
'type': 'bool',
'advanced': True,
@@ -343,6 +405,7 @@ config = [{
},
{
'name': 'paused',
+ 'order': 13,
'type': 'bool',
'advanced': True,
'default': False,
@@ -350,6 +413,7 @@ config = [{
},
{
'name': 'manual',
+ 'order': 14,
'default': 0,
'type': 'bool',
'advanced': True,
diff --git a/libs/rtorrent/__init__.py b/libs/rtorrent/__init__.py
index a3f1607..a23640b 100755
--- a/libs/rtorrent/__init__.py
+++ b/libs/rtorrent/__init__.py
@@ -22,13 +22,11 @@ import os.path
import time
import xmlrpclib
+from rtorrent.connection import Connection
from rtorrent.common import find_torrent, join_uri, \
update_uri, is_valid_port, convert_version_tuple_to_str
from rtorrent.lib.torrentparser import TorrentParser
-from rtorrent.lib.xmlrpc.http import HTTPServerProxy
-from rtorrent.lib.xmlrpc.scgi import SCGIServerProxy
from rtorrent.rpc import Method
-from rtorrent.lib.xmlrpc.basic_auth import BasicAuthTransport
from rtorrent.torrent import Torrent
from rtorrent.group import Group
import rtorrent.rpc # @UnresolvedImport
@@ -38,119 +36,28 @@ __author__ = "Chris Lucas"
__contact__ = "chris@chrisjlucas.com"
__license__ = "MIT"
-MIN_RTORRENT_VERSION = (0, 8, 1)
-MIN_RTORRENT_VERSION_STR = convert_version_tuple_to_str(MIN_RTORRENT_VERSION)
-
class RTorrent:
""" Create a new rTorrent connection """
rpc_prefix = None
- def __init__(self, uri, username=None, password=None,
- verify=False, sp=None, sp_kwargs=None):
- self.uri = self._transform_uri(uri) # : From X{__init__(self, url)}
-
- self.username = username
- self.password = password
-
- self.scheme = urllib.splittype(self.uri)[0]
-
- if sp:
- self.sp = sp
- elif self.scheme in ['http', 'https']:
- self.sp = HTTPServerProxy
- elif self.scheme == 'scgi':
- self.sp = SCGIServerProxy
- else:
- raise NotImplementedError()
-
- self.sp_kwargs = sp_kwargs or {}
+ def __init__(self, uri, auth=None, verify_server=False, verify_ssl=True, sp=None, sp_kwargs=None):
+ self.connection = Connection(uri, auth, verify_ssl, sp, sp_kwargs)
self.torrents = [] # : List of L{Torrent} instances
- self._rpc_methods = [] # : List of rTorrent RPC methods
- self._torrent_cache = []
- self._client_version_tuple = ()
-
- if verify is True:
- self._verify_conn()
- def _transform_uri(self, uri):
- scheme = urllib.splittype(uri)[0]
-
- if scheme == 'httprpc' or scheme.startswith('httprpc+'):
- # Try find HTTPRPC transport (token after '+' in 'httprpc+https'), otherwise assume HTTP
- transport = scheme[scheme.index('+') + 1:] if '+' in scheme else 'http'
+ self._torrent_cache = []
- # Transform URI with new path and scheme
- uri = join_uri(uri, 'plugins/httprpc/action.php', construct=False)
- return update_uri(uri, scheme=transport)
+ # Verify connection is valid
+ if verify_server is True:
+ self.connection.verify()
- return uri
+ @property
+ def client(self):
+ return self.connection.client
def _get_conn(self):
- """Get ServerProxy instance"""
-
- if self.username and self.password:
- if self.scheme == 'scgi':
- raise NotImplementedError()
-
- secure = self.scheme == 'https'
-
- return self.sp(
- self.uri,
- transport=BasicAuthTransport(secure, self.username, self.password),
- **self.sp_kwargs
- )
-
- return self.sp(self.uri, **self.sp_kwargs)
-
- def _verify_conn(self):
- # check for rpc methods that should be available
- assert "system.client_version" in self._get_rpc_methods(), "Required RPC method not available."
- assert "system.library_version" in self._get_rpc_methods(), "Required RPC method not available."
-
- # minimum rTorrent version check
- assert self._meets_version_requirement() is True,\
- "Error: Minimum rTorrent version required is {0}".format(
- MIN_RTORRENT_VERSION_STR)
-
- def test_connection(self):
- try:
- self._verify_conn()
- except:
- return False
- return True
-
- def _meets_version_requirement(self):
- return self._get_client_version_tuple() >= MIN_RTORRENT_VERSION
-
- def _get_client_version_tuple(self):
- conn = self._get_conn()
-
- if not self._client_version_tuple:
- if not hasattr(self, "client_version"):
- setattr(self, "client_version",
- conn.system.client_version())
-
- rtver = getattr(self, "client_version")
- self._client_version_tuple = tuple([int(i) for i in
- rtver.split(".")])
-
- return self._client_version_tuple
-
- def _update_rpc_methods(self):
- self._rpc_methods = self._get_conn().system.listMethods()
-
- return self._rpc_methods
-
- def _get_rpc_methods(self):
- """ Get list of raw RPC commands
-
- @return: raw RPC commands
- @rtype: list
- """
-
- return(self._rpc_methods or self._update_rpc_methods())
+ return self.client
def get_torrents(self, view="main"):
"""Get list of all torrents in specified view
@@ -341,7 +248,7 @@ class RTorrent:
assert view is not None, "view parameter required on non-persistent groups"
p.group.insert('', name, view)
- self._update_rpc_methods()
+ self.connection._update_rpc_methods()
def get_group(self, name):
assert name is not None, "group name required"
@@ -424,8 +331,8 @@ def _build_class_methods(class_obj):
def __compare_rpc_methods(rt_new, rt_old):
from pprint import pprint
- rt_new_methods = set(rt_new._get_rpc_methods())
- rt_old_methods = set(rt_old._get_rpc_methods())
+ rt_new_methods = set(rt_new.connection._get_rpc_methods())
+ rt_old_methods = set(rt_old.connection._get_rpc_methods())
print("New Methods:")
pprint(rt_new_methods - rt_old_methods)
print("Methods not in new rTorrent:")
@@ -440,7 +347,7 @@ def __check_supported_methods(rt):
rtorrent.torrent.methods +
rtorrent.tracker.methods +
rtorrent.peer.methods])
- all_methods = set(rt._get_rpc_methods())
+ all_methods = set(rt.connection._get_rpc_methods())
print("Methods NOT in supported methods")
pprint(all_methods - supported_methods)
diff --git a/libs/rtorrent/connection.py b/libs/rtorrent/connection.py
new file mode 100644
index 0000000..a79381c
--- /dev/null
+++ b/libs/rtorrent/connection.py
@@ -0,0 +1,158 @@
+import logging
+import urllib
+
+from rtorrent.common import convert_version_tuple_to_str, join_uri, update_uri
+from rtorrent.lib.xmlrpc.clients.http import HTTPServerProxy
+from rtorrent.lib.xmlrpc.clients.scgi import SCGIServerProxy
+from rtorrent.lib.xmlrpc.transports.basic_auth import BasicAuthTransport
+
+# Try import requests transport (optional)
+try:
+ from rtorrent.lib.xmlrpc.transports.requests_ import RequestsTransport
+except ImportError:
+ RequestsTransport = None
+
+MIN_RTORRENT_VERSION = (0, 8, 1)
+MIN_RTORRENT_VERSION_STR = convert_version_tuple_to_str(MIN_RTORRENT_VERSION)
+
+log = logging.getLogger(__name__)
+
+
+class Connection(object):
+ def __init__(self, uri, auth=None, verify_ssl=True, sp=None, sp_kwargs=None):
+ self.auth = auth
+ self.verify_ssl = verify_ssl
+
+ # Transform + Parse URI
+ self.uri = self._transform_uri(uri)
+ self.scheme = urllib.splittype(self.uri)[0]
+
+ # Construct RPC Client
+ self.sp = self._get_sp(self.scheme, sp)
+ self.sp_kwargs = sp_kwargs or {}
+
+ self._client = None
+ self._client_version_tuple = ()
+ self._rpc_methods = []
+
+ @property
+ def client(self):
+ if self._client is None:
+ # Construct new client
+ self._client = self.connect()
+
+ # Return client
+ return self._client
+
+ def connect(self):
+ log.debug('Connecting to server: %r', self.uri)
+
+ if self.auth:
+ # Construct server proxy with authentication transport
+ return self.sp(self.uri, transport=self._construct_transport(), **self.sp_kwargs)
+
+ # Construct plain server proxy
+ return self.sp(self.uri, **self.sp_kwargs)
+
+ def test(self):
+ try:
+ self.verify()
+ except:
+ return False
+
+ return True
+
+ def verify(self):
+ # check for rpc methods that should be available
+ assert "system.client_version" in self._get_rpc_methods(), "Required RPC method not available."
+ assert "system.library_version" in self._get_rpc_methods(), "Required RPC method not available."
+
+ # minimum rTorrent version check
+ assert self._meets_version_requirement() is True,\
+ "Error: Minimum rTorrent version required is {0}".format(MIN_RTORRENT_VERSION_STR)
+
+ #
+ # Private methods
+ #
+
+ def _construct_transport(self):
+ # Ensure "auth" parameter is valid
+ if type(self.auth) is not tuple or len(self.auth) != 3:
+ raise ValueError('Invalid "auth" parameter format')
+
+ # Construct transport with authentication details
+ method, _, _ = self.auth
+ secure = self.scheme == 'https'
+
+ log.debug('Constructing transport for scheme: %r, authentication method: %r', self.scheme, method)
+
+ # Use requests transport (if available)
+ if RequestsTransport and method in ['basic', 'digest']:
+ return RequestsTransport(
+ secure, self.auth,
+ verify_ssl=self.verify_ssl
+ )
+
+ # Use basic authentication transport
+ if method == 'basic':
+ return BasicAuthTransport(secure, self.auth)
+
+ # Unsupported authentication method
+ if method == 'digest':
+ raise Exception('Digest authentication requires the "requests" library')
+
+ raise NotImplementedError('Unknown authentication method: %r' % method)
+
+ def _get_client_version_tuple(self):
+ if not self._client_version_tuple:
+ if not hasattr(self, "client_version"):
+ setattr(self, "client_version", self.client.system.client_version())
+
+ rtver = getattr(self, "client_version")
+ self._client_version_tuple = tuple([int(i) for i in rtver.split(".")])
+
+ return self._client_version_tuple
+
+ def _get_rpc_methods(self):
+ """ Get list of raw RPC commands
+
+ @return: raw RPC commands
+ @rtype: list
+ """
+
+ return(self._rpc_methods or self._update_rpc_methods())
+
+ @staticmethod
+ def _get_sp(scheme, sp):
+ if sp:
+ return sp
+
+ if scheme in ['http', 'https']:
+ return HTTPServerProxy
+
+ if scheme == 'scgi':
+ return SCGIServerProxy
+
+ raise NotImplementedError()
+
+ def _meets_version_requirement(self):
+ return self._get_client_version_tuple() >= MIN_RTORRENT_VERSION
+
+ @staticmethod
+ def _transform_uri(uri):
+ scheme = urllib.splittype(uri)[0]
+
+ if scheme == 'httprpc' or scheme.startswith('httprpc+'):
+ # Try find HTTPRPC transport (token after '+' in 'httprpc+https'), otherwise assume HTTP
+ transport = scheme[scheme.index('+') + 1:] if '+' in scheme else 'http'
+
+ # Transform URI with new path and scheme
+ uri = join_uri(uri, 'plugins/httprpc/action.php', construct=False)
+ return update_uri(uri, scheme=transport)
+
+ return uri
+
+ def _update_rpc_methods(self):
+ self._rpc_methods = self.client.system.listMethods()
+
+ return self._rpc_methods
diff --git a/libs/rtorrent/lib/xmlrpc/clients/__init__.py b/libs/rtorrent/lib/xmlrpc/clients/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/libs/rtorrent/lib/xmlrpc/http.py b/libs/rtorrent/lib/xmlrpc/clients/http.py
old mode 100755
new mode 100644
similarity index 100%
rename from libs/rtorrent/lib/xmlrpc/http.py
rename to libs/rtorrent/lib/xmlrpc/clients/http.py
diff --git a/libs/rtorrent/lib/xmlrpc/clients/scgi.py b/libs/rtorrent/lib/xmlrpc/clients/scgi.py
new file mode 100644
index 0000000..ade57c5
--- /dev/null
+++ b/libs/rtorrent/lib/xmlrpc/clients/scgi.py
@@ -0,0 +1,152 @@
+#!/usr/bin/python
+
+# rtorrent_xmlrpc
+# (c) 2011 Roger Que
+#
+# Modified portions:
+# (c) 2013 Dean Gardiner
+#
+# 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]
+#
+# 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 urllib
+import xmlrpclib
+
+from rtorrent.lib.xmlrpc.transports.scgi import SCGITransport
+
+
+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 __close(self):
+ self.__transport.close()
+
+ 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 (
+ "" %
+ (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,))
diff --git a/libs/rtorrent/lib/xmlrpc/transports/__init__.py b/libs/rtorrent/lib/xmlrpc/transports/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/libs/rtorrent/lib/xmlrpc/basic_auth.py b/libs/rtorrent/lib/xmlrpc/transports/basic_auth.py
similarity index 100%
rename from libs/rtorrent/lib/xmlrpc/basic_auth.py
rename to libs/rtorrent/lib/xmlrpc/transports/basic_auth.py
diff --git a/libs/rtorrent/lib/xmlrpc/transports/requests_.py b/libs/rtorrent/lib/xmlrpc/transports/requests_.py
new file mode 100644
index 0000000..779b744
--- /dev/null
+++ b/libs/rtorrent/lib/xmlrpc/transports/requests_.py
@@ -0,0 +1,91 @@
+import requests
+import requests.auth
+import xmlrpclib
+
+
+class RequestsTransport(xmlrpclib.Transport):
+ def __init__(self, secure, auth=None, proxies=None, verify_ssl=True):
+ xmlrpclib.Transport.__init__(self)
+
+ self.secure = secure
+
+ # Construct session
+ self.session = requests.Session()
+ self.session.auth = self.parse_auth(auth)
+ self.session.proxies = proxies or {}
+ self.session.verify = verify_ssl
+
+ @property
+ def scheme(self):
+ if self.secure:
+ return 'https'
+
+ return 'http'
+
+ def build_url(self, host, handler):
+ return '%s://%s' % (self.scheme, host + handler)
+
+ def request(self, host, handler, request_body, verbose=0):
+ # Retry request once if cached connection has gone cold
+ for i in (0, 1):
+ try:
+ return self.single_request(host, handler, request_body, verbose)
+ except requests.ConnectionError:
+ if i:
+ raise
+ except requests.Timeout:
+ if i:
+ raise
+
+ def single_request(self, host, handler, request_body, verbose=0):
+ url = self.build_url(host, handler)
+
+ # Send request
+ response = self.session.post(
+ url,
+ data=request_body,
+ headers={
+ 'Content-Type': 'text/xml'
+ },
+ stream=True
+ )
+
+ if response.status_code == 200:
+ return self.parse_response(response)
+
+ # Invalid response returned
+ raise xmlrpclib.ProtocolError(
+ host + handler,
+ response.status_code, response.reason,
+ response.headers
+ )
+
+ def parse_auth(self, auth):
+ # Parse "auth" parameter
+ if type(auth) is not tuple or len(auth) != 3:
+ return None
+
+ method, username, password = auth
+
+ # Basic Authentication
+ if method == 'basic':
+ return requests.auth.HTTPBasicAuth(username, password)
+
+ # Digest Authentication
+ if method == 'digest':
+ return requests.auth.HTTPDigestAuth(username, password)
+
+ raise NotImplementedError('Unsupported authentication method: %r' % method)
+
+ def parse_response(self, response):
+ p, u = self.getparser()
+
+ # Write chunks to parser
+ for chunk in response.iter_content(1024):
+ p.feed(chunk)
+
+ # Close parser
+ p.close()
+
+ # Close unmarshaller
+ return u.close()
diff --git a/libs/rtorrent/lib/xmlrpc/scgi.py b/libs/rtorrent/lib/xmlrpc/transports/scgi.py
similarity index 74%
rename from libs/rtorrent/lib/xmlrpc/scgi.py
rename to libs/rtorrent/lib/xmlrpc/transports/scgi.py
index 5ba61fa..e63b0db 100644
--- a/libs/rtorrent/lib/xmlrpc/scgi.py
+++ b/libs/rtorrent/lib/xmlrpc/transports/scgi.py
@@ -28,12 +28,12 @@
# 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
@@ -81,12 +81,13 @@
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
+
+import errno
import httplib
import re
import socket
import urllib
import xmlrpclib
-import errno
class SCGITransport(xmlrpclib.Transport):
@@ -152,68 +153,3 @@ class SCGITransport(xmlrpclib.Transport):
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 __close(self):
- self.__transport.close()
-
- 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 (
- "" %
- (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,))
diff --git a/libs/rtorrent/rpc/__init__.py b/libs/rtorrent/rpc/__init__.py
index 116ca1c..607d409 100755
--- a/libs/rtorrent/rpc/__init__.py
+++ b/libs/rtorrent/rpc/__init__.py
@@ -45,7 +45,7 @@ def get_varname(rpc_call):
def _handle_unavailable_rpc_method(method, rt_obj):
msg = "Method isn't available."
- if rt_obj._get_client_version_tuple() < method.min_version:
+ if rt_obj.connection._get_client_version_tuple() < method.min_version:
msg = "This method is only available in " \
"RTorrent version v{0} or later".format(
convert_version_tuple_to_str(method.min_version))
@@ -108,8 +108,8 @@ class Method:
return(False)
def is_available(self, rt_obj):
- if rt_obj._get_client_version_tuple() < self.min_version or \
- self.rpc_call not in rt_obj._get_rpc_methods():
+ if rt_obj.connection._get_client_version_tuple() < self.min_version or \
+ self.rpc_call not in rt_obj.connection._get_rpc_methods():
return(False)
else:
return(True)