forked from LBRYCommunity/lbry-sdk
fixes and tests for publish command
This commit is contained in:
parent
148481a5ca
commit
7860b956ff
3 changed files with 87 additions and 21 deletions
|
@ -1967,7 +1967,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
Create or update a stream claim at a given name (use 'stream create/update' for more control).
|
Create or update a stream claim at a given name (use 'stream create/update' for more control).
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
publish (<name> | --name=<name>) (<bid> | --bid=<bid>) (<file_path> | --file_path=<file_path>)
|
publish (<name> | --name=<name>) [--bid=<bid>] [--file_path=<file_path>]
|
||||||
[<stream_type> | --stream_type=<stream_type>] [--tags=<tags>...]
|
[<stream_type> | --stream_type=<stream_type>] [--tags=<tags>...]
|
||||||
[--fee_currency=<fee_currency>] [--fee_amount=<fee_amount>] [--fee_address=<fee_address>]
|
[--fee_currency=<fee_currency>] [--fee_amount=<fee_amount>] [--fee_address=<fee_address>]
|
||||||
[--title=<title>] [--description=<description>] [--author=<author>] [--language=<language>]
|
[--title=<title>] [--description=<description>] [--author=<author>] [--language=<language>]
|
||||||
|
@ -1975,7 +1975,8 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
[--release_time=<release_time>]
|
[--release_time=<release_time>]
|
||||||
[--video_width=<video_width>] [--video_height=<video_height>] [--video_duration=<video_duration>]
|
[--video_width=<video_width>] [--video_height=<video_height>] [--video_duration=<video_duration>]
|
||||||
[--image_width=<image_width>] [--image_height=<image_height>] [--audio_duration=<audio_duration>]
|
[--image_width=<image_width>] [--image_height=<image_height>] [--audio_duration=<audio_duration>]
|
||||||
[--channel_id=<channel_id>] [--channel_account_id=<channel_account_id>...]
|
[--channel_id=<channel_id>] [--channel_name=<channel_name>]
|
||||||
|
[--channel_account_id=<channel_account_id>...]
|
||||||
[--account_id=<account_id>] [--claim_address=<claim_address>] [--preview]
|
[--account_id=<account_id>] [--claim_address=<claim_address>] [--preview]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
@ -2011,6 +2012,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
--audio_duration=<duration> : (int) audio duration in seconds, an attempt will be made to
|
--audio_duration=<duration> : (int) audio duration in seconds, an attempt will be made to
|
||||||
calculate this automatically if not provided
|
calculate this automatically if not provided
|
||||||
--channel_id=<channel_id> : (str) claim id of the publisher channel
|
--channel_id=<channel_id> : (str) claim id of the publisher channel
|
||||||
|
--channel_name=<channel_name> : (str) name of publisher channel
|
||||||
--channel_account_id=<channel_id>: (str) one or more account ids for accounts to look in
|
--channel_account_id=<channel_id>: (str) one or more account ids for accounts to look in
|
||||||
for channel certificates, defaults to all accounts.
|
for channel certificates, defaults to all accounts.
|
||||||
--account_id=<account_id> : (str) account to use for funding the transaction
|
--account_id=<account_id> : (str) account to use for funding the transaction
|
||||||
|
@ -2022,6 +2024,10 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
account = self.get_account_or_default(kwargs.get('account_id'))
|
account = self.get_account_or_default(kwargs.get('account_id'))
|
||||||
claims = await account.get_claims(claim_name=name)
|
claims = await account.get_claims(claim_name=name)
|
||||||
if len(claims) == 0:
|
if len(claims) == 0:
|
||||||
|
if 'bid' not in kwargs:
|
||||||
|
raise Exception("'bid' is a required argument for new publishes.")
|
||||||
|
if 'file_path' not in kwargs:
|
||||||
|
raise Exception("'file_path' is a required argument for new publishes.")
|
||||||
return await self.jsonrpc_stream_create(name, **kwargs)
|
return await self.jsonrpc_stream_create(name, **kwargs)
|
||||||
elif len(claims) == 1:
|
elif len(claims) == 1:
|
||||||
assert claims[0].claim.is_stream, f"Claim at name '{name}' is not a stream claim."
|
assert claims[0].claim.is_stream, f"Claim at name '{name}' is not a stream claim."
|
||||||
|
@ -2035,7 +2041,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
conditions=[WALLET_IS_UNLOCKED])
|
conditions=[WALLET_IS_UNLOCKED])
|
||||||
async def jsonrpc_stream_create(
|
async def jsonrpc_stream_create(
|
||||||
self, name, bid, file_path, allow_duplicate_name=False,
|
self, name, bid, file_path, allow_duplicate_name=False,
|
||||||
channel_id=None, channel_account_id=None,
|
channel_id=None, channel_name=None, channel_account_id=None,
|
||||||
account_id=None, claim_address=None, preview=False, **kwargs):
|
account_id=None, claim_address=None, preview=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Make a new stream claim and announce the associated file to lbrynet.
|
Make a new stream claim and announce the associated file to lbrynet.
|
||||||
|
@ -2050,7 +2056,8 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
[--release_time=<release_time>]
|
[--release_time=<release_time>]
|
||||||
[--video_width=<video_width>] [--video_height=<video_height>] [--video_duration=<video_duration>]
|
[--video_width=<video_width>] [--video_height=<video_height>] [--video_duration=<video_duration>]
|
||||||
[--image_width=<image_width>] [--image_height=<image_height>] [--audio_duration=<audio_duration>]
|
[--image_width=<image_width>] [--image_height=<image_height>] [--audio_duration=<audio_duration>]
|
||||||
[--channel_id=<channel_id>] [--channel_account_id=<channel_account_id>...]
|
[--channel_id=<channel_id>] [--channel_name=<channel_name>]
|
||||||
|
[--channel_account_id=<channel_account_id>...]
|
||||||
[--account_id=<account_id>] [--claim_address=<claim_address>] [--preview]
|
[--account_id=<account_id>] [--claim_address=<claim_address>] [--preview]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
@ -2097,7 +2104,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
"""
|
"""
|
||||||
self.valid_stream_name_or_error(name)
|
self.valid_stream_name_or_error(name)
|
||||||
account = self.get_account_or_default(account_id)
|
account = self.get_account_or_default(account_id)
|
||||||
channel = await self.get_channel_or_none(channel_account_id, channel_id, for_signing=True)
|
channel = await self.get_channel_or_none(channel_account_id, channel_id, channel_name, for_signing=True)
|
||||||
amount = self.get_dewies_or_error('bid', bid, positive_value=True)
|
amount = self.get_dewies_or_error('bid', bid, positive_value=True)
|
||||||
claim_address = await self.get_receiving_address(claim_address, account)
|
claim_address = await self.get_receiving_address(claim_address, account)
|
||||||
kwargs['fee_address'] = self.get_fee_address(kwargs, claim_address)
|
kwargs['fee_address'] = self.get_fee_address(kwargs, claim_address)
|
||||||
|
@ -2141,7 +2148,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
conditions=[WALLET_IS_UNLOCKED])
|
conditions=[WALLET_IS_UNLOCKED])
|
||||||
async def jsonrpc_stream_update(
|
async def jsonrpc_stream_update(
|
||||||
self, claim_id, bid=None, file_path=None,
|
self, claim_id, bid=None, file_path=None,
|
||||||
channel_id=None, channel_account_id=None, clear_channel=False,
|
channel_id=None, channel_name=None, channel_account_id=None, clear_channel=False,
|
||||||
account_id=None, claim_address=None,
|
account_id=None, claim_address=None,
|
||||||
preview=False, **kwargs):
|
preview=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -2149,14 +2156,15 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
stream_update (<claim_id> | --claim_id=<claim_id>)
|
stream_update (<claim_id> | --claim_id=<claim_id>)
|
||||||
[--bid=<bid>] [--file_path=<file_path>] [--tags=<tags>...] [--clear-tags]
|
[--bid=<bid>] [--file_path=<file_path>] [--tags=<tags>...] [--clear_tags]
|
||||||
[--fee_currency=<fee_currency>] [--fee_amount=<fee_amount>] [--fee_address=<fee_address>]
|
[--fee_currency=<fee_currency>] [--fee_amount=<fee_amount>] [--fee_address=<fee_address>]
|
||||||
[--title=<title>] [--description=<description>] [--author=<author>] [--language=<language>]
|
[--title=<title>] [--description=<description>] [--author=<author>] [--language=<language>]
|
||||||
[--license=<license>] [--license_url=<license_url>] [--thumbnail_url=<thumbnail_url>]
|
[--license=<license>] [--license_url=<license_url>] [--thumbnail_url=<thumbnail_url>]
|
||||||
[--release_time=<release_time>] [--stream_type=<stream_type>]
|
[--release_time=<release_time>] [--stream_type=<stream_type>]
|
||||||
[--video_width=<video_width>] [--video_height=<video_height>] [--video_duration=<video_duration>]
|
[--video_width=<video_width>] [--video_height=<video_height>] [--video_duration=<video_duration>]
|
||||||
[--image_width=<image_width>] [--image_height=<image_height>] [--audio_duration=<audio_duration>]
|
[--image_width=<image_width>] [--image_height=<image_height>] [--audio_duration=<audio_duration>]
|
||||||
[--channel_id=<channel_id>] [--channel_account_id=<channel_account_id>...] [--clear-channel]
|
[--channel_id=<channel_id>] [--channel_name=<channel_name>] [--clear_channel]
|
||||||
|
[--channel_account_id=<channel_account_id>...]
|
||||||
[--account_id=<account_id>] [--claim_address=<claim_address>] [--preview]
|
[--account_id=<account_id>] [--claim_address=<claim_address>] [--preview]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
@ -2164,7 +2172,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
--bid=<bid> : (decimal) amount to back the claim
|
--bid=<bid> : (decimal) amount to back the claim
|
||||||
--file_path=<file_path> : (str) path to file to be associated with name.
|
--file_path=<file_path> : (str) path to file to be associated with name.
|
||||||
--tags=<tags> : (list) content tags
|
--tags=<tags> : (list) content tags
|
||||||
--clear-tags : (bool) clear existing tags (prior to adding new ones)
|
--clear_tags : (bool) clear existing tags (prior to adding new ones)
|
||||||
--fee_currency=<fee_currency> : (string) specify fee currency
|
--fee_currency=<fee_currency> : (string) specify fee currency
|
||||||
--fee_amount=<fee_amount> : (decimal) content download fee
|
--fee_amount=<fee_amount> : (decimal) content download fee
|
||||||
--fee_address=<fee_address> : (str) address where to send fee payments, will use
|
--fee_address=<fee_address> : (str) address where to send fee payments, will use
|
||||||
|
@ -2191,7 +2199,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
--audio_duration=<duration> : (int) audio duration in seconds, an attempt will be made to
|
--audio_duration=<duration> : (int) audio duration in seconds, an attempt will be made to
|
||||||
calculate this automatically if not provided
|
calculate this automatically if not provided
|
||||||
--channel_id=<channel_id> : (str) claim id of the publisher channel
|
--channel_id=<channel_id> : (str) claim id of the publisher channel
|
||||||
--clear-channel : (bool) remove channel signature
|
--clear_channel : (bool) remove channel signature
|
||||||
--channel_account_id=<channel_id>: (str) one or more account ids for accounts to look in
|
--channel_account_id=<channel_id>: (str) one or more account ids for accounts to look in
|
||||||
for channel certificates, defaults to all accounts.
|
for channel certificates, defaults to all accounts.
|
||||||
--account_id=<account_id> : (str) account to use for funding the transaction
|
--account_id=<account_id> : (str) account to use for funding the transaction
|
||||||
|
@ -2223,8 +2231,8 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
claim_address = old_txo.get_address(account.ledger)
|
claim_address = old_txo.get_address(account.ledger)
|
||||||
|
|
||||||
channel = None
|
channel = None
|
||||||
if channel_id:
|
if channel_id or channel_name:
|
||||||
channel = await self.get_channel_or_error(channel_account_id, channel_id, for_signing=True)
|
channel = await self.get_channel_or_error(channel_account_id, channel_id, channel_name, for_signing=True)
|
||||||
elif old_txo.claim.is_signed and not clear_channel:
|
elif old_txo.claim.is_signed and not clear_channel:
|
||||||
channel = old_txo.channel
|
channel = old_txo.channel
|
||||||
|
|
||||||
|
@ -2974,22 +2982,28 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
self.valid_address_or_error(address)
|
self.valid_address_or_error(address)
|
||||||
return address
|
return address
|
||||||
|
|
||||||
async def get_channel_or_none(self, account_ids: List[str], channel_id: str = None,
|
async def get_channel_or_none(self, account_ids: List[str], channel_id: str = None, channel_name: str = None,
|
||||||
for_signing: bool = False) -> Output:
|
for_signing: bool = False) -> Output:
|
||||||
if channel_id is not None:
|
if channel_id is not None:
|
||||||
return await self.get_channel_or_error(account_ids, channel_id, for_signing)
|
return await self.get_channel_or_error(account_ids, channel_id, channel_name, for_signing)
|
||||||
|
|
||||||
async def get_channel_or_error(self, account_ids: List[str], channel_id: str = None,
|
async def get_channel_or_error(self, account_ids: List[str], channel_id: str = None, channel_name: str = None,
|
||||||
for_signing: bool = False) -> Output:
|
for_signing: bool = False) -> Output:
|
||||||
if channel_id is None:
|
if channel_id:
|
||||||
raise ValueError("Couldn't find channel because a channel_id was not provided.")
|
key, value = 'id', channel_id
|
||||||
|
elif channel_name:
|
||||||
|
key, value = 'name', channel_name
|
||||||
|
else:
|
||||||
|
raise ValueError("Couldn't find channel because a channel_id or channel_name was not provided.")
|
||||||
for account in self.get_accounts_or_all(account_ids):
|
for account in self.get_accounts_or_all(account_ids):
|
||||||
channels = await account.get_channels(claim_id=channel_id, limit=1)
|
channels = await account.get_channels(**{f'claim_{key}': value}, limit=1)
|
||||||
if channels:
|
if len(channels) == 1:
|
||||||
if for_signing and channels[0].private_key is None:
|
if for_signing and channels[0].private_key is None:
|
||||||
raise Exception(f"Couldn't find private key for channel '{channel_id}'. ")
|
raise Exception(f"Couldn't find private key for {key} '{value}'. ")
|
||||||
return channels[0]
|
return channels[0]
|
||||||
raise ValueError(f"Couldn't find channel with channel_id '{channel_id}'.")
|
elif len(channels) > 1:
|
||||||
|
raise ValueError(f"Multiple channels found with {key} '{value}', pass a channel_id to narrow it down.")
|
||||||
|
raise ValueError(f"Couldn't find channel with {key} '{value}'.")
|
||||||
|
|
||||||
def get_account_or_default(self, account_id: str, argument_name: str = "account", lbc_only=True) -> LBCAccount:
|
def get_account_or_default(self, account_id: str, argument_name: str = "account", lbc_only=True) -> LBCAccount:
|
||||||
if account_id is None:
|
if account_id is None:
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import tempfile
|
||||||
|
import logging
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
@ -246,8 +248,10 @@ class StreamCommands(CommandTestCase):
|
||||||
|
|
||||||
# defaults to using all accounts to lookup channel
|
# defaults to using all accounts to lookup channel
|
||||||
await self.stream_create('hovercraft1', channel_id=baz_id)
|
await self.stream_create('hovercraft1', channel_id=baz_id)
|
||||||
|
self.assertEqual((await self.claim_search('hovercraft1'))[0]['channel_name'], '@baz')
|
||||||
# uses only the specific accounts which contains the channel
|
# uses only the specific accounts which contains the channel
|
||||||
await self.stream_create('hovercraft2', channel_id=baz_id, channel_account_id=[account2_id])
|
await self.stream_create('hovercraft2', channel_id=baz_id, channel_account_id=[account2_id])
|
||||||
|
self.assertEqual((await self.claim_search('hovercraft2'))[0]['channel_name'], '@baz')
|
||||||
# fails when specifying account which does not contain channel
|
# fails when specifying account which does not contain channel
|
||||||
with self.assertRaisesRegex(ValueError, "Couldn't find channel with channel_id"):
|
with self.assertRaisesRegex(ValueError, "Couldn't find channel with channel_id"):
|
||||||
await self.stream_create(
|
await self.stream_create(
|
||||||
|
@ -386,6 +390,45 @@ class StreamCommands(CommandTestCase):
|
||||||
await self.claim_abandon(tx['outputs'][0]['claim_id'])
|
await self.claim_abandon(tx['outputs'][0]['claim_id'])
|
||||||
await self.assertBalance(self.account, '9.97968399')
|
await self.assertBalance(self.account, '9.97968399')
|
||||||
|
|
||||||
|
async def test_publish(self):
|
||||||
|
|
||||||
|
# errors on missing arguments to create a stream
|
||||||
|
with self.assertRaisesRegex(Exception, "'bid' is a required argument for new publishes."):
|
||||||
|
await self.daemon.jsonrpc_publish('foo')
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(Exception, "'file_path' is a required argument for new publishes."):
|
||||||
|
await self.daemon.jsonrpc_publish('foo', bid='1.0')
|
||||||
|
|
||||||
|
# successfully create stream
|
||||||
|
with tempfile.NamedTemporaryFile() as file:
|
||||||
|
file.write(b'hi')
|
||||||
|
file.flush()
|
||||||
|
tx1 = await self.publish('foo', bid='1.0', file_path=file.name)
|
||||||
|
|
||||||
|
# doesn't error on missing arguments when doing an update stream
|
||||||
|
tx2 = await self.publish('foo', tags='updated')
|
||||||
|
self.assertEqual(
|
||||||
|
tx1['outputs'][0]['claim_id'],
|
||||||
|
tx2['outputs'][0]['claim_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
# update conflict with two claims of the same name
|
||||||
|
tx3 = await self.stream_create('foo', allow_duplicate_name=True)
|
||||||
|
with self.assertRaisesRegex(Exception, "There are 2 claims for 'foo'"):
|
||||||
|
await self.daemon.jsonrpc_publish('foo')
|
||||||
|
|
||||||
|
# abandon duplicate channel
|
||||||
|
await self.claim_abandon(tx3['outputs'][0]['claim_id'])
|
||||||
|
|
||||||
|
# publish to a channel
|
||||||
|
await self.channel_create('@abc')
|
||||||
|
tx3 = await self.publish('foo', channel_name='@abc')
|
||||||
|
r = await self.resolve('lbry://@abc/foo')
|
||||||
|
self.assertEqual(
|
||||||
|
r['lbry://@abc/foo']['claim']['claim_id'],
|
||||||
|
tx3['outputs'][0]['claim_id']
|
||||||
|
)
|
||||||
|
|
||||||
async def test_claim_search(self):
|
async def test_claim_search(self):
|
||||||
# search for channel claim
|
# search for channel claim
|
||||||
channel = await self.channel_create('@abc', '1.0')
|
channel = await self.channel_create('@abc', '1.0')
|
||||||
|
|
|
@ -186,6 +186,15 @@ class CommandTestCase(IntegrationTestCase):
|
||||||
await self.on_transaction_dict(claim)
|
await self.on_transaction_dict(claim)
|
||||||
return claim
|
return claim
|
||||||
|
|
||||||
|
async def publish(self, name, *args, confirm=True, **kwargs):
|
||||||
|
claim = await self.out(self.daemon.jsonrpc_publish(name, *args, **kwargs))
|
||||||
|
self.assertEqual(claim['outputs'][0]['name'], name)
|
||||||
|
if confirm:
|
||||||
|
await self.on_transaction_dict(claim)
|
||||||
|
await self.generate(1)
|
||||||
|
await self.on_transaction_dict(claim)
|
||||||
|
return claim
|
||||||
|
|
||||||
async def channel_create(self, name='@arena', bid='1.0', confirm=True, **kwargs):
|
async def channel_create(self, name='@arena', bid='1.0', confirm=True, **kwargs):
|
||||||
channel = await self.out(self.daemon.jsonrpc_channel_create(name, bid, **kwargs))
|
channel = await self.out(self.daemon.jsonrpc_channel_create(name, bid, **kwargs))
|
||||||
self.assertEqual(channel['outputs'][0]['name'], name)
|
self.assertEqual(channel['outputs'][0]['name'], name)
|
||||||
|
|
Loading…
Add table
Reference in a new issue