From 86ba7ffd5ceaa7c7cb98cbad7f935c08de3f2bad Mon Sep 17 00:00:00 2001 From: Alex Grintsvayg Date: Wed, 25 Jan 2017 20:06:17 -0500 Subject: [PATCH] explicitly list jsonrpc params in function signature. add jsonrpc tests --- lbrynet/lbrynet_daemon/Daemon.py | 334 ++++++++++------------- lbrynet/lbrynet_daemon/auth/server.py | 13 +- tests/mocks.py | 12 + tests/unit/lbrynet_daemon/test_Daemon.py | 37 ++- 4 files changed, 192 insertions(+), 204 deletions(-) diff --git a/lbrynet/lbrynet_daemon/Daemon.py b/lbrynet/lbrynet_daemon/Daemon.py index e46bcdfe5..95e9a3f80 100644 --- a/lbrynet/lbrynet_daemon/Daemon.py +++ b/lbrynet/lbrynet_daemon/Daemon.py @@ -1031,7 +1031,6 @@ class Daemon(AuthJSONRPCServer): ) return run_reflector_factory(factory) - ############################################################################ # # # JSON-RPC API methods start here # @@ -1039,7 +1038,7 @@ class Daemon(AuthJSONRPCServer): ############################################################################ @defer.inlineCallbacks - def jsonrpc_status(self, p={}): + def jsonrpc_status(self, session_status=False, blockchain_status=False): """ Return daemon status @@ -1068,17 +1067,17 @@ class Daemon(AuthJSONRPCServer): }, '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' ), } - if p.get('session_status', False): + if session_status: blobs = yield self.session.blob_manager.get_all_verified_blobs() response['session_status'] = { 'managed_blobs': len(blobs), '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 local_height = self.session.wallet.network.get_local_height() remote_height = self.session.wallet.network.get_server_height() @@ -1091,7 +1090,7 @@ class Daemon(AuthJSONRPCServer): """ 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( x['blockchain_status']['best_blockhash'])) return d @@ -1141,7 +1140,7 @@ class Daemon(AuthJSONRPCServer): """ 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'])) return d @@ -1150,7 +1149,7 @@ class Daemon(AuthJSONRPCServer): 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({ 'lbry_id': x['lbry_id'], 'managed_blobs': x['session_status']['managed_blobs'], @@ -1162,7 +1161,7 @@ class Daemon(AuthJSONRPCServer): """ 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'])) return d @@ -1210,7 +1209,7 @@ class Daemon(AuthJSONRPCServer): log.info("Get version info: " + json.dumps(msg)) return self._render_response(msg) - def jsonrpc_report_bug(self, p): + def jsonrpc_report_bug(self, message=None): """ Report a bug to slack @@ -1220,9 +1219,8 @@ class Daemon(AuthJSONRPCServer): True if successful """ - bug_message = p['message'] 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) def jsonrpc_get_settings(self): @@ -1233,10 +1231,8 @@ class Daemon(AuthJSONRPCServer): def jsonrpc_settings_get(self): """ - Get lbrynet daemon settings + Get daemon settings - Args: - None Returns: 'run_on_startup': bool, 'data_rate': float, @@ -1259,16 +1255,16 @@ class Daemon(AuthJSONRPCServer): return self._render_response(conf.settings.get_current_settings_dict()) @AuthJSONRPCServer.auth_required - def jsonrpc_set_settings(self, p): + def jsonrpc_set_settings(self, **kwargs): """ DEPRECATED. Use `settings_set` instead. """ - return self.jsonrpc_settings_set(p) + return self.jsonrpc_settings_set(**kwargs) @AuthJSONRPCServer.auth_required - def jsonrpc_settings_set(self, p): + def jsonrpc_settings_set(self, **kwargs): """ - Set lbrynet daemon settings + Set daemon settings Args: 'run_on_startup': bool, @@ -1288,7 +1284,7 @@ class Daemon(AuthJSONRPCServer): "Set daemon settings to %s", 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.addCallback(lambda _: _log_settings_change()) d.addCallback( @@ -1296,7 +1292,7 @@ class Daemon(AuthJSONRPCServer): return d - def jsonrpc_help(self, p=None): + def jsonrpc_help(self, command=None): """ Return a useful message for an API command @@ -1307,16 +1303,17 @@ class Daemon(AuthJSONRPCServer): otherwise returns general help message """ - if p and 'command' in p: - 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: + if command is None: 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): """ Return a list of available commands @@ -1394,13 +1391,13 @@ class Daemon(AuthJSONRPCServer): return d - def jsonrpc_get_lbry_file(self, p): + def jsonrpc_get_lbry_file(self, **kwargs): """ 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 @@ -1420,19 +1417,19 @@ class Daemon(AuthJSONRPCServer): 'upload_allowed': bool '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)) return d - def _get_deferred_for_lbry_file(self, p): + def _get_deferred_for_lbry_file(self, search_fields): try: - searchtype, value = get_lbry_file_search_value(p) + searchtype, value = get_lbry_file_search_value(search_fields) except NoValidSearch: return defer.fail() else: 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 @@ -1442,9 +1439,6 @@ class Daemon(AuthJSONRPCServer): metadata from name claim """ - force = p.get('force', False) - - name = p.get(FileID.NAME) if not name: return self._render_response(None) @@ -1452,13 +1446,13 @@ class Daemon(AuthJSONRPCServer): d.addCallback(self._render_response) return d - def jsonrpc_get_claim_info(self, p): + def jsonrpc_get_claim_info(self, **kwargs): """ 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 @@ -1479,9 +1473,6 @@ class Daemon(AuthJSONRPCServer): r['amount'] = float(r['amount']) / 10 ** 8 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.addCallback(_convert_amount_to_float) d.addCallback(lambda r: self._render_response(r)) @@ -1510,7 +1501,7 @@ class Daemon(AuthJSONRPCServer): @AuthJSONRPCServer.auth_required @defer.inlineCallbacks - def jsonrpc_get(self, p): + def jsonrpc_get(self, **kwargs): """ Download stream from a LBRY uri. @@ -1526,7 +1517,7 @@ class Daemon(AuthJSONRPCServer): 'stream_hash': hex string 'path': path of download """ - params = self._process_get_parameters(p) + params = self._process_get_parameters(kwargs) if not params.name: # TODO: return a useful error message here, like "name argument is required" defer.returnValue(server.failure) @@ -1587,24 +1578,22 @@ class Daemon(AuthJSONRPCServer): defer.returnValue(response) @AuthJSONRPCServer.auth_required - def jsonrpc_stop_lbry_file(self, p): + def jsonrpc_stop_lbry_file(self, **kwargs): """ DEPRECATED. Use `file_seed status=stop` instead. """ - p['status'] = 'stop' - return self.jsonrpc_file_seed(p) + return self.jsonrpc_file_seed(status='stop', **kwargs) @AuthJSONRPCServer.auth_required - def jsonrpc_start_lbry_file(self, p): + def jsonrpc_start_lbry_file(self, **kwargs): """ DEPRECATED. Use `file_seed status=start` instead. """ - p['status'] = 'start' - return self.jsonrpc_file_seed(p) + return self.jsonrpc_file_seed(status='start', **kwargs) @AuthJSONRPCServer.auth_required @defer.inlineCallbacks - def jsonrpc_file_seed(self, p): + def jsonrpc_file_seed(self, status, **kwargs): """ Start or stop seeding a file @@ -1617,13 +1606,10 @@ class Daemon(AuthJSONRPCServer): confirmation message """ - status = p.get('status', None) - if status is None: - raise Exception('"status" option required') if status not in ['start', '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) if not lbry_file: 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) @AuthJSONRPCServer.auth_required - def jsonrpc_file_delete(self, p): + def jsonrpc_file_delete(self, delete_target_file=True, **kwargs): """ Delete a lbry file @@ -1656,19 +1642,16 @@ class Daemon(AuthJSONRPCServer): 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): if not f: return False 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) return d try: - searchtype, value = get_lbry_file_search_value(p) + searchtype, value = get_lbry_file_search_value(kwargs) except NoValidSearch: d = defer.fail() else: @@ -1678,13 +1661,13 @@ class Daemon(AuthJSONRPCServer): d.addCallback(lambda r: self._render_response(r)) return d - def jsonrpc_get_est_cost(self, p): + def jsonrpc_get_est_cost(self, **kwargs): """ 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 @@ -1695,15 +1678,12 @@ class Daemon(AuthJSONRPCServer): estimated cost """ - size = p.get('size', None) - name = p.get(FileID.NAME, None) - d = self.get_est_cost(name, size) d.addCallback(lambda r: self._render_response(r)) return d @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 @@ -1733,23 +1713,26 @@ class Daemon(AuthJSONRPCServer): d.addCallback(lambda _: claim_out) return d - name = p[FileID.NAME] - log.info("Publish: %s", p) + log.info("Publish: %s", { + 'name': name, + 'file_path': file_path, + 'bid': bid, + 'metadata': metadata, + 'fee': fee, + }) verify_name_characters(name) - bid = p['bid'] + if bid <= 0.0: return defer.fail(Exception("Invalid bid")) try: - metadata = Metadata(p['metadata']) + metadata = Metadata(metadata) make_lbry_file = False sd_hash = metadata['sources']['lbry_sd_hash'] log.info("Update publish for %s using existing stream", name) except ValidationError: make_lbry_file = True sd_hash = None - metadata = p['metadata'] - file_path = p['file_path'] if not file_path: raise Exception("No file given to publish") if not os.path.isfile(file_path): @@ -1760,8 +1743,8 @@ class Daemon(AuthJSONRPCServer): d = self._resolve_name(name, force_refresh=True) d.addErrback(lambda _: None) - if 'fee' in p: - metadata['fee'] = p['fee'] + if fee is not None: + metadata['fee'] = fee assert len(metadata['fee']) == 1, "Too many fees" for c in metadata['fee']: if 'address' not in metadata['fee'][c]: @@ -1783,14 +1766,14 @@ class Daemon(AuthJSONRPCServer): return d @AuthJSONRPCServer.auth_required - def jsonrpc_abandon_claim(self, p): + def jsonrpc_abandon_claim(self, **kwargs): """ DEPRECATED. Use `claim_abandon` instead """ - return self.jsonrpc_claim_abandon(p) + return self.jsonrpc_claim_abandon(**kwargs) @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 @@ -1801,21 +1784,18 @@ class Daemon(AuthJSONRPCServer): txid : txid of resulting 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): log.info("Abandoned name claim tx " + str(x)) return self._render_response(x) 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.callback(None) # TODO: is this line necessary??? return d @AuthJSONRPCServer.auth_required - def jsonrpc_abandon_name(self, p): + def jsonrpc_abandon_name(self, **kwargs): """ DEPRECIATED, use abandon_claim @@ -1825,17 +1805,17 @@ class Daemon(AuthJSONRPCServer): txid """ - return self.jsonrpc_abandon_claim(p) + return self.jsonrpc_abandon_claim(**kwargs) @AuthJSONRPCServer.auth_required - def jsonrpc_support_claim(self, p): + def jsonrpc_support_claim(self, **kwargs): """ DEPRECATED. Use `claim_abandon` instead """ - return self.jsonrpc_claim_new_support(p) + return self.jsonrpc_claim_new_support(**kwargs) @AuthJSONRPCServer.auth_required - def jsonrpc_claim_new_support(self, p): + def jsonrpc_claim_new_support(self, name, claim_id, amount): """ Support a name claim @@ -1849,16 +1829,13 @@ class Daemon(AuthJSONRPCServer): 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.addCallback(lambda r: self._render_response(r)) return d # TODO: merge this into claim_list @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. @@ -1870,7 +1847,7 @@ class Daemon(AuthJSONRPCServer): 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)) return d @@ -1905,19 +1882,19 @@ class Daemon(AuthJSONRPCServer): d.addCallback(lambda claims: self._render_response(claims)) return d - def jsonrpc_get_claims_for_name(self, p): + def jsonrpc_get_claims_for_name(self, **kwargs): """ 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. """ - 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 @@ -1928,10 +1905,10 @@ class Daemon(AuthJSONRPCServer): list of name claims """ - if FileID.NAME in p: - d = self.session.wallet.get_claims_for_name(p[FileID.NAME]) - elif 'txid' in p: - d = self.session.wallet.get_claims_from_tx(p['txid']) + if name is not None: + d = self.session.wallet.get_claims_for_name(name) + elif txid is not None: + d = self.session.wallet.get_claims_from_tx(txid) else: return server.failure @@ -1960,13 +1937,13 @@ class Daemon(AuthJSONRPCServer): d.addCallback(lambda r: self._render_response(r)) return d - def jsonrpc_get_transaction(self, p): + def jsonrpc_get_transaction(self, txid): """ 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 @@ -1976,19 +1953,19 @@ class Daemon(AuthJSONRPCServer): 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)) return d @AuthJSONRPCServer.auth_required - def jsonrpc_address_is_mine(self, p): + def jsonrpc_address_is_mine(self, address): """ 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 - 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. @@ -1998,19 +1975,19 @@ class Daemon(AuthJSONRPCServer): 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)) return d @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 """ - return self.jsonrpc_wallet_public_key(p) + return self.jsonrpc_wallet_public_key(wallet) @AuthJSONRPCServer.auth_required - def jsonrpc_wallet_public_key(self, p): + def jsonrpc_wallet_public_key(self, wallet): """ Get public key from wallet address @@ -2020,7 +1997,7 @@ class Daemon(AuthJSONRPCServer): 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)) @AuthJSONRPCServer.auth_required @@ -2051,7 +2028,7 @@ class Daemon(AuthJSONRPCServer): return d @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 @@ -2062,13 +2039,6 @@ class Daemon(AuthJSONRPCServer): 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) if reserved_points is None: return defer.fail(InsufficientFundsError()) @@ -2076,13 +2046,13 @@ class Daemon(AuthJSONRPCServer): d.addCallback(lambda _: self._render_response(True)) return d - def jsonrpc_get_block(self, p): + def jsonrpc_get_block(self, **kwargs): """ 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 @@ -2092,36 +2062,38 @@ class Daemon(AuthJSONRPCServer): requested block """ - if 'blockhash' in p: - d = self.session.wallet.get_block(p['blockhash']) - elif 'height' in p: - d = self.session.wallet.get_block_info(p['height']) - d.addCallback(lambda blockhash: self.session.wallet.get_block(blockhash)) + if blockhash is not None: + d = self.session.wallet.get_block(blockhash) + elif height is not None: + d = self.session.wallet.get_block_info(height) + d.addCallback(lambda b: self.session.wallet.get_block(b)) else: # TODO: return a useful error message return server.failure + d.addCallback(lambda r: self._render_response(r)) return d @AuthJSONRPCServer.auth_required - def jsonrpc_download_descriptor(self, p): + def jsonrpc_download_descriptor(self, **kwargs): """ DEPRECATED. Use `blob_get` instead """ - return self.jsonrpc_blob_get(p) + return self.jsonrpc_blob_get(**kwargs) @AuthJSONRPCServer.auth_required - def jsonrpc_blob_get(self, p): + def jsonrpc_blob_get(self, sd_hash, timeout=None): """ Download and return a sd blob Args: sd_hash + timeout (optional) Returns sd blob, dict """ - sd_hash = p[FileID.SD_HASH] - timeout = p.get('timeout', conf.settings['sd_download_timeout']) + if timeout is None: + timeout = conf.settings['sd_download_timeout'] d = self._download_sd_blob(sd_hash, timeout) d.addCallbacks( lambda r: self._render_response(r), @@ -2143,7 +2115,7 @@ class Daemon(AuthJSONRPCServer): d.addCallback(lambda r: self._render_response(r)) return d - def jsonrpc_log(self, p): + def jsonrpc_log(self, message): """ DEPRECATED. This method will be removed in a future release. @@ -2155,10 +2127,11 @@ class Daemon(AuthJSONRPCServer): True """ - log.info("API client log request: %s" % p['message']) + log.info("API client log request: %s" % message) 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. @@ -2174,33 +2147,22 @@ class Daemon(AuthJSONRPCServer): """ - exclude_previous = True - force = False - log_type = None - - 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'] + if name_prefix is not None: + log_type = name_prefix + '_api' + elif log_type is not None: + log_type += '_api' 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.addCallback(lambda _: self._render_response(True)) return d @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 @@ -2209,25 +2171,21 @@ class Daemon(AuthJSONRPCServer): 'path': path to a ui folder """ - if 'check_requirements' in p: - check_require = p['check_requirements'] - else: - check_require = True - - if 'path' in p: + if path is not None: d = self.lbry_ui_manager.setup( - user_specified=p['path'], check_requirements=check_require) - elif 'branch' in p: - d = self.lbry_ui_manager.setup(branch=p['branch'], check_requirements=check_require) + user_specified=path, check_requirements=check_requirements) + elif branch is not None: + d = self.lbry_ui_manager.setup(branch=branch, check_requirements=check_requirements) 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)) return d @AuthJSONRPCServer.auth_required @defer.inlineCallbacks - def jsonrpc_open(self, p): + def jsonrpc_open(self, sd_hash): """ Instruct the OS to open a file with its default program. @@ -2237,12 +2195,9 @@ class Daemon(AuthJSONRPCServer): True, opens file """ - if 'sd_hash' not in p: - raise ValueError('sd_hash is required') - - lbry_file = yield self._get_lbry_file(FileID.SD_HASH, p['sd_hash']) + lbry_file = yield self._get_lbry_file(FileID.SD_HASH, sd_hash) 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: file_utils.start(lbry_file['download_path']) @@ -2252,7 +2207,7 @@ class Daemon(AuthJSONRPCServer): @defer.inlineCallbacks @AuthJSONRPCServer.auth_required - def jsonrpc_reveal(self, p): + def jsonrpc_reveal(self, sd_hash): """ Reveal a file or directory in file browser @@ -2262,12 +2217,9 @@ class Daemon(AuthJSONRPCServer): True, opens file browser """ - if 'sd_hash' not in p: - raise ValueError('sd_hash is required') - - lbry_file = yield self._get_lbry_file(FileID.SD_HASH, p['sd_hash']) + lbry_file = yield self._get_lbry_file(FileID.SD_HASH, sd_hash) 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: file_utils.reveal(lbry_file['download_path']) @@ -2275,13 +2227,13 @@ class Daemon(AuthJSONRPCServer): pass 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 """ - 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 @@ -2291,8 +2243,6 @@ class Daemon(AuthJSONRPCServer): List of contacts """ - blob_hash = p['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: self._render_response(r)) @@ -2318,7 +2268,7 @@ class Daemon(AuthJSONRPCServer): d.addCallback(lambda _: self._render_response("Announced")) return d - def jsonrpc_reflect(self, p): + def jsonrpc_reflect(self, sd_hash): """ Reflect a stream @@ -2328,7 +2278,6 @@ class Daemon(AuthJSONRPCServer): True or traceback """ - sd_hash = p[FileID.SD_HASH] d = self._get_lbry_file(FileID.SD_HASH, sd_hash, return_json=False) d.addCallback(self._reflect) d.addCallbacks( @@ -2390,7 +2339,7 @@ class Daemon(AuthJSONRPCServer): d = self._render_response(self.session.blob_tracker.last_mean_availability) return d - def jsonrpc_get_availability(self, p): + def jsonrpc_get_availability(self, name): """ Get stream availability for a winning claim @@ -2411,7 +2360,7 @@ class Daemon(AuthJSONRPCServer): else: 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(self._download_sd_blob) d.addCallbacks( @@ -2445,7 +2394,6 @@ class Daemon(AuthJSONRPCServer): return d - def get_lbryum_version_from_github(): return get_version_from_github('https://api.github.com/repos/lbryio/lbryum/releases/latest') diff --git a/lbrynet/lbrynet_daemon/auth/server.py b/lbrynet/lbrynet_daemon/auth/server.py index 136cd3b49..7ad3ea56b 100644 --- a/lbrynet/lbrynet_daemon/auth/server.py +++ b/lbrynet/lbrynet_daemon/auth/server.py @@ -72,7 +72,7 @@ class AuthJSONRPCServer(AuthorizedBase): 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 Attributes: @@ -195,10 +195,17 @@ class AuthJSONRPCServer(AuthorizedBase): self._render_error(err, request, version) return server.NOT_DONE_YET - if args == EMPTY_PARAMS: + if args == EMPTY_PARAMS or args == []: 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: - 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 # and errback if something went wrong. If the errback is diff --git a/tests/mocks.py b/tests/mocks.py index 2ac30e175..96845ad43 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -25,6 +25,18 @@ class Wallet(object): def __init__(self): self.private_key = RSA.generate(1024) 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): return defer.succeed(True) diff --git a/tests/unit/lbrynet_daemon/test_Daemon.py b/tests/unit/lbrynet_daemon/test_Daemon.py index 759d2cf9d..4dc338f94 100644 --- a/tests/unit/lbrynet_daemon/test_Daemon.py +++ b/tests/unit/lbrynet_daemon/test_Daemon.py @@ -3,9 +3,10 @@ import requests from tests.mocks import BlobAvailabilityTracker as DummyBlobAvailabilityTracker from tests import util from twisted.internet import defer +from twisted.internet import reactor from twisted.trial import unittest 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 import ExchangeRateManager 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] rates = { - 'BTCLBC': {'spot': 3.0, 'ts': util.DEFAULT_ISO_TIME + 1}, - 'USDBTC': {'spot': 2.0, 'ts': util.DEFAULT_ISO_TIME + 2} - } + 'BTCLBC': {'spot': 3.0, 'ts': util.DEFAULT_ISO_TIME + 1}, + 'USDBTC': {'spot': 2.0, 'ts': util.DEFAULT_ISO_TIME + 2} + } daemon = LBRYDaemon(None, None, upload_logs_on_shutdown=False) daemon.session = mock.Mock(spec=Session.Session) daemon.exchange_rate_manager = ExchangeRateManager.DummyExchangeRateManager(rates) 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 metadata = { "author": "fake author", @@ -74,7 +76,8 @@ def get_test_daemon(data_rate=None, generous=True, with_fee=False): "ver": "0.0.3" } 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) return daemon @@ -94,7 +97,7 @@ class TestCostEst(unittest.TestCase): size = 10000000 fake_fee_amount = 4.5 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) 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): size = 10000000 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) 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)