added --replace option to stream_update and channel_update, publish defaults to --replace

This commit is contained in:
Lex Berezhny 2019-04-26 20:44:38 -04:00
parent 3618de1227
commit da637b9c0e
3 changed files with 89 additions and 20 deletions

View file

@ -1852,7 +1852,7 @@ class Daemon(metaclass=JSONRPCServerType):
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
async def jsonrpc_channel_update( async def jsonrpc_channel_update(
self, claim_id, bid=None, account_id=None, claim_address=None, self, claim_id, bid=None, account_id=None, claim_address=None,
new_signing_key=False, preview=False, **kwargs): new_signing_key=False, preview=False, replace=False, **kwargs):
""" """
Update an existing channel claim. Update an existing channel claim.
@ -1865,7 +1865,8 @@ class Daemon(metaclass=JSONRPCServerType):
[--locations=<locations>...] [--clear_locations] [--locations=<locations>...] [--clear_locations]
[--email=<email>] [--email=<email>]
[--website_url=<website_url>] [--thumbnail_url=<thumbnail_url>] [--cover_url=<cover_url>] [--website_url=<website_url>] [--thumbnail_url=<thumbnail_url>] [--cover_url=<cover_url>]
[--account_id=<account_id>] [--claim_address=<claim_address>] [--new_signing_key] [--preview] [--account_id=<account_id>] [--claim_address=<claim_address>] [--new_signing_key]
[--preview] [--replace]
Options: Options:
--claim_id=<claim_id> : (str) claim_id of the channel to update --claim_id=<claim_id> : (str) claim_id of the channel to update
@ -1923,6 +1924,10 @@ class Daemon(metaclass=JSONRPCServerType):
--account_id=<account_id> : (str) id of the account to store channel --account_id=<account_id> : (str) id of the account to store channel
--claim_address=<claim_address>: (str) address where the channel is sent --claim_address=<claim_address>: (str) address where the channel is sent
--new_signing_key : (bool) generate a new signing key, will invalidate all previous publishes --new_signing_key : (bool) generate a new signing key, will invalidate all previous publishes
--replace : (bool) instead of modifying specific values on
the channel, this will clear all existing values
and only save passed in values, useful for form
submissions where all values are always set
--preview : (bool) do not broadcast the transaction --preview : (bool) do not broadcast the transaction
Returns: {Transaction} Returns: {Transaction}
@ -1950,7 +1955,11 @@ class Daemon(metaclass=JSONRPCServerType):
else: else:
claim_address = old_txo.get_address(account.ledger) claim_address = old_txo.get_address(account.ledger)
claim = Claim.from_bytes(old_txo.claim.to_bytes()) if replace:
claim = Claim()
claim.channel.public_key_bytes = old_txo.claim.channel.public_key_bytes
else:
claim = Claim.from_bytes(old_txo.claim.to_bytes())
claim.channel.update(**kwargs) claim.channel.update(**kwargs)
tx = await Transaction.claim_update( tx = await Transaction.claim_update(
old_txo, claim, amount, claim_address, [account], account old_txo, claim, amount, claim_address, [account], account
@ -2092,13 +2101,11 @@ class Daemon(metaclass=JSONRPCServerType):
conditions=[WALLET_IS_UNLOCKED]) conditions=[WALLET_IS_UNLOCKED])
async def jsonrpc_publish(self, name, **kwargs): async def jsonrpc_publish(self, name, **kwargs):
""" """
Create or update a stream claim at a given name (use 'stream create/update' for more control). Create or replace a stream claim at a given name (use 'stream create/update' for more control).
Usage: Usage:
publish (<name> | --name=<name>) [--bid=<bid>] [--file_path=<file_path>] publish (<name> | --name=<name>) [--bid=<bid>] [--file_path=<file_path>]
[--tags=<tags>...] [--clear_tags] [--tags=<tags>...] [--languages=<languages>...] [--locations=<locations>...]
[--languages=<languages>...] [--clear_languages]
[--locations=<locations>...] [--clear_locations]
[--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>]
@ -2122,9 +2129,7 @@ class Daemon(metaclass=JSONRPCServerType):
who is not the publisher and is not represented by the channel. For who is not the publisher and is not represented by the channel. For
example, a pdf file of 'The Odyssey' has an author of 'Homer' but may example, a pdf file of 'The Odyssey' has an author of 'Homer' but may
by published to a channel such as '@classics', or to no channel at all by published to a channel such as '@classics', or to no channel at all
--clear_tags : (bool) clear existing tags (prior to adding new ones)
--tags=<tags> : (list) add content tags --tags=<tags> : (list) add content tags
--clear_languages : (bool) clear existing languages (prior to adding new ones)
--languages=<languages> : (list) languages used by the channel, --languages=<languages> : (list) languages used by the channel,
using RFC 5646 format, eg: using RFC 5646 format, eg:
for English `--languages=en` for English `--languages=en`
@ -2132,7 +2137,6 @@ class Daemon(metaclass=JSONRPCServerType):
for Spanish (Mexican) `--languages=es-MX` for Spanish (Mexican) `--languages=es-MX`
for Chinese (Simplified) `--languages=zh-Hans` for Chinese (Simplified) `--languages=zh-Hans`
for Chinese (Traditional) `--languages=zh-Hant` for Chinese (Traditional) `--languages=zh-Hant`
--clear_locations : (bool) clear existing locations (prior to adding new ones)
--locations=<locations> : (list) locations relevant to the stream, consisting of 2 letter --locations=<locations> : (list) locations relevant to the stream, consisting of 2 letter
`country` code and a `state`, `city` and a postal `country` code and a `state`, `city` and a postal
`code` along with a `latitude` and `longitude`. `code` along with a `latitude` and `longitude`.
@ -2193,7 +2197,7 @@ class Daemon(metaclass=JSONRPCServerType):
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."
return await self.jsonrpc_stream_update(claims[0].claim_id, **kwargs) return await self.jsonrpc_stream_update(claims[0].claim_id, replace=True, **kwargs)
raise Exception( raise Exception(
f"There are {len(claims)} claims for '{name}', please use 'stream update' command " f"There are {len(claims)} claims for '{name}', please use 'stream update' command "
f"to update a specific stream claim." f"to update a specific stream claim."
@ -2339,7 +2343,7 @@ class Daemon(metaclass=JSONRPCServerType):
self, claim_id, bid=None, file_path=None, self, claim_id, bid=None, file_path=None,
channel_id=None, channel_name=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, replace=False, **kwargs):
""" """
Update an existing stream claim and if a new file is provided announce it to lbrynet. Update an existing stream claim and if a new file is provided announce it to lbrynet.
@ -2356,7 +2360,8 @@ class Daemon(metaclass=JSONRPCServerType):
[--release_time=<release_time>] [--width=<width>] [--height=<height>] [--duration=<duration>] [--release_time=<release_time>] [--width=<width>] [--height=<height>] [--duration=<duration>]
[--channel_id=<channel_id>] [--channel_name=<channel_name>] [--clear_channel] [--channel_id=<channel_id>] [--channel_name=<channel_name>] [--clear_channel]
[--channel_account_id=<channel_account_id>...] [--channel_account_id=<channel_account_id>...]
[--account_id=<account_id>] [--claim_address=<claim_address>] [--preview] [--account_id=<account_id>] [--claim_address=<claim_address>]
[--preview] [--replace]
Options: Options:
--claim_id=<claim_id> : (str) id of the stream claim to update --claim_id=<claim_id> : (str) id of the stream claim to update
@ -2433,6 +2438,10 @@ class Daemon(metaclass=JSONRPCServerType):
--account_id=<account_id> : (str) account to use for funding the transaction --account_id=<account_id> : (str) account to use for funding the transaction
--claim_address=<claim_address>: (str) address where the claim is sent to, if not specified --claim_address=<claim_address>: (str) address where the claim is sent to, if not specified
it will be determined automatically from the account it will be determined automatically from the account
--replace : (bool) instead of modifying specific values on
the stream, this will clear all existing values
and only save passed in values, useful for form
submissions where all values are always set
--preview : (bool) do not broadcast the transaction --preview : (bool) do not broadcast the transaction
Returns: {Transaction} Returns: {Transaction}
@ -2442,7 +2451,7 @@ class Daemon(metaclass=JSONRPCServerType):
existing_claims = await account.get_claims(claim_id=claim_id) existing_claims = await account.get_claims(claim_id=claim_id)
if len(existing_claims) != 1: if len(existing_claims) != 1:
raise Exception( raise Exception(
f"Can't find the claim '{claim_id}' in account '{account_id}'." f"Can't find the claim '{claim_id}' in account '{account.id}'."
) )
old_txo = existing_claims[0] old_txo = existing_claims[0]
if not old_txo.claim.is_stream: if not old_txo.claim.is_stream:
@ -2469,8 +2478,20 @@ class Daemon(metaclass=JSONRPCServerType):
if 'fee_address' in kwargs: if 'fee_address' in kwargs:
self.valid_address_or_error(kwargs['fee_address']) self.valid_address_or_error(kwargs['fee_address'])
claim = Claim.from_bytes(old_txo.claim.to_bytes()) if replace:
claim.stream.update(file_path=file_path, **kwargs) claim = Claim()
claim.stream.message.source.CopyFrom(
old_txo.claim.stream.message.source
)
stream_type = old_txo.claim.stream.stream_type
if stream_type:
old_stream_type = getattr(old_txo.claim.stream.message, stream_type)
new_stream_type = getattr(claim.stream.message, stream_type)
new_stream_type.CopyFrom(old_stream_type)
claim.stream.update(file_path=file_path, **kwargs)
else:
claim = Claim.from_bytes(old_txo.claim.to_bytes())
claim.stream.update(file_path=file_path, **kwargs)
tx = await Transaction.claim_update( tx = await Transaction.claim_update(
old_txo, claim, amount, claim_address, [account], account, channel old_txo, claim, amount, claim_address, [account], account, channel
) )

View file

@ -233,10 +233,11 @@ class Stream(BaseClaim):
if stream_type in ('image', 'video', 'audio'): if stream_type in ('image', 'video', 'audio'):
media = getattr(self, stream_type) media = getattr(self, stream_type)
media_args = {'file_metadata': None} media_args = {'file_metadata': None}
try: if file_path is not None:
media_args['file_metadata'] = binary_file_metadata(binary_file_parser(file_path)) try:
except: media_args['file_metadata'] = binary_file_metadata(binary_file_parser(file_path))
log.exception('Could not read file metadata.') except:
log.exception('Could not read file metadata.')
if isinstance(media, Playable): if isinstance(media, Playable):
media_args['duration'] = duration media_args['duration'] = duration
if isinstance(media, Dimmensional): if isinstance(media, Dimmensional):
@ -290,6 +291,10 @@ class Stream(BaseClaim):
def source(self) -> Source: def source(self) -> Source:
return Source(self.message.source) return Source(self.message.source)
@property
def stream_type(self) -> str:
return self.message.WhichOneof('type')
@property @property
def image(self) -> Image: def image(self) -> Image:
return Image(self.message.image) return Image(self.message.image)

View file

@ -125,6 +125,13 @@ class ChannelCommands(CommandTestCase):
channel = tx['outputs'][0]['value'] channel = tx['outputs'][0]['value']
self.assertNotEqual(channel['public_key'], fixed_values['public_key']) self.assertNotEqual(channel['public_key'], fixed_values['public_key'])
# replace mode (clears everything except public_key)
tx = await self.out(self.channel_update(claim_id, replace=True, title='foo', email='new@email.com'))
self.assertEqual(
tx['outputs'][0]['value'],
{'public_key': channel['public_key'], 'title': 'foo', 'email': 'new@email.com'}
)
# send channel to someone else # send channel to someone else
new_account = await self.out(self.daemon.jsonrpc_account_create('second account')) new_account = await self.out(self.daemon.jsonrpc_account_create('second account'))
account2_id, account2 = new_account['id'], self.daemon.get_account_or_error(new_account['id']) account2_id, account2 = new_account['id'], self.daemon.get_account_or_error(new_account['id'])
@ -470,6 +477,42 @@ class StreamCommands(CommandTestCase):
} }
) )
async def test_replace_mode_preserves_source_and_type(self):
expected = {
'tags': ['blah'],
'languages': ['uk'],
'locations': [{'country': 'UA', 'city': 'Kyiv'}],
'source': {
'size': '2299653',
'name': 'ForBiggerEscapes.mp4',
'media_type': 'video/mp4',
'hash': 'f846d9c7f5ed28f0ed47e9d9b4198a03075e6df967ac54078af85ea1bf0ddd87',
},
'stream_type': 'video',
'video': {
'width': 1280,
'height': 720,
'duration': 15
}
}
tx = await self.out(self.daemon.jsonrpc_stream_create(
'chrome', '1.0', file_path=self.video_file_name,
tags='blah', languages='uk', locations='UA::Kyiv'
))
await self.on_transaction_dict(tx)
txo = tx['outputs'][0]
expected['source']['sd_hash'] = txo['value']['source']['sd_hash']
self.assertEqual(txo['value'], expected)
tx = await self.out(self.daemon.jsonrpc_stream_update(
txo['claim_id'], title='new title', replace=True
))
txo = tx['outputs'][0]
expected['title'] = 'new title'
del expected['tags']
del expected['languages']
del expected['locations']
self.assertEqual(txo['value'], expected)
async def test_create_update_and_abandon_stream(self): async def test_create_update_and_abandon_stream(self):
await self.assertBalance(self.account, '10.0') await self.assertBalance(self.account, '10.0')