Merge pull request #260 from lbryio/error-messages

meaningful error messages, improve cli, remove unused search from daemon
This commit is contained in:
Jack Robison 2016-11-22 15:54:21 -05:00 committed by GitHub
commit f65a50a6a3
7 changed files with 163 additions and 230 deletions

View file

@ -163,7 +163,6 @@ class AdjustableSettings(Setting):
self.check_ui_requirements = True
self.local_ui_path = False
self.api_port = 5279
self.search_servers = ['lighthouse1.lbry.io:50005']
self.data_rate = .0001 # points/megabyte
self.min_info_rate = .02 # points/1000 infos
self.min_valuable_info_rate = .05 # points/1000 infos

View file

@ -321,6 +321,7 @@ class KademliaProtocol(protocol.DatagramProtocol):
except Exception, e:
log.exception('Failed to cancel %s', self._callLaterList[key])
del self._callLaterList[key]
# not sure why this is needed, but taking this out sometimes causes
# exceptions.AttributeError: 'Port' object has no attribute 'socket'
# to happen on shutdown

View file

@ -9,11 +9,11 @@ import sys
import base58
import requests
import simplejson as json
from urllib2 import urlopen
from appdirs import user_data_dir
from datetime import datetime
from decimal import Decimal
from twisted.web import server
from twisted.internet import defer, threads, error, reactor, task
from twisted.internet.task import LoopingCall
@ -22,41 +22,32 @@ from jsonschema import ValidationError
# TODO: importing this when internet is disabled raises a socket.gaierror
from lbryum.version import LBRYUM_VERSION as lbryum_version
from lbrynet import __version__ as lbrynet_version
from lbrynet import conf
from lbrynet.conf import settings as lbrynet_settings
from lbrynet import conf, reflector, analytics
from lbrynet.conf import LBRYCRD_WALLET, LBRYUM_WALLET, PTC_WALLET
from lbrynet import analytics
from lbrynet.metadata.Fee import FeeValidator
from lbrynet.core import Platform
from lbrynet.core.looping_call_manager import LoopingCallManager
from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory
from lbrynet.core.server.ServerProtocol import ServerProtocolFactory
from lbrynet.core.Error import InsufficientFundsError, InvalidNameError
from lbrynet.lbryfile.StreamDescriptor import EncryptedFileStreamType
from lbrynet.metadata.Metadata import Metadata, verify_name_characters
from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileSaverFactory, EncryptedFileOpenerFactory
from lbrynet.lbryfile.client.EncryptedFileOptions import add_lbry_file_to_sd_identifier
from lbrynet.lbryfile.EncryptedFileMetadataManager import DBEncryptedFileMetadataManager
from lbrynet.lbryfile.EncryptedFileMetadataManager import TempEncryptedFileMetadataManager
from lbrynet.lbryfile.StreamDescriptor import EncryptedFileStreamType
from lbrynet.lbryfilemanager.EncryptedFileManager import EncryptedFileManager
from lbrynet.lbrynet_console.Settings import Settings
from lbrynet.lbrynet_daemon.UIManager import UIManager
from lbrynet.lbrynet_daemon.Downloader import GetStream
from lbrynet.lbrynet_daemon.Publisher import Publisher
from lbrynet.lbrynet_daemon.ExchangeRateManager import ExchangeRateManager
from lbrynet.lbrynet_daemon.Lighthouse import LighthouseClient
from lbrynet.lbrynet_daemon.auth.server import AuthJSONRPCServer
from lbrynet.metadata.Metadata import Metadata, verify_name_characters
from lbrynet.core import log_support
from lbrynet.core import utils
from lbrynet.core.utils import generate_id
from lbrynet.lbrynet_console.Settings import Settings
from lbrynet.core import log_support, utils, Platform
from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier, download_sd_blob, BlobStreamDescriptorReader
from lbrynet.core.Session import Session
from lbrynet.core.PTCWallet import PTCWallet
from lbrynet.core.Wallet import LBRYcrdWallet, LBRYumWallet
from lbrynet.lbryfilemanager.EncryptedFileManager import EncryptedFileManager
from lbrynet.lbryfile.EncryptedFileMetadataManager import DBEncryptedFileMetadataManager, TempEncryptedFileMetadataManager
from lbrynet import reflector
from lbrynet.core.looping_call_manager import LoopingCallManager
from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory
from lbrynet.core.server.ServerProtocol import ServerProtocolFactory
from lbrynet.core.Error import InsufficientFundsError, InvalidNameError
log = logging.getLogger(__name__)
@ -209,52 +200,51 @@ class Daemon(AuthJSONRPCServer):
"""
def __init__(self, root, analytics_manager):
AuthJSONRPCServer.__init__(self, lbrynet_settings.use_auth_http)
AuthJSONRPCServer.__init__(self, conf.settings.use_auth_http)
reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)
self.allowed_during_startup = [
'is_running', 'is_first_run',
'get_time_behind_blockchain', 'stop',
'daemon_status', 'get_start_notice',
'version', 'get_search_servers'
'version'
]
last_version = {'last_version': {'lbrynet': lbrynet_version, 'lbryum': lbryum_version}}
lbrynet_settings.update(last_version)
self.db_dir = lbrynet_settings.data_dir
self.download_directory = lbrynet_settings.download_directory
conf.settings.update(last_version)
self.db_dir = conf.settings.data_dir
self.download_directory = conf.settings.download_directory
self.created_data_dir = False
if not os.path.exists(self.db_dir):
os.mkdir(self.db_dir)
self.created_data_dir = True
if lbrynet_settings.BLOBFILES_DIR == "blobfiles":
if conf.settings.BLOBFILES_DIR == "blobfiles":
self.blobfile_dir = os.path.join(self.db_dir, "blobfiles")
else:
log.info("Using non-default blobfiles directory: %s", lbrynet_settings.BLOBFILES_DIR)
self.blobfile_dir = lbrynet_settings.BLOBFILES_DIR
log.info("Using non-default blobfiles directory: %s", conf.settings.BLOBFILES_DIR)
self.blobfile_dir = conf.settings.BLOBFILES_DIR
self.run_on_startup = lbrynet_settings.run_on_startup
self.data_rate = lbrynet_settings.data_rate
self.max_key_fee = lbrynet_settings.max_key_fee
self.max_upload = lbrynet_settings.max_upload
self.max_download = lbrynet_settings.max_download
self.upload_log = lbrynet_settings.upload_log
self.search_timeout = lbrynet_settings.search_timeout
self.download_timeout = lbrynet_settings.download_timeout
self.max_search_results = lbrynet_settings.max_search_results
self.run_reflector_server = lbrynet_settings.run_reflector_server
self.wallet_type = lbrynet_settings.wallet
self.delete_blobs_on_remove = lbrynet_settings.delete_blobs_on_remove
self.peer_port = lbrynet_settings.peer_port
self.reflector_port = lbrynet_settings.reflector_port
self.dht_node_port = lbrynet_settings.dht_node_port
self.use_upnp = lbrynet_settings.use_upnp
self.start_lbrycrdd = lbrynet_settings.start_lbrycrdd
self.cache_time = lbrynet_settings.cache_time
self.startup_scripts = lbrynet_settings.startup_scripts
self.run_on_startup = conf.settings.run_on_startup
self.data_rate = conf.settings.data_rate
self.max_key_fee = conf.settings.max_key_fee
self.max_upload = conf.settings.max_upload
self.max_download = conf.settings.max_download
self.upload_log = conf.settings.upload_log
self.search_timeout = conf.settings.search_timeout
self.download_timeout = conf.settings.download_timeout
self.max_search_results = conf.settings.max_search_results
self.run_reflector_server = conf.settings.run_reflector_server
self.wallet_type = conf.settings.wallet
self.delete_blobs_on_remove = conf.settings.delete_blobs_on_remove
self.peer_port = conf.settings.peer_port
self.reflector_port = conf.settings.reflector_port
self.dht_node_port = conf.settings.dht_node_port
self.use_upnp = conf.settings.use_upnp
self.start_lbrycrdd = conf.settings.start_lbrycrdd
self.cache_time = conf.settings.cache_time
self.startup_scripts = conf.settings.startup_scripts
self.startup_status = STARTUP_STAGES[0]
self.startup_message = None
self.announced_startup = False
self.connected_to_internet = True
self.connection_problem = None
self.git_lbrynet_version = None
@ -262,19 +252,19 @@ class Daemon(AuthJSONRPCServer):
self.ui_version = None
self.platform = None
self.first_run = None
self.log_file = lbrynet_settings.get_log_filename()
self.log_file = conf.settings.get_log_filename()
self.current_db_revision = 1
self.session = None
self.uploaded_temp_files = []
self._session_id = base58.b58encode(generate_id())
self._session_id = base58.b58encode(utils.generate_id())
# TODO: this should probably be passed into the daemon, or
# possibly have the entire log upload functionality taken out
# of the daemon, but I don't want to deal with that now
self.log_uploader = log_support.LogUploader.load('lbrynet', self.log_file)
self.analytics_manager = None
self.analytics_manager = analytics_manager
self.lbryid = PENDING_LBRY_ID
self.daemon_conf = lbrynet_settings.get_conf_filename()
self.daemon_conf = conf.settings.get_conf_filename()
self.wallet_user = None
self.wallet_password = None
@ -285,7 +275,6 @@ class Daemon(AuthJSONRPCServer):
self.name_cache = {}
self.set_wallet_attributes()
self.exchange_rate_manager = ExchangeRateManager()
self.lighthouse_client = LighthouseClient()
calls = {
Checker.INTERNET_CONNECTION: LoopingCall(CheckInternetConnection(self)),
Checker.VERSION: LoopingCall(CheckRemoteVersions(self)),
@ -300,7 +289,6 @@ class Daemon(AuthJSONRPCServer):
self.blob_request_payment_rate_manager = None
self.lbry_file_metadata_manager = None
self.lbry_file_manager = None
self.analytics_manager = analytics_manager
@AuthJSONRPCServer.subhandler
def _exclude_lbrycrd_only_commands_from_lbryum_session(self, request):
@ -377,7 +365,7 @@ class Daemon(AuthJSONRPCServer):
self.exchange_rate_manager.start()
d = defer.Deferred()
if lbrynet_settings.host_ui:
if conf.settings.host_ui:
self.lbry_ui_manager.update_checker.start(1800, now=False)
d.addCallback(lambda _: self.lbry_ui_manager.setup())
d.addCallback(lambda _: self._initial_setup())
@ -661,27 +649,27 @@ class Daemon(AuthJSONRPCServer):
for key, setting_type in setting_types.iteritems():
if key in settings:
if isinstance(settings[key], setting_type):
lbrynet_settings.update({key: settings[key]})
conf.settings.update({key: settings[key]})
elif key == "max_key_fee" and isinstance(FeeValidator(settings[key]).amount, setting_type):
lbrynet_settings.update({key: settings[key]})
conf.settings.update({key: settings[key]})
else:
try:
converted = setting_type(settings[key])
lbrynet_settings.update({key: converted})
conf.settings.update({key: converted})
except Exception as err:
log.warning(err.message)
log.warning("error converting setting '%s' to type %s", key, setting_type)
self.run_on_startup = lbrynet_settings.run_on_startup
self.data_rate = lbrynet_settings.data_rate
self.max_key_fee = lbrynet_settings.max_key_fee
self.download_directory = lbrynet_settings.download_directory
self.max_upload = lbrynet_settings.max_upload
self.max_download = lbrynet_settings.max_download
self.upload_log = lbrynet_settings.upload_log
self.download_timeout = lbrynet_settings.download_timeout
self.search_timeout = lbrynet_settings.search_timeout
self.cache_time = lbrynet_settings.cache_time
self.run_on_startup = conf.settings.run_on_startup
self.data_rate = conf.settings.data_rate
self.max_key_fee = conf.settings.max_key_fee
self.download_directory = conf.settings.download_directory
self.max_upload = conf.settings.max_upload
self.max_download = conf.settings.max_download
self.upload_log = conf.settings.upload_log
self.download_timeout = conf.settings.download_timeout
self.search_timeout = conf.settings.search_timeout
self.cache_time = conf.settings.cache_time
return defer.succeed(True)
@ -738,7 +726,7 @@ class Daemon(AuthJSONRPCServer):
self.lbryid = lbryid
def _make_set_and_save_lbryid(self):
self.lbryid = generate_id()
self.lbryid = utils.generate_id()
log.info("Generated new LBRY ID: " + base58.b58encode(self.lbryid))
d = self.settings.save_lbryid(self.lbryid)
return d
@ -785,7 +773,7 @@ class Daemon(AuthJSONRPCServer):
def get_default_data_rate():
d = self.settings.get_default_data_payment_rate()
d.addCallback(lambda rate: {"default_data_payment_rate": rate if rate is not None else
lbrynet_settings.data_rate})
conf.settings.data_rate})
return d
def get_wallet():
@ -799,8 +787,8 @@ class Daemon(AuthJSONRPCServer):
elif self.wallet_type == LBRYUM_WALLET:
log.info("Using lbryum wallet")
config = {'auto_connect': True}
if lbrynet_settings.lbryum_wallet_dir:
config['lbryum_path'] = lbrynet_settings.lbryum_wallet_dir
if conf.settings.lbryum_wallet_dir:
config['lbryum_path'] = conf.settings.lbryum_wallet_dir
d = defer.succeed(LBRYumWallet(self.db_dir, config))
elif self.wallet_type == PTC_WALLET:
log.info("Using PTC wallet")
@ -823,7 +811,7 @@ class Daemon(AuthJSONRPCServer):
def create_session(results):
self.session = Session(results['default_data_payment_rate'], db_dir=self.db_dir, lbryid=self.lbryid,
blob_dir=self.blobfile_dir, dht_node_port=self.dht_node_port,
known_dht_nodes=lbrynet_settings.known_dht_nodes, peer_port=self.peer_port,
known_dht_nodes=conf.settings.known_dht_nodes, peer_port=self.peer_port,
use_upnp=self.use_upnp, wallet=results['wallet'])
self.startup_status = STARTUP_STAGES[2]
@ -845,7 +833,7 @@ class Daemon(AuthJSONRPCServer):
self.sd_identifier.add_stream_downloader_factory(EncryptedFileStreamType, file_opener_factory)
return defer.succeed(None)
def _download_sd_blob(self, sd_hash, timeout=lbrynet_settings.sd_download_timeout):
def _download_sd_blob(self, sd_hash, timeout=conf.settings.sd_download_timeout):
def cb(result):
if not r.called:
r.callback(result)
@ -866,7 +854,7 @@ class Daemon(AuthJSONRPCServer):
return r
def _download_name(self, name, timeout=lbrynet_settings.download_timeout, download_directory=None,
def _download_name(self, name, timeout=conf.settings.download_timeout, download_directory=None,
file_name=None, stream_info=None, wait_for_write=True):
"""
Add a lbry file to the file manager, start the download, and return the new lbry file.
@ -1039,7 +1027,7 @@ class Daemon(AuthJSONRPCServer):
log.info("Removing one time startup scripts")
remaining_scripts = [s for s in self.startup_scripts if 'run_once' not in s.keys()]
startup_scripts = self.startup_scripts
self.startup_scripts = lbrynet_settings.startup_scripts = remaining_scripts
self.startup_scripts = conf.settings.startup_scripts = remaining_scripts
conf.save_settings()
for script in startup_scripts:
@ -1055,9 +1043,6 @@ class Daemon(AuthJSONRPCServer):
return defer.succeed(None)
def _search(self, search):
return self.lighthouse_client.search(search)
def jsonrpc_is_running(self):
"""
Check if lbrynet daemon is running
@ -1218,7 +1203,7 @@ class Daemon(AuthJSONRPCServer):
"""
log.info("Get daemon settings")
return self._render_response(lbrynet_settings.__dict__, OK_CODE)
return self._render_response(conf.settings.__dict__, OK_CODE)
@AuthJSONRPCServer.auth_required
def jsonrpc_set_settings(self, p):
@ -1239,12 +1224,12 @@ class Daemon(AuthJSONRPCServer):
"""
def _log_settings_change():
log.info("Set daemon settings to " + json.dumps(lbrynet_settings.configurable_settings))
log.info("Set daemon settings to " + json.dumps(conf.settings.configurable_settings))
d = self._update_settings(p)
d.addErrback(lambda err: log.info(err.getTraceback()))
d.addCallback(lambda _: _log_settings_change())
d.addCallback(lambda _: self._render_response(lbrynet_settings.configurable_settings, OK_CODE))
d.addCallback(lambda _: self._render_response(conf.settings.configurable_settings, OK_CODE))
return d
@ -1556,42 +1541,6 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r, OK_CODE))
return d
def jsonrpc_search_nametrie(self, p):
"""
Search the nametrie for claims
Args:
'search': search query, string
Returns:
List of search results
"""
# TODO: change this function to "search"
if 'search' in p.keys():
search = p['search']
else:
return self._render_response(None, BAD_REQUEST)
# TODO: have ui accept the actual outputs
def _clean(n):
t = []
for i in n:
td = {k: i['value'][k] for k in i['value']}
td['cost_est'] = float(i['cost'])
td['thumbnail'] = i['value'].get('thumbnail', "img/Free-speech-flag.svg")
td['name'] = i['name']
t.append(td)
return t
log.info('Search: %s' % search)
d = self._search(search)
d.addCallback(_clean)
d.addCallback(lambda results: self._render_response(results, OK_CODE))
return d
@AuthJSONRPCServer.auth_required
def jsonrpc_delete_lbry_file(self, p):
"""
@ -2002,7 +1951,7 @@ class Daemon(AuthJSONRPCServer):
sd blob, dict
"""
sd_hash = p[FileID.SD_HASH]
timeout = p.get('timeout', lbrynet_settings.sd_download_timeout)
timeout = p.get('timeout', conf.settings.sd_download_timeout)
d = self._download_sd_blob(sd_hash, timeout)
d.addCallbacks(
lambda r: self._render_response(r, OK_CODE),
@ -2235,18 +2184,6 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r, OK_CODE))
return d
def jsonrpc_get_search_servers(self):
"""
Get list of lighthouse servers
Args:
None
Returns:
List of address:port
"""
d = self._render_response(lbrynet_settings.search_servers, OK_CODE)
return d
def jsonrpc_get_mean_availability(self):
"""
Get mean blob availability
@ -2365,7 +2302,7 @@ def get_darwin_lbrycrdd_path():
class _DownloadNameHelper(object):
def __init__(self, daemon, name, timeout=lbrynet_settings.download_timeout, download_directory=None,
def __init__(self, daemon, name, timeout=conf.settings.download_timeout, download_directory=None,
file_name=None, wait_for_write=True):
self.daemon = daemon
self.name = name
@ -2668,7 +2605,7 @@ def handle_failure(err, msg):
def run_reflector_factory(factory):
reflector_server = random.choice(lbrynet_settings.reflector_servers)
reflector_server = random.choice(conf.settings.reflector_servers)
reflector_address, reflector_port = reflector_server
log.info("Start reflector client")
d = reactor.resolve(reflector_address)

View file

@ -1,15 +1,17 @@
import sys
import json
import argparse
import json
from lbrynet.conf import settings
from lbrynet.lbrynet_daemon.auth.client import LBRYAPIClient
from jsonrpc.common import RPCError
help_msg = "Usage: lbrynet-cli method json-args\n" \
help_msg = "Usage: lbrynet-cli method kwargs\n" \
+ "Examples: " \
+ "lbrynet-cli resolve_name '{\"name\": \"what\"}'\n" \
+ "lbrynet-cli resolve_name name=what\n" \
+ "lbrynet-cli get_balance\n" \
+ "lbrynet-cli help '{\"function\": \"resolve_name\"}'\n" \
+ "lbrynet-cli help function=resolve_name\n" \
+ "\n******lbrynet-cli functions******\n"
@ -59,14 +61,13 @@ def main():
meth = args.method[0]
params = {}
if args.params:
if len(args.params) > 1:
if len(args.params) > 1:
params = get_params_from_kwargs(args.params)
elif len(args.params) == 1:
try:
params = json.loads(args.params[0])
except ValueError:
params = get_params_from_kwargs(args.params)
elif len(args.params) == 1:
try:
params = json.loads(args.params[0])
except ValueError:
params = get_params_from_kwargs(args.params)
msg = help_msg
for f in api.help():
@ -83,14 +84,16 @@ def main():
else:
result = LBRYAPIClient.config(service=meth, params=params)
print json.dumps(result, sort_keys=True)
except:
except RPCError as err:
# TODO: The api should return proper error codes
# and messages so that they can be passed along to the user
# instead of this generic message.
# https://app.asana.com/0/158602294500137/200173944358192
print "Something went wrong, here's the usage for %s:" % meth
print api.help({'function': meth})
print "Here's the traceback for the error you encountered:"
print err.msg
else:
print "Unknown function"
print msg

View file

@ -1,4 +1,3 @@
import json
import logging
import os
@ -77,13 +76,10 @@ class GetStream(object):
self.finished.callback((False, None, None))
def _convert_max_fee(self):
if isinstance(self.max_key_fee, dict):
max_fee = FeeValidator(self.max_key_fee)
if max_fee.currency_symbol == "LBC":
return max_fee.amount
return self.exchange_rate_manager.to_lbc(self.fee).amount
elif isinstance(self.max_key_fee, float):
return float(self.max_key_fee)
max_fee = FeeValidator(self.max_key_fee)
if max_fee.currency_symbol == "LBC":
return max_fee.amount
return self.exchange_rate_manager.to_lbc(self.max_key_fee).amount
def start(self, stream_info, name):
def _cause_timeout(err):
@ -117,14 +113,18 @@ class GetStream(object):
if 'fee' in self.stream_info:
self.fee = FeeValidator(self.stream_info['fee'])
max_key_fee = self._convert_max_fee()
if self.exchange_rate_manager.to_lbc(self.fee).amount > max_key_fee:
log.info("Key fee %f above limit of %f didn't download lbry://%s" % (self.fee.amount,
self.max_key_fee,
self.resolved_name))
converted_fee = self.exchange_rate_manager.to_lbc(self.fee).amount
if converted_fee > self.wallet.get_balance():
log.warning("Insufficient funds to download lbry://%s", self.resolved_name)
return defer.fail(InsufficientFundsError())
if converted_fee > max_key_fee:
log.warning("Key fee %f above limit of %f didn't download lbry://%s", converted_fee,
max_key_fee,
self.resolved_name)
return defer.fail(KeyFeeAboveMaxAllowed())
log.info("Key fee %s below limit of %f, downloading lbry://%s" % (json.dumps(self.fee),
max_key_fee,
self.resolved_name))
log.info("Key fee %f below limit of %f, downloading lbry://%s", converted_fee,
max_key_fee,
self.resolved_name)
self.checker.start(1)

View file

@ -1,27 +0,0 @@
import logging
import random
from txjsonrpc.web.jsonrpc import Proxy
from lbrynet.conf import settings
log = logging.getLogger(__name__)
class LighthouseClient(object):
def __init__(self, servers=None):
self.servers = servers or settings.search_servers
def _get_random_server(self):
return Proxy(random.choice(self.servers))
def _run_query(self, func, arg):
return self._get_random_server().callRemote(func, arg)
def search(self, search):
return self._run_query('search', search)
def announce_sd(self, sd_hash):
log.info("Announce sd to lighthouse")
return self._run_query('announce_sd', sd_hash)
def check_available(self, sd_hash):
return self._run_query('check_available', sd_hash)

View file

@ -1,11 +1,11 @@
import logging
from decimal import Decimal
from zope.interface import implements
from twisted.web import server, resource
from twisted.internet import defer
from txjsonrpc import jsonrpclib
from twisted.python.failure import Failure
from txjsonrpc import jsonrpclib
from lbrynet.core.Error import InvalidAuthenticationToken, InvalidHeaderError, SubhandlerError
from lbrynet.conf import settings
from lbrynet.core import log_support
@ -20,6 +20,16 @@ def default_decimal(obj):
return float(obj)
class JSONRPCException(Exception):
def __init__(self, err, code):
self.faultCode = code
self.err = err
@property
def faultString(self):
return self.err.getTraceback()
class AuthorizedBase(object):
def __init__(self):
self.authorized_functions = []
@ -85,20 +95,36 @@ class AuthJSONRPCServer(AuthorizedBase):
def __init__(self, use_authentication=settings.use_auth_http):
AuthorizedBase.__init__(self)
self._use_authentication = use_authentication
self.announced_startup = False
self.allowed_during_startup = []
self.sessions = {}
def setup(self):
return NotImplementedError()
def render(self, request):
assert self._check_headers(request), InvalidHeaderError
def _render_error(self, failure, request, version=jsonrpclib.VERSION_1, response_code=FAILURE):
err = JSONRPCException(Failure(failure), response_code)
fault = jsonrpclib.dumps(err, version=version)
self._set_headers(request, fault)
if response_code != AuthJSONRPCServer.FAILURE:
request.setResponseCode(response_code)
request.write(fault)
request.finish()
def _log_and_render_error(self, failure, request, message=None, **kwargs):
msg = message or "API Failure: %s"
log_support.failure(Failure(failure), log, msg)
self._render_error(failure, request, **kwargs)
def render(self, request):
notify_finish = request.notifyFinish()
assert self._check_headers(request), InvalidHeaderError
session = request.getSession()
session_id = session.uid
if self._use_authentication:
# if this is a new session, send a new secret and set the expiration, otherwise, session.touch()
# if this is a new session, send a new secret and set the expiration
# otherwise, session.touch()
if self._initialize_session(session_id):
def expire_session():
self._unregister_user_session(session_id)
@ -115,8 +141,10 @@ class AuthJSONRPCServer(AuthorizedBase):
content = request.content.read()
try:
parsed = jsonrpclib.loads(content)
except ValueError:
return server.failure
except ValueError as err:
log.warning("Unable to decode request json")
self._render_error(err, request)
return server.NOT_DONE_YET
function_name = parsed.get('method')
args = parsed.get('params')
@ -126,36 +154,38 @@ class AuthJSONRPCServer(AuthorizedBase):
try:
self._run_subhandlers(request)
except SubhandlerError:
return server.failure
except SubhandlerError as err:
self._render_error(err, request, version)
return server.NOT_DONE_YET
reply_with_next_secret = False
if self._use_authentication:
if function_name in self.authorized_functions:
try:
self._verify_token(session_id, parsed, token)
except InvalidAuthenticationToken:
except InvalidAuthenticationToken as err:
log.warning("API validation failed")
request.setResponseCode(self.UNAUTHORIZED)
request.finish()
self._render_error(err, request, version=version, response_code=AuthJSONRPCServer.UNAUTHORIZED)
return server.NOT_DONE_YET
self._update_session_secret(session_id)
reply_with_next_secret = True
try:
function = self._get_jsonrpc_method(function_name)
except Exception:
except AttributeError as err:
log.warning("Unknown method: %s", function_name)
return server.failure
self._render_error(err, request, version)
return server.NOT_DONE_YET
if args == [{}]:
d = defer.maybeDeferred(function)
else:
d = defer.maybeDeferred(function, *args)
d = defer.maybeDeferred(function) if args == [{}] else defer.maybeDeferred(function, *args)
# cancel the response if the connection is broken
notify_finish = request.notifyFinish()
notify_finish.addErrback(self._response_failed, d)
d.addErrback(self._errback_render, id)
d.addCallback(self._callback_render, request, id, version, reply_with_next_secret)
d.addErrback(notify_finish.errback)
d.addCallback(self._callback_render, request, version, reply_with_next_secret)
d.addErrback(self._log_and_render_error, request, version=version)
return server.NOT_DONE_YET
def _register_user_session(self, session_id):
@ -210,7 +240,8 @@ class AuthJSONRPCServer(AuthorizedBase):
return True
def _get_jsonrpc_method(self, function_path):
assert self._check_function_path(function_path)
if not self._check_function_path(function_path):
raise AttributeError(function_path)
return self.callable_methods.get(function_path)
def _initialize_session(self, session_id):
@ -239,13 +270,10 @@ class AuthJSONRPCServer(AuthorizedBase):
def _run_subhandlers(self, request):
for handler in self.subhandlers:
try:
assert handler(request)
except Exception as err:
log.error(err.message)
raise SubhandlerError
if not handler(request):
raise SubhandlerError("Subhandler error processing request: %s", request)
def _callback_render(self, result, request, id, version, auth_required=False):
def _callback_render(self, result, request, version, auth_required=False):
result_for_return = result if not isinstance(result, dict) else result['result']
if version == jsonrpclib.VERSION_PRE1:
@ -256,17 +284,9 @@ class AuthJSONRPCServer(AuthorizedBase):
encoded_message = jsonrpclib.dumps(result_for_return, version=version, default=default_decimal)
self._set_headers(request, encoded_message, auth_required)
self._render_message(request, encoded_message)
except:
fault = jsonrpclib.Fault(self.FAILURE, "can't serialize output")
encoded_message = jsonrpclib.dumps(fault, version=version)
self._set_headers(request, encoded_message)
self._render_message(request, encoded_message)
def _errback_render(self, failure, id):
log_support.failure(failure, log, "Request failed. Id: %s, Failure: %s", id)
if isinstance(failure.value, jsonrpclib.Fault):
return failure.value
return server.failure
except Exception as err:
msg = "Failed to render API response: %s"
self._log_and_render_error(err, request, message=msg, version=version)
def _render_response(self, result, code):
return defer.succeed({'result': result, 'code': code})