Merge pull request #448 from lbryio/jsonrpc_params_in_function_signature

explicitly list jsonrpc params in function signature. add jsonrpc tests
This commit is contained in:
Alex Grin 2017-01-30 16:34:50 -05:00 committed by GitHub
commit b219806959
4 changed files with 192 additions and 204 deletions

View file

@ -1031,7 +1031,6 @@ class Daemon(AuthJSONRPCServer):
) )
return run_reflector_factory(factory) return run_reflector_factory(factory)
############################################################################ ############################################################################
# # # #
# JSON-RPC API methods start here # # JSON-RPC API methods start here #
@ -1039,7 +1038,7 @@ class Daemon(AuthJSONRPCServer):
############################################################################ ############################################################################
@defer.inlineCallbacks @defer.inlineCallbacks
def jsonrpc_status(self, p={}): def jsonrpc_status(self, session_status=False, blockchain_status=False):
""" """
Return daemon status Return daemon status
@ -1068,17 +1067,17 @@ class Daemon(AuthJSONRPCServer):
}, },
'blocks_behind': ( 'blocks_behind': (
self.session.wallet.blocks_behind self.session.wallet.blocks_behind
if has_wallet and self.wallet_type == LBRYUM_WALLET if has_wallet and self.wallet_type == LBRYUM_WALLET
else 'unknown' else 'unknown'
), ),
} }
if p.get('session_status', False): if session_status:
blobs = yield self.session.blob_manager.get_all_verified_blobs() blobs = yield self.session.blob_manager.get_all_verified_blobs()
response['session_status'] = { response['session_status'] = {
'managed_blobs': len(blobs), 'managed_blobs': len(blobs),
'managed_streams': len(self.lbry_file_manager.lbry_files), 'managed_streams': len(self.lbry_file_manager.lbry_files),
} }
if p.get('blockchain_status', False) and has_wallet: if blockchain_status and has_wallet:
# calculate blocks_behind more accurately # calculate blocks_behind more accurately
local_height = self.session.wallet.network.get_local_height() local_height = self.session.wallet.network.get_local_height()
remote_height = self.session.wallet.network.get_server_height() remote_height = self.session.wallet.network.get_server_height()
@ -1091,7 +1090,7 @@ class Daemon(AuthJSONRPCServer):
""" """
DEPRECATED. Use `status blockchain_status=True` instead DEPRECATED. Use `status blockchain_status=True` instead
""" """
d = self.jsonrpc_status({'blockchain_status': True}) d = self.jsonrpc_status(blockchain_status=True)
d.addCallback(lambda x: self._render_response( d.addCallback(lambda x: self._render_response(
x['blockchain_status']['best_blockhash'])) x['blockchain_status']['best_blockhash']))
return d return d
@ -1141,7 +1140,7 @@ class Daemon(AuthJSONRPCServer):
""" """
DEPRECATED. Use `status` instead DEPRECATED. Use `status` instead
""" """
d = self.jsonrpc_status({'blockchain_status': True}) d = self.jsonrpc_status(blockchain_status=True)
d.addCallback(lambda x: self._render_response(x['is_first_run'])) d.addCallback(lambda x: self._render_response(x['is_first_run']))
return d return d
@ -1150,7 +1149,7 @@ class Daemon(AuthJSONRPCServer):
DEPRECATED. Use `status` instead DEPRECATED. Use `status` instead
""" """
d = self.jsonrpc_status({'session_status': True}) d = self.jsonrpc_status(session_status=True)
d.addCallback(lambda x: self._render_response({ d.addCallback(lambda x: self._render_response({
'lbry_id': x['lbry_id'], 'lbry_id': x['lbry_id'],
'managed_blobs': x['session_status']['managed_blobs'], 'managed_blobs': x['session_status']['managed_blobs'],
@ -1162,7 +1161,7 @@ class Daemon(AuthJSONRPCServer):
""" """
DEPRECATED. Use `status` instead DEPRECATED. Use `status` instead
""" """
d = self.jsonrpc_status({'blockchain_status': True}) # blockchain_status=True is needed d = self.jsonrpc_status(blockchain_status=True)
d.addCallback(lambda x: self._render_response(x['blocks_behind'])) d.addCallback(lambda x: self._render_response(x['blocks_behind']))
return d return d
@ -1210,7 +1209,7 @@ class Daemon(AuthJSONRPCServer):
log.info("Get version info: " + json.dumps(msg)) log.info("Get version info: " + json.dumps(msg))
return self._render_response(msg) return self._render_response(msg)
def jsonrpc_report_bug(self, p): def jsonrpc_report_bug(self, message=None):
""" """
Report a bug to slack Report a bug to slack
@ -1220,9 +1219,8 @@ class Daemon(AuthJSONRPCServer):
True if successful True if successful
""" """
bug_message = p['message']
platform_name = self._get_platform()['platform'] platform_name = self._get_platform()['platform']
report_bug_to_slack(bug_message, self.lbryid, platform_name, lbrynet_version) report_bug_to_slack(message, self.lbryid, platform_name, lbrynet_version)
return self._render_response(True) return self._render_response(True)
def jsonrpc_get_settings(self): def jsonrpc_get_settings(self):
@ -1233,10 +1231,8 @@ class Daemon(AuthJSONRPCServer):
def jsonrpc_settings_get(self): def jsonrpc_settings_get(self):
""" """
Get lbrynet daemon settings Get daemon settings
Args:
None
Returns: Returns:
'run_on_startup': bool, 'run_on_startup': bool,
'data_rate': float, 'data_rate': float,
@ -1259,16 +1255,16 @@ class Daemon(AuthJSONRPCServer):
return self._render_response(conf.settings.get_current_settings_dict()) return self._render_response(conf.settings.get_current_settings_dict())
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_set_settings(self, p): def jsonrpc_set_settings(self, **kwargs):
""" """
DEPRECATED. Use `settings_set` instead. DEPRECATED. Use `settings_set` instead.
""" """
return self.jsonrpc_settings_set(p) return self.jsonrpc_settings_set(**kwargs)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_settings_set(self, p): def jsonrpc_settings_set(self, **kwargs):
""" """
Set lbrynet daemon settings Set daemon settings
Args: Args:
'run_on_startup': bool, 'run_on_startup': bool,
@ -1288,7 +1284,7 @@ class Daemon(AuthJSONRPCServer):
"Set daemon settings to %s", "Set daemon settings to %s",
json.dumps(conf.settings.get_adjustable_settings_dict())) json.dumps(conf.settings.get_adjustable_settings_dict()))
d = self._update_settings(p) d = self._update_settings(kwargs)
d.addErrback(lambda err: log.info(err.getTraceback())) d.addErrback(lambda err: log.info(err.getTraceback()))
d.addCallback(lambda _: _log_settings_change()) d.addCallback(lambda _: _log_settings_change())
d.addCallback( d.addCallback(
@ -1296,7 +1292,7 @@ class Daemon(AuthJSONRPCServer):
return d return d
def jsonrpc_help(self, p=None): def jsonrpc_help(self, command=None):
""" """
Return a useful message for an API command Return a useful message for an API command
@ -1307,16 +1303,17 @@ class Daemon(AuthJSONRPCServer):
otherwise returns general help message otherwise returns general help message
""" """
if p and 'command' in p: if command is None:
fn = self.callable_methods.get(p['command'])
if fn is None:
return self._render_response(
"No help available for '" + p['command'] + "'. It is not a valid command."
)
return self._render_response(textwrap.dedent(fn.__doc__))
else:
return self._render_response(textwrap.dedent(self.jsonrpc_help.__doc__)) return self._render_response(textwrap.dedent(self.jsonrpc_help.__doc__))
fn = self.callable_methods.get(command)
if fn is None:
return self._render_response(
"No help available for '{}'. It is not a valid command.".format(command)
)
return self._render_response(textwrap.dedent(fn.__doc__))
def jsonrpc_commands(self): def jsonrpc_commands(self):
""" """
Return a list of available commands Return a list of available commands
@ -1394,13 +1391,13 @@ class Daemon(AuthJSONRPCServer):
return d return d
def jsonrpc_get_lbry_file(self, p): def jsonrpc_get_lbry_file(self, **kwargs):
""" """
DEPRECATED. Use `file_get` instead. DEPRECATED. Use `file_get` instead.
""" """
return self.jsonrpc_file_get(p) return self.jsonrpc_file_get(**kwargs)
def jsonrpc_file_get(self, p): def jsonrpc_file_get(self, **kwargs):
""" """
Get a file Get a file
@ -1420,19 +1417,19 @@ class Daemon(AuthJSONRPCServer):
'upload_allowed': bool 'upload_allowed': bool
'sd_hash': string 'sd_hash': string
""" """
d = self._get_deferred_for_lbry_file(p) d = self._get_deferred_for_lbry_file(kwargs)
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
def _get_deferred_for_lbry_file(self, p): def _get_deferred_for_lbry_file(self, search_fields):
try: try:
searchtype, value = get_lbry_file_search_value(p) searchtype, value = get_lbry_file_search_value(search_fields)
except NoValidSearch: except NoValidSearch:
return defer.fail() return defer.fail()
else: else:
return self._get_lbry_file(searchtype, value) return self._get_lbry_file(searchtype, value)
def jsonrpc_resolve_name(self, p): def jsonrpc_resolve_name(self, name, force=False):
""" """
Resolve stream info from a LBRY uri Resolve stream info from a LBRY uri
@ -1442,9 +1439,6 @@ class Daemon(AuthJSONRPCServer):
metadata from name claim metadata from name claim
""" """
force = p.get('force', False)
name = p.get(FileID.NAME)
if not name: if not name:
return self._render_response(None) return self._render_response(None)
@ -1452,13 +1446,13 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(self._render_response) d.addCallback(self._render_response)
return d return d
def jsonrpc_get_claim_info(self, p): def jsonrpc_get_claim_info(self, **kwargs):
""" """
DEPRECATED. Use `claim_show` instead. DEPRECATED. Use `claim_show` instead.
""" """
return self.jsonrpc_claim_show(p) return self.jsonrpc_claim_show(**kwargs)
def jsonrpc_claim_show(self, p): def jsonrpc_claim_show(self, name, txid=None, nout=None):
""" """
Resolve claim info from a LBRY uri Resolve claim info from a LBRY uri
@ -1479,9 +1473,6 @@ class Daemon(AuthJSONRPCServer):
r['amount'] = float(r['amount']) / 10 ** 8 r['amount'] = float(r['amount']) / 10 ** 8
return r return r
name = p[FileID.NAME]
txid = p.get('txid', None)
nout = p.get('nout', None)
d = self.session.wallet.get_claim_info(name, txid, nout) d = self.session.wallet.get_claim_info(name, txid, nout)
d.addCallback(_convert_amount_to_float) d.addCallback(_convert_amount_to_float)
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
@ -1510,7 +1501,7 @@ class Daemon(AuthJSONRPCServer):
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
def jsonrpc_get(self, p): def jsonrpc_get(self, **kwargs):
""" """
Download stream from a LBRY uri. Download stream from a LBRY uri.
@ -1526,7 +1517,7 @@ class Daemon(AuthJSONRPCServer):
'stream_hash': hex string 'stream_hash': hex string
'path': path of download 'path': path of download
""" """
params = self._process_get_parameters(p) params = self._process_get_parameters(kwargs)
if not params.name: if not params.name:
# TODO: return a useful error message here, like "name argument is required" # TODO: return a useful error message here, like "name argument is required"
defer.returnValue(server.failure) defer.returnValue(server.failure)
@ -1587,24 +1578,22 @@ class Daemon(AuthJSONRPCServer):
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_stop_lbry_file(self, p): def jsonrpc_stop_lbry_file(self, **kwargs):
""" """
DEPRECATED. Use `file_seed status=stop` instead. DEPRECATED. Use `file_seed status=stop` instead.
""" """
p['status'] = 'stop' return self.jsonrpc_file_seed(status='stop', **kwargs)
return self.jsonrpc_file_seed(p)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_start_lbry_file(self, p): def jsonrpc_start_lbry_file(self, **kwargs):
""" """
DEPRECATED. Use `file_seed status=start` instead. DEPRECATED. Use `file_seed status=start` instead.
""" """
p['status'] = 'start' return self.jsonrpc_file_seed(status='start', **kwargs)
return self.jsonrpc_file_seed(p)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
def jsonrpc_file_seed(self, p): def jsonrpc_file_seed(self, status, **kwargs):
""" """
Start or stop seeding a file Start or stop seeding a file
@ -1617,13 +1606,10 @@ class Daemon(AuthJSONRPCServer):
confirmation message confirmation message
""" """
status = p.get('status', None)
if status is None:
raise Exception('"status" option required')
if status not in ['start', 'stop']: if status not in ['start', 'stop']:
raise Exception('Status must be "start" or "stop".') raise Exception('Status must be "start" or "stop".')
search_type, value = get_lbry_file_search_value(p) search_type, value = get_lbry_file_search_value(**kwargs)
lbry_file = yield self._get_lbry_file(search_type, value, return_json=False) lbry_file = yield self._get_lbry_file(search_type, value, return_json=False)
if not lbry_file: if not lbry_file:
raise Exception('Unable to find a file for {}:{}'.format(search_type, value)) raise Exception('Unable to find a file for {}:{}'.format(search_type, value))
@ -1646,7 +1632,7 @@ class Daemon(AuthJSONRPCServer):
return self.jsonrpc_file_delete(p) return self.jsonrpc_file_delete(p)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_file_delete(self, p): def jsonrpc_file_delete(self, delete_target_file=True, **kwargs):
""" """
Delete a lbry file Delete a lbry file
@ -1656,19 +1642,16 @@ class Daemon(AuthJSONRPCServer):
confirmation message confirmation message
""" """
# TODO: is this option used? if yes, document it. if no, remove it
delete_file = p.get('delete_target_file', True)
def _delete_file(f): def _delete_file(f):
if not f: if not f:
return False return False
file_name = f.file_name file_name = f.file_name
d = self._delete_lbry_file(f, delete_file=delete_file) d = self._delete_lbry_file(f, delete_file=delete_target_file)
d.addCallback(lambda _: "Deleted file: " + file_name) d.addCallback(lambda _: "Deleted file: " + file_name)
return d return d
try: try:
searchtype, value = get_lbry_file_search_value(p) searchtype, value = get_lbry_file_search_value(kwargs)
except NoValidSearch: except NoValidSearch:
d = defer.fail() d = defer.fail()
else: else:
@ -1678,13 +1661,13 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
def jsonrpc_get_est_cost(self, p): def jsonrpc_get_est_cost(self, **kwargs):
""" """
DEPRECATED. Use `stream_cost_estimate` instead DEPRECATED. Use `stream_cost_estimate` instead
""" """
return self.jsonrpc_stream_cost_estimate(p) return self.jsonrpc_stream_cost_estimate(**kwargs)
def jsonrpc_stream_cost_estimate(self, p): def jsonrpc_stream_cost_estimate(self, name, size=None):
""" """
Get estimated cost for a lbry stream Get estimated cost for a lbry stream
@ -1695,15 +1678,12 @@ class Daemon(AuthJSONRPCServer):
estimated cost estimated cost
""" """
size = p.get('size', None)
name = p.get(FileID.NAME, None)
d = self.get_est_cost(name, size) d = self.get_est_cost(name, size)
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_publish(self, p): def jsonrpc_publish(self, name, file_path, bid, metadata, fee=None):
""" """
Make a new name claim and publish associated data to lbrynet Make a new name claim and publish associated data to lbrynet
@ -1733,23 +1713,26 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda _: claim_out) d.addCallback(lambda _: claim_out)
return d return d
name = p[FileID.NAME] log.info("Publish: %s", {
log.info("Publish: %s", p) 'name': name,
'file_path': file_path,
'bid': bid,
'metadata': metadata,
'fee': fee,
})
verify_name_characters(name) verify_name_characters(name)
bid = p['bid']
if bid <= 0.0: if bid <= 0.0:
return defer.fail(Exception("Invalid bid")) return defer.fail(Exception("Invalid bid"))
try: try:
metadata = Metadata(p['metadata']) metadata = Metadata(metadata)
make_lbry_file = False make_lbry_file = False
sd_hash = metadata['sources']['lbry_sd_hash'] sd_hash = metadata['sources']['lbry_sd_hash']
log.info("Update publish for %s using existing stream", name) log.info("Update publish for %s using existing stream", name)
except ValidationError: except ValidationError:
make_lbry_file = True make_lbry_file = True
sd_hash = None sd_hash = None
metadata = p['metadata']
file_path = p['file_path']
if not file_path: if not file_path:
raise Exception("No file given to publish") raise Exception("No file given to publish")
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
@ -1760,8 +1743,8 @@ class Daemon(AuthJSONRPCServer):
d = self._resolve_name(name, force_refresh=True) d = self._resolve_name(name, force_refresh=True)
d.addErrback(lambda _: None) d.addErrback(lambda _: None)
if 'fee' in p: if fee is not None:
metadata['fee'] = p['fee'] metadata['fee'] = fee
assert len(metadata['fee']) == 1, "Too many fees" assert len(metadata['fee']) == 1, "Too many fees"
for c in metadata['fee']: for c in metadata['fee']:
if 'address' not in metadata['fee'][c]: if 'address' not in metadata['fee'][c]:
@ -1783,14 +1766,14 @@ class Daemon(AuthJSONRPCServer):
return d return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_abandon_claim(self, p): def jsonrpc_abandon_claim(self, **kwargs):
""" """
DEPRECATED. Use `claim_abandon` instead DEPRECATED. Use `claim_abandon` instead
""" """
return self.jsonrpc_claim_abandon(p) return self.jsonrpc_claim_abandon(**kwargs)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_claim_abandon(self, p): def jsonrpc_claim_abandon(self, txid, nout):
""" """
Abandon a name and reclaim credits from the claim Abandon a name and reclaim credits from the claim
@ -1801,21 +1784,18 @@ class Daemon(AuthJSONRPCServer):
txid : txid of resulting transaction if succesful txid : txid of resulting transaction if succesful
fee : fee paid for the transaction if succesful fee : fee paid for the transaction if succesful
""" """
if 'txid' not in p or 'nout' not in p:
return server.failure
def _disp(x): def _disp(x):
log.info("Abandoned name claim tx " + str(x)) log.info("Abandoned name claim tx " + str(x))
return self._render_response(x) return self._render_response(x)
d = defer.Deferred() d = defer.Deferred()
d.addCallback(lambda _: self.session.wallet.abandon_claim(p['txid'], p['nout'])) d.addCallback(lambda _: self.session.wallet.abandon_claim(txid, nout))
d.addCallback(_disp) d.addCallback(_disp)
d.callback(None) # TODO: is this line necessary??? d.callback(None) # TODO: is this line necessary???
return d return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_abandon_name(self, p): def jsonrpc_abandon_name(self, **kwargs):
""" """
DEPRECIATED, use abandon_claim DEPRECIATED, use abandon_claim
@ -1825,17 +1805,17 @@ class Daemon(AuthJSONRPCServer):
txid txid
""" """
return self.jsonrpc_abandon_claim(p) return self.jsonrpc_abandon_claim(**kwargs)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_support_claim(self, p): def jsonrpc_support_claim(self, **kwargs):
""" """
DEPRECATED. Use `claim_abandon` instead DEPRECATED. Use `claim_abandon` instead
""" """
return self.jsonrpc_claim_new_support(p) return self.jsonrpc_claim_new_support(**kwargs)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_claim_new_support(self, p): def jsonrpc_claim_new_support(self, name, claim_id, amount):
""" """
Support a name claim Support a name claim
@ -1849,16 +1829,13 @@ class Daemon(AuthJSONRPCServer):
fee : fee paid for the transaction if succesful fee : fee paid for the transaction if succesful
""" """
name = p[FileID.NAME]
claim_id = p['claim_id']
amount = p['amount']
d = self.session.wallet.support_claim(name, claim_id, amount) d = self.session.wallet.support_claim(name, claim_id, amount)
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
# TODO: merge this into claim_list # TODO: merge this into claim_list
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_get_my_claim(self, p): def jsonrpc_get_my_claim(self, name):
""" """
DEPRECATED. This method will be removed in a future release. DEPRECATED. This method will be removed in a future release.
@ -1870,7 +1847,7 @@ class Daemon(AuthJSONRPCServer):
claim info, False if no such claim exists claim info, False if no such claim exists
""" """
d = self.session.wallet.get_my_claim(p[FileID.NAME]) d = self.session.wallet.get_my_claim(name)
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@ -1905,19 +1882,19 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda claims: self._render_response(claims)) d.addCallback(lambda claims: self._render_response(claims))
return d return d
def jsonrpc_get_claims_for_name(self, p): def jsonrpc_get_claims_for_name(self, **kwargs):
""" """
DEPRECATED. Use `claim_list` instead. DEPRECATED. Use `claim_list` instead.
""" """
return self.jsonrpc_claim_list(p) return self.jsonrpc_claim_list(**kwargs)
def jsonrpc_get_claims_for_tx(self, p): def jsonrpc_get_claims_for_tx(self, **kwargs):
""" """
DEPRECATED. Use `claim_list` instead. DEPRECATED. Use `claim_list` instead.
""" """
return self.jsonrpc_claim_list(p) return self.jsonrpc_claim_list(**kwargs)
def jsonrpc_claim_list(self, p): def jsonrpc_claim_list(self, name=None, txid=None):
""" """
Get claims for a name Get claims for a name
@ -1928,10 +1905,10 @@ class Daemon(AuthJSONRPCServer):
list of name claims list of name claims
""" """
if FileID.NAME in p: if name is not None:
d = self.session.wallet.get_claims_for_name(p[FileID.NAME]) d = self.session.wallet.get_claims_for_name(name)
elif 'txid' in p: elif txid is not None:
d = self.session.wallet.get_claims_from_tx(p['txid']) d = self.session.wallet.get_claims_from_tx(txid)
else: else:
return server.failure return server.failure
@ -1960,13 +1937,13 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
def jsonrpc_get_transaction(self, p): def jsonrpc_get_transaction(self, txid):
""" """
DEPRECATED. Use `transaction_show` instead DEPRECATED. Use `transaction_show` instead
""" """
return self.jsonrpc_transaction_show(p) return self.jsonrpc_transaction_show(txid)
def jsonrpc_transaction_show(self, p): def jsonrpc_transaction_show(self, txid):
""" """
Get a decoded transaction from a txid Get a decoded transaction from a txid
@ -1976,19 +1953,19 @@ class Daemon(AuthJSONRPCServer):
JSON formatted transaction JSON formatted transaction
""" """
d = self.session.wallet.get_transaction(p['txid']) d = self.session.wallet.get_transaction(txid)
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_address_is_mine(self, p): def jsonrpc_address_is_mine(self, address):
""" """
DEPRECATED. Use `wallet_is_address_mine` instead DEPRECATED. Use `wallet_is_address_mine` instead
""" """
return self.jsonrpc_wallet_is_address_mine(p) return self.jsonrpc_wallet_is_address_mine(address)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_wallet_is_address_mine(self, p): def jsonrpc_wallet_is_address_mine(self, address):
""" """
Checks if an address is associated with the current wallet. Checks if an address is associated with the current wallet.
@ -1998,19 +1975,19 @@ class Daemon(AuthJSONRPCServer):
is_mine: bool is_mine: bool
""" """
d = self.session.wallet.address_is_mine(p['address']) d = self.session.wallet.address_is_mine(address)
d.addCallback(lambda is_mine: self._render_response(is_mine)) d.addCallback(lambda is_mine: self._render_response(is_mine))
return d return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_get_public_key_from_wallet(self, p): def jsonrpc_get_public_key_from_wallet(self, wallet):
""" """
DEPRECATED. Use `wallet_is_address_mine` instead DEPRECATED. Use `wallet_is_address_mine` instead
""" """
return self.jsonrpc_wallet_public_key(p) return self.jsonrpc_wallet_public_key(wallet)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_wallet_public_key(self, p): def jsonrpc_wallet_public_key(self, wallet):
""" """
Get public key from wallet address Get public key from wallet address
@ -2020,7 +1997,7 @@ class Daemon(AuthJSONRPCServer):
public key public key
""" """
d = self.session.wallet.get_pub_keys(p['wallet']) d = self.session.wallet.get_pub_keys(wallet)
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@ -2051,7 +2028,7 @@ class Daemon(AuthJSONRPCServer):
return d return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_send_amount_to_address(self, p): def jsonrpc_send_amount_to_address(self, amount, address):
""" """
Send credits to an address Send credits to an address
@ -2062,13 +2039,6 @@ class Daemon(AuthJSONRPCServer):
True if payment successfully scheduled True if payment successfully scheduled
""" """
if 'amount' in p and 'address' in p:
amount = p['amount']
address = p['address']
else:
# TODO: return a useful error message
return server.failure
reserved_points = self.session.wallet.reserve_points(address, amount) reserved_points = self.session.wallet.reserve_points(address, amount)
if reserved_points is None: if reserved_points is None:
return defer.fail(InsufficientFundsError()) return defer.fail(InsufficientFundsError())
@ -2076,13 +2046,13 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda _: self._render_response(True)) d.addCallback(lambda _: self._render_response(True))
return d return d
def jsonrpc_get_block(self, p): def jsonrpc_get_block(self, **kwargs):
""" """
DEPRECATED. Use `block_show` instead DEPRECATED. Use `block_show` instead
""" """
return self.jsonrpc_block_show(p) return self.jsonrpc_block_show(**kwargs)
def jsonrpc_block_show(self, p): def jsonrpc_block_show(self, blockhash=None, height=None):
""" """
Get contents of a block Get contents of a block
@ -2092,36 +2062,38 @@ class Daemon(AuthJSONRPCServer):
requested block requested block
""" """
if 'blockhash' in p: if blockhash is not None:
d = self.session.wallet.get_block(p['blockhash']) d = self.session.wallet.get_block(blockhash)
elif 'height' in p: elif height is not None:
d = self.session.wallet.get_block_info(p['height']) d = self.session.wallet.get_block_info(height)
d.addCallback(lambda blockhash: self.session.wallet.get_block(blockhash)) d.addCallback(lambda b: self.session.wallet.get_block(b))
else: else:
# TODO: return a useful error message # TODO: return a useful error message
return server.failure return server.failure
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_download_descriptor(self, p): def jsonrpc_download_descriptor(self, **kwargs):
""" """
DEPRECATED. Use `blob_get` instead DEPRECATED. Use `blob_get` instead
""" """
return self.jsonrpc_blob_get(p) return self.jsonrpc_blob_get(**kwargs)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_blob_get(self, p): def jsonrpc_blob_get(self, sd_hash, timeout=None):
""" """
Download and return a sd blob Download and return a sd blob
Args: Args:
sd_hash sd_hash
timeout (optional)
Returns Returns
sd blob, dict sd blob, dict
""" """
sd_hash = p[FileID.SD_HASH] if timeout is None:
timeout = p.get('timeout', conf.settings['sd_download_timeout']) timeout = conf.settings['sd_download_timeout']
d = self._download_sd_blob(sd_hash, timeout) d = self._download_sd_blob(sd_hash, timeout)
d.addCallbacks( d.addCallbacks(
lambda r: self._render_response(r), lambda r: self._render_response(r),
@ -2143,7 +2115,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
def jsonrpc_log(self, p): def jsonrpc_log(self, message):
""" """
DEPRECATED. This method will be removed in a future release. DEPRECATED. This method will be removed in a future release.
@ -2155,10 +2127,11 @@ class Daemon(AuthJSONRPCServer):
True True
""" """
log.info("API client log request: %s" % p['message']) log.info("API client log request: %s" % message)
return self._render_response(True) return self._render_response(True)
def jsonrpc_upload_log(self, p=None): def jsonrpc_upload_log(self, name_prefix=None, log_type=None, exclude_previous=True,
message=None, force=False):
""" """
DEPRECATED. This method will be removed in a future release. DEPRECATED. This method will be removed in a future release.
@ -2174,33 +2147,22 @@ class Daemon(AuthJSONRPCServer):
""" """
exclude_previous = True if name_prefix is not None:
force = False log_type = name_prefix + '_api'
log_type = None elif log_type is not None:
log_type += '_api'
if p:
if 'name_prefix' in p:
log_type = p['name_prefix'] + '_api'
elif 'log_type' in p:
log_type = p['log_type'] + '_api'
if 'exclude_previous' in p:
exclude_previous = p['exclude_previous']
if 'message' in p:
log.info("Upload log message: " + str(p['message']))
if 'force' in p:
force = p['force']
else: else:
log_type = "api" log_type = 'api'
if message is not None:
log.info("Upload log message: " + str(message))
d = self._upload_log(log_type=log_type, exclude_previous=exclude_previous, force=force) d = self._upload_log(log_type=log_type, exclude_previous=exclude_previous, force=force)
d.addCallback(lambda _: self._render_response(True)) d.addCallback(lambda _: self._render_response(True))
return d return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_configure_ui(self, p): def jsonrpc_configure_ui(self, branch=None, path=None, check_requirements=True):
""" """
Configure the UI being hosted Configure the UI being hosted
@ -2209,25 +2171,21 @@ class Daemon(AuthJSONRPCServer):
'path': path to a ui folder 'path': path to a ui folder
""" """
if 'check_requirements' in p: if path is not None:
check_require = p['check_requirements']
else:
check_require = True
if 'path' in p:
d = self.lbry_ui_manager.setup( d = self.lbry_ui_manager.setup(
user_specified=p['path'], check_requirements=check_require) user_specified=path, check_requirements=check_requirements)
elif 'branch' in p: elif branch is not None:
d = self.lbry_ui_manager.setup(branch=p['branch'], check_requirements=check_require) d = self.lbry_ui_manager.setup(branch=branch, check_requirements=check_requirements)
else: else:
d = self.lbry_ui_manager.setup(check_requirements=check_require) d = self.lbry_ui_manager.setup(check_requirements=check_requirements)
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
def jsonrpc_open(self, p): def jsonrpc_open(self, sd_hash):
""" """
Instruct the OS to open a file with its default program. Instruct the OS to open a file with its default program.
@ -2237,12 +2195,9 @@ class Daemon(AuthJSONRPCServer):
True, opens file True, opens file
""" """
if 'sd_hash' not in p: lbry_file = yield self._get_lbry_file(FileID.SD_HASH, sd_hash)
raise ValueError('sd_hash is required')
lbry_file = yield self._get_lbry_file(FileID.SD_HASH, p['sd_hash'])
if not lbry_file: if not lbry_file:
raise Exception('Unable to find file for {}'.format(p['sd_hash'])) raise Exception('Unable to find file for {}'.format(sd_hash))
try: try:
file_utils.start(lbry_file['download_path']) file_utils.start(lbry_file['download_path'])
@ -2252,7 +2207,7 @@ class Daemon(AuthJSONRPCServer):
@defer.inlineCallbacks @defer.inlineCallbacks
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_reveal(self, p): def jsonrpc_reveal(self, sd_hash):
""" """
Reveal a file or directory in file browser Reveal a file or directory in file browser
@ -2262,12 +2217,9 @@ class Daemon(AuthJSONRPCServer):
True, opens file browser True, opens file browser
""" """
if 'sd_hash' not in p: lbry_file = yield self._get_lbry_file(FileID.SD_HASH, sd_hash)
raise ValueError('sd_hash is required')
lbry_file = yield self._get_lbry_file(FileID.SD_HASH, p['sd_hash'])
if not lbry_file: if not lbry_file:
raise Exception('Unable to find file for {}'.format(p['sd_hash'])) raise Exception('Unable to find file for {}'.format(sd_hash))
try: try:
file_utils.reveal(lbry_file['download_path']) file_utils.reveal(lbry_file['download_path'])
@ -2275,13 +2227,13 @@ class Daemon(AuthJSONRPCServer):
pass pass
defer.returnValue(True) defer.returnValue(True)
def jsonrpc_get_peers_for_hash(self, p): def jsonrpc_get_peers_for_hash(self, blob_hash):
""" """
DEPRECATED. Use `peer_list` instead DEPRECATED. Use `peer_list` instead
""" """
return self.jsonrpc_peer_list(p) return self.jsonrpc_peer_list(blob_hash)
def jsonrpc_peer_list(self, p): def jsonrpc_peer_list(self, blob_hash):
""" """
Get peers for blob hash Get peers for blob hash
@ -2291,8 +2243,6 @@ class Daemon(AuthJSONRPCServer):
List of contacts List of contacts
""" """
blob_hash = p['blob_hash']
d = self.session.peer_finder.find_peers_for_blob(blob_hash) d = self.session.peer_finder.find_peers_for_blob(blob_hash)
d.addCallback(lambda r: [[c.host, c.port, c.is_available()] for c in r]) d.addCallback(lambda r: [[c.host, c.port, c.is_available()] for c in r])
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
@ -2318,7 +2268,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda _: self._render_response("Announced")) d.addCallback(lambda _: self._render_response("Announced"))
return d return d
def jsonrpc_reflect(self, p): def jsonrpc_reflect(self, sd_hash):
""" """
Reflect a stream Reflect a stream
@ -2328,7 +2278,6 @@ class Daemon(AuthJSONRPCServer):
True or traceback True or traceback
""" """
sd_hash = p[FileID.SD_HASH]
d = self._get_lbry_file(FileID.SD_HASH, sd_hash, return_json=False) d = self._get_lbry_file(FileID.SD_HASH, sd_hash, return_json=False)
d.addCallback(self._reflect) d.addCallback(self._reflect)
d.addCallbacks( d.addCallbacks(
@ -2390,7 +2339,7 @@ class Daemon(AuthJSONRPCServer):
d = self._render_response(self.session.blob_tracker.last_mean_availability) d = self._render_response(self.session.blob_tracker.last_mean_availability)
return d return d
def jsonrpc_get_availability(self, p): def jsonrpc_get_availability(self, name):
""" """
Get stream availability for a winning claim Get stream availability for a winning claim
@ -2411,7 +2360,7 @@ class Daemon(AuthJSONRPCServer):
else: else:
return 0.0 return 0.0
d = self._resolve_name(p[FileID.NAME], force_refresh=True) d = self._resolve_name(name, force_refresh=True)
d.addCallback(get_sd_hash) d.addCallback(get_sd_hash)
d.addCallback(self._download_sd_blob) d.addCallback(self._download_sd_blob)
d.addCallbacks( d.addCallbacks(
@ -2445,7 +2394,6 @@ class Daemon(AuthJSONRPCServer):
return d return d
def get_lbryum_version_from_github(): def get_lbryum_version_from_github():
return get_version_from_github('https://api.github.com/repos/lbryio/lbryum/releases/latest') return get_version_from_github('https://api.github.com/repos/lbryio/lbryum/releases/latest')

View file

@ -72,7 +72,7 @@ class AuthJSONRPCServer(AuthorizedBase):
Decorators: Decorators:
@AuthJSONRPCServer.auth_required: this requires the client @AuthJSONRPCServer.auth_required: this requires that the client
include a valid hmac authentication token in their request include a valid hmac authentication token in their request
Attributes: Attributes:
@ -195,10 +195,17 @@ class AuthJSONRPCServer(AuthorizedBase):
self._render_error(err, request, version) self._render_error(err, request, version)
return server.NOT_DONE_YET return server.NOT_DONE_YET
if args == EMPTY_PARAMS: if args == EMPTY_PARAMS or args == []:
d = defer.maybeDeferred(function) d = defer.maybeDeferred(function)
elif isinstance(args, dict):
d = defer.maybeDeferred(function, **args)
elif len(args) == 1 and isinstance(args[0], dict):
# TODO: this is for backwards compatibility. Remove this once API and UI are updated
# TODO: also delete EMPTY_PARAMS then
d = defer.maybeDeferred(function, **args[0])
else: else:
d = defer.maybeDeferred(function, *args) # d = defer.maybeDeferred(function, *args) # if we want to support positional args too
raise ValueError('Args must be a dict')
# finished_deferred will callback when the request is finished # finished_deferred will callback when the request is finished
# and errback if something went wrong. If the errback is # and errback if something went wrong. If the errback is

View file

@ -25,6 +25,18 @@ class Wallet(object):
def __init__(self): def __init__(self):
self.private_key = RSA.generate(1024) self.private_key = RSA.generate(1024)
self.encoded_public_key = self.private_key.publickey().exportKey() self.encoded_public_key = self.private_key.publickey().exportKey()
self._config = None
self.network = None
self.wallet = None
self.is_first_run = False
self.printed_retrieving_headers = False
self._start_check = None
self._catch_up_check = None
self._caught_up_counter = 0
self._lag_counter = 0
self.blocks_behind = 0
self.catchup_progress = 0
self.max_behind = 0
def start(self): def start(self):
return defer.succeed(True) return defer.succeed(True)

View file

@ -3,9 +3,10 @@ import requests
from tests.mocks import BlobAvailabilityTracker as DummyBlobAvailabilityTracker from tests.mocks import BlobAvailabilityTracker as DummyBlobAvailabilityTracker
from tests import util from tests import util
from twisted.internet import defer from twisted.internet import defer
from twisted.internet import reactor
from twisted.trial import unittest from twisted.trial import unittest
from lbrynet.lbrynet_daemon import Daemon from lbrynet.lbrynet_daemon import Daemon
from lbrynet.core import Session, PaymentRateManager from lbrynet.core import Session, PaymentRateManager, Wallet
from lbrynet.lbrynet_daemon.Daemon import Daemon as LBRYDaemon from lbrynet.lbrynet_daemon.Daemon import Daemon as LBRYDaemon
from lbrynet.lbrynet_daemon import ExchangeRateManager from lbrynet.lbrynet_daemon import ExchangeRateManager
from lbrynet import conf from lbrynet import conf
@ -50,14 +51,15 @@ def get_test_daemon(data_rate=None, generous=True, with_fee=False):
data_rate = conf.ADJUSTABLE_SETTINGS['data_rate'][1] data_rate = conf.ADJUSTABLE_SETTINGS['data_rate'][1]
rates = { rates = {
'BTCLBC': {'spot': 3.0, 'ts': util.DEFAULT_ISO_TIME + 1}, 'BTCLBC': {'spot': 3.0, 'ts': util.DEFAULT_ISO_TIME + 1},
'USDBTC': {'spot': 2.0, 'ts': util.DEFAULT_ISO_TIME + 2} 'USDBTC': {'spot': 2.0, 'ts': util.DEFAULT_ISO_TIME + 2}
} }
daemon = LBRYDaemon(None, None, upload_logs_on_shutdown=False) daemon = LBRYDaemon(None, None, upload_logs_on_shutdown=False)
daemon.session = mock.Mock(spec=Session.Session) daemon.session = mock.Mock(spec=Session.Session)
daemon.exchange_rate_manager = ExchangeRateManager.DummyExchangeRateManager(rates) daemon.exchange_rate_manager = ExchangeRateManager.DummyExchangeRateManager(rates)
base_prm = PaymentRateManager.BasePaymentRateManager(rate=data_rate) base_prm = PaymentRateManager.BasePaymentRateManager(rate=data_rate)
prm = PaymentRateManager.NegotiatedPaymentRateManager(base_prm, DummyBlobAvailabilityTracker(), generous=generous) prm = PaymentRateManager.NegotiatedPaymentRateManager(base_prm, DummyBlobAvailabilityTracker(),
generous=generous)
daemon.session.payment_rate_manager = prm daemon.session.payment_rate_manager = prm
metadata = { metadata = {
"author": "fake author", "author": "fake author",
@ -74,7 +76,8 @@ def get_test_daemon(data_rate=None, generous=True, with_fee=False):
"ver": "0.0.3" "ver": "0.0.3"
} }
if with_fee: if with_fee:
metadata.update({"fee": {"USD": {"address": "bQ6BGboPV2SpTMEP7wLNiAcnsZiH8ye6eA", "amount": 0.75}}}) metadata.update(
{"fee": {"USD": {"address": "bQ6BGboPV2SpTMEP7wLNiAcnsZiH8ye6eA", "amount": 0.75}}})
daemon._resolve_name = lambda _: defer.succeed(metadata) daemon._resolve_name = lambda _: defer.succeed(metadata)
return daemon return daemon
@ -94,7 +97,7 @@ class TestCostEst(unittest.TestCase):
size = 10000000 size = 10000000
fake_fee_amount = 4.5 fake_fee_amount = 4.5
data_rate = conf.ADJUSTABLE_SETTINGS['data_rate'][1] data_rate = conf.ADJUSTABLE_SETTINGS['data_rate'][1]
correct_result = size / 10**6 * data_rate + fake_fee_amount correct_result = size / 10 ** 6 * data_rate + fake_fee_amount
daemon = get_test_daemon(generous=False, with_fee=True) daemon = get_test_daemon(generous=False, with_fee=True)
self.assertEquals(daemon.get_est_cost("test", size).result, correct_result) self.assertEquals(daemon.get_est_cost("test", size).result, correct_result)
@ -107,6 +110,24 @@ class TestCostEst(unittest.TestCase):
def test_ungenerous_data_and_no_fee(self): def test_ungenerous_data_and_no_fee(self):
size = 10000000 size = 10000000
data_rate = conf.ADJUSTABLE_SETTINGS['data_rate'][1] data_rate = conf.ADJUSTABLE_SETTINGS['data_rate'][1]
correct_result = size / 10**6 * data_rate correct_result = size / 10 ** 6 * data_rate
daemon = get_test_daemon(generous=False) daemon = get_test_daemon(generous=False)
self.assertEquals(daemon.get_est_cost("test", size).result, correct_result) self.assertEquals(daemon.get_est_cost("test", size).result, correct_result)
class TestJsonRpc(unittest.TestCase):
def setUp(self):
mock_conf_settings(self)
util.resetTime(self)
self.test_daemon = get_test_daemon()
self.test_daemon.session.wallet = Wallet.LBRYumWallet(storage=Wallet.InMemoryStorage())
# self.test_daemon.session.wallet = FakeWallet()
def test_status(self):
d = defer.maybeDeferred(self.test_daemon.jsonrpc_status)
d.addCallback(lambda status: self.assertDictContainsSubset({'is_running': False}, status))
def test_help(self):
d = defer.maybeDeferred(self.test_daemon.jsonrpc_help, command='status')
d.addCallback(lambda result: self.assertSubstring('daemon status', result))
# self.assertSubstring('daemon status', d.result)