def _http_query(self, query, timeout=None): """ Query Transmission through HTTP. """ headers = {'x-transmission-session-id': str(self.session_id)} result = {} request_count = 0 if timeout is None: timeout = self._query_timeout while True: LOGGER.debug(json.dumps({'url': self.url, 'headers': headers, 'query': query, 'timeout': timeout}, indent=2)) try: result = self.http_handler.request(self.url, query, headers, timeout) break except HTTPHandlerError, error: if error.code == 409: LOGGER.info('Server responded with 409, trying to set session-id.') if request_count > 1: raise TransmissionError('Session ID negotiation failed.', error) if 'x-transmission-session-id' in error.headers: self.session_id = error.headers['x-transmission-session-id'] headers = {'x-transmission-session-id': str(self.session_id)} else: debug_httperror(error) raise TransmissionError('Unknown conflict.', error) else: debug_httperror(error) raise TransmissionError('Request failed.', error) request_count += 1
def _request(self, method, arguments=None, ids=None, require_ids=False, timeout=None): """ Send json-rpc request to Transmission using http POST """ if not isinstance(method, (str, unicode)): raise ValueError('request takes method as string') if arguments is None: arguments = {} if not isinstance(arguments, dict): raise ValueError('request takes arguments as dict') ids = self._format_ids(ids) if len(ids) > 0: arguments['ids'] = ids elif require_ids: raise ValueError('request require ids') query = json.dumps({'tag': self._sequence, 'method': method , 'arguments': arguments}) self._sequence += 1 start = time.time() http_data = self._http_query(query, timeout) elapsed = time.time() - start LOGGER.info('http request took %.3f s' % (elapsed)) try: data = json.loads(http_data) except ValueError, error: LOGGER.error('Error: ' + str(error)) LOGGER.error('Request: \"%s\"' % (query)) LOGGER.error('HTTP data: \"%s\"' % (http_data)) raise
def debug_httperror(error): """ Log the Transmission RPC HTTP error. """ try: data = json.loads(error.data) except ValueError: data = error.data LOGGER.debug( json.dumps( { 'response': { 'url': error.url, 'code': error.code, 'msg': error.message, 'headers': error.headers, 'data': data, } }, indent=2 ) )
def __init__(self, address='localhost', port=DEFAULT_PORT, user=None, password=None, http_handler=None, timeout=None): if isinstance(timeout, (int, long, float)): self._query_timeout = float(timeout) else: self._query_timeout = DEFAULT_TIMEOUT urlo = urlparse.urlparse(address) if urlo.scheme == '': base_url = 'http://' + address + ':' + str(port) self.url = base_url + '/transmission/rpc' else: if urlo.port: self.url = urlo.scheme + '://' + urlo.hostname + ':' + str(urlo.port) + urlo.path else: self.url = urlo.scheme + '://' + urlo.hostname + urlo.path LOGGER.info('Using custom URL "' + self.url + '".') if urlo.username and urlo.password: user = urlo.username password = urlo.password elif urlo.username or urlo.password: LOGGER.warning('Either user or password missing, not using authentication.') if http_handler is None: self.http_handler = DefaultHTTPHandler() else: if hasattr(http_handler, 'set_authentication') and hasattr(http_handler, 'request'): self.http_handler = http_handler else: raise ValueError('Invalid HTTP handler.') if user and password: self.http_handler.set_authentication(self.url, user, password) elif user or password: LOGGER.warning('Either user or password missing, not using authentication.') self._sequence = 0 self.session = Session() self.session_id = 0 self.server_version = None self.protocol_version = None self.get_session() self.torrent_get_arguments = get_arguments('torrent-get' , self.rpc_version)
def _rpc_version_warning(self, version): """ Add a warning to the log if the Transmission RPC version is lower then the provided version. """ if self.rpc_version < version: LOGGER.warning('Using feature not supported by server. RPC version for server %d, feature introduced in %d.' % (self.rpc_version, version))
, 'arguments': arguments}) self._sequence += 1 start = time.time() http_data = self._http_query(query, timeout) elapsed = time.time() - start LOGGER.info('http request took %.3f s' % (elapsed)) try: data = json.loads(http_data) except ValueError, error: LOGGER.error('Error: ' + str(error)) LOGGER.error('Request: \"%s\"' % (query)) LOGGER.error('HTTP data: \"%s\"' % (http_data)) raise LOGGER.debug(json.dumps(data, indent=2)) if 'result' in data: if data['result'] != 'success': raise TransmissionError('Query failed with result \"%s\".' % (data['result'])) else: raise TransmissionError('Query failed without result.') results = {} if method == 'torrent-get': for item in data['arguments']['torrents']: results[item['id']] = Torrent(self, item) if self.protocol_version == 2 and 'peers' not in item: self.protocol_version = 1 elif method == 'torrent-add': item = data['arguments']['torrent-added'] results[item['id']] = Torrent(self, item)