diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index cbe1a1a53..9789bfa14 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -1917,9 +1917,8 @@ class Daemon(metaclass=JSONRPCServerType): """ @requires(STREAM_MANAGER_COMPONENT) - async def jsonrpc_file_list( - self, sort=None, reverse=False, comparison=None, - wallet_id=None, page=None, page_size=None, **kwargs): + async def jsonrpc_file_list(self, sort=None, reverse=False, comparison=None, wallet_id=None, page=None, + page_size=None, **kwargs): """ List files limited by optional filters @@ -1940,17 +1939,17 @@ class Daemon(metaclass=JSONRPCServerType): --stream_hash= : (str) get file with matching stream hash --rowid= : (int) get file with matching row id --added_on= : (int) get file with matching time of insertion - --claim_id= : (str) get file with matching claim id - --outpoint= : (str) get file with matching claim outpoint + --claim_id= : (str) get file with matching claim id(s) + --outpoint= : (str) get file with matching claim outpoint(s) --txid= : (str) get file with matching claim txid --nout= : (int) get file with matching claim nout - --channel_claim_id= : (str) get file with matching channel claim id + --channel_claim_id= : (str) get file with matching channel claim id(s) --channel_name= : (str) get file with matching channel name --claim_name= : (str) get file with matching claim name --blobs_in_stream : (int) get file with matching blobs in stream --blobs_remaining= : (int) amount of remaining blobs to download --sort= : (str) field to sort by (one of the above filter fields) - --comparison= : (str) logical comparison, (eq | ne | g | ge | l | le) + --comparison= : (str) logical comparison, (eq | ne | g | ge | l | le | in) --page= : (int) page to return during paginating --page_size= : (int) number of items on page during pagination --wallet_id= : (str) add purchase receipts from this wallet @@ -1960,6 +1959,7 @@ class Daemon(metaclass=JSONRPCServerType): wallet = self.wallet_manager.get_wallet_or_default(wallet_id) sort = sort or 'rowid' comparison = comparison or 'eq' + paginated = paginate_list( self.stream_manager.get_filtered_streams(sort, reverse, comparison, **kwargs), page, page_size ) diff --git a/lbry/stream/stream_manager.py b/lbry/stream/stream_manager.py index 0ff206936..4fb37e99a 100644 --- a/lbry/stream/stream_manager.py +++ b/lbry/stream/stream_manager.py @@ -23,6 +23,9 @@ if typing.TYPE_CHECKING: from lbry.extras.daemon.analytics import AnalyticsManager from lbry.extras.daemon.storage import SQLiteStorage, StoredContentClaim from lbry.extras.daemon.exchange_rate_manager import ExchangeRateManager + from lbry.wallet.transaction import Transaction + from lbry.wallet.manager import WalletManager + from lbry.wallet.wallet import Wallet log = logging.getLogger(__name__) @@ -46,6 +49,12 @@ FILTER_FIELDS = [ 'blobs_in_stream' ] +SET_FILTER_FIELDS = { + "claim_ids": "claim_id", + "channel_claim_ids": "channel_claim_id", + "outpoints": "outpoint" +} + COMPARISON_OPERATORS = { 'eq': lambda a, b: a == b, 'ne': lambda a, b: a != b, @@ -53,6 +62,7 @@ COMPARISON_OPERATORS = { 'l': lambda a, b: a < b, 'ge': lambda a, b: a >= b, 'le': lambda a, b: a <= b, + 'in': lambda a, b: a in b } @@ -276,15 +286,34 @@ class StreamManager: raise ValueError(f"'{comparison}' is not a valid comparison") if 'full_status' in search_by: del search_by['full_status'] + for search in search_by: if search not in FILTER_FIELDS: raise ValueError(f"'{search}' is not a valid search operation") + + compare_sets = {} + if isinstance(search_by.get('claim_id'), list): + compare_sets['claim_ids'] = search_by.pop('claim_id') + if isinstance(search_by.get('outpoint'), list): + compare_sets['outpoints'] = search_by.pop('outpoint') + if isinstance(search_by.get('channel_claim_id'), list): + compare_sets['channel_claim_ids'] = search_by.pop('channel_claim_id') + if search_by: comparison = comparison or 'eq' streams = [] for stream in self.streams.values(): + matched = False + for set_search, val in compare_sets.items(): + if COMPARISON_OPERATORS[comparison](getattr(stream, SET_FILTER_FIELDS[set_search]), val): + streams.append(stream) + matched = True + break + if matched: + continue for search, val in search_by.items(): - if COMPARISON_OPERATORS[comparison](getattr(stream, search), val): + this_stream = getattr(stream, search) + if COMPARISON_OPERATORS[comparison](this_stream, val): streams.append(stream) break else: diff --git a/tests/integration/datanetwork/test_file_commands.py b/tests/integration/datanetwork/test_file_commands.py index 24d9b1e71..1ab06d088 100644 --- a/tests/integration/datanetwork/test_file_commands.py +++ b/tests/integration/datanetwork/test_file_commands.py @@ -21,6 +21,11 @@ class FileCommands(CommandTestCase): self.assertEqual(file1['claim_name'], 'foo') self.assertEqual(file2['claim_name'], 'foo2') + self.assertItemCount(await self.daemon.jsonrpc_file_list(claim_id=[file1['claim_id'], file2['claim_id']]), 2) + self.assertItemCount(await self.daemon.jsonrpc_file_list(claim_id=file1['claim_id']), 1) + self.assertItemCount(await self.daemon.jsonrpc_file_list(outpoint=[file1['outpoint'], file2['outpoint']]), 2) + self.assertItemCount(await self.daemon.jsonrpc_file_list(outpoint=file1['outpoint']), 1) + await self.daemon.jsonrpc_file_delete(claim_name='foo') self.assertItemCount(await self.daemon.jsonrpc_file_list(), 1) await self.daemon.jsonrpc_file_delete(claim_name='foo2')