working integration tests
This commit is contained in:
parent
1ca82b9d52
commit
5eac4247e1
6 changed files with 122 additions and 103 deletions
|
@ -53,17 +53,16 @@ class ComponentManager:
|
||||||
for component_class in self.component_classes.values():
|
for component_class in self.component_classes.values():
|
||||||
self.components.add(component_class(self))
|
self.components.add(component_class(self))
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def evaluate_condition(self, condition_name):
|
def evaluate_condition(self, condition_name):
|
||||||
if condition_name not in RegisteredConditions.conditions:
|
if condition_name not in RegisteredConditions.conditions:
|
||||||
raise NameError(condition_name)
|
raise NameError(condition_name)
|
||||||
condition = RegisteredConditions.conditions[condition_name]
|
condition = RegisteredConditions.conditions[condition_name]
|
||||||
try:
|
try:
|
||||||
component = self.get_component(condition.component)
|
component = self.get_component(condition.component)
|
||||||
result = yield defer.maybeDeferred(condition.evaluate, component)
|
result = condition.evaluate(component)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
result = False
|
result = False
|
||||||
defer.returnValue((result, "" if result else condition.message))
|
return result, "" if result else condition.message
|
||||||
|
|
||||||
def sort_components(self, reverse=False):
|
def sort_components(self, reverse=False):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -83,8 +83,7 @@ DIRECTION_DESCENDING = 'desc'
|
||||||
DIRECTIONS = DIRECTION_ASCENDING, DIRECTION_DESCENDING
|
DIRECTIONS = DIRECTION_ASCENDING, DIRECTION_DESCENDING
|
||||||
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
async def maybe_paginate(get_records: Callable, get_record_count: Callable,
|
||||||
def maybe_paginate(get_records: Callable, get_record_count: Callable,
|
|
||||||
page: Optional[int], page_size: Optional[int], **constraints):
|
page: Optional[int], page_size: Optional[int], **constraints):
|
||||||
if None not in (page, page_size):
|
if None not in (page, page_size):
|
||||||
constraints.update({
|
constraints.update({
|
||||||
|
@ -92,11 +91,11 @@ def maybe_paginate(get_records: Callable, get_record_count: Callable,
|
||||||
"limit": page_size
|
"limit": page_size
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
"items": (yield get_records(**constraints)),
|
"items": await get_records(**constraints),
|
||||||
"total_pages": int(((yield get_record_count(**constraints)) + (page_size-1)) / page_size),
|
"total_pages": int(((await get_record_count(**constraints)) + (page_size-1)) / page_size),
|
||||||
"page": page, "page_size": page_size
|
"page": page, "page_size": page_size
|
||||||
}
|
}
|
||||||
return (yield get_records(**constraints))
|
return await get_records(**constraints)
|
||||||
|
|
||||||
|
|
||||||
class IterableContainer:
|
class IterableContainer:
|
||||||
|
@ -200,9 +199,7 @@ class WalletIsUnlocked(RequiredCondition):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def evaluate(component):
|
def evaluate(component):
|
||||||
d = component.check_locked()
|
return not component.check_locked()
|
||||||
d.addCallback(lambda r: not r)
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
class Daemon(AuthJSONRPCServer):
|
class Daemon(AuthJSONRPCServer):
|
||||||
|
@ -403,8 +400,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
del self.streams[sd_hash]
|
del self.streams[sd_hash]
|
||||||
defer.returnValue(result)
|
defer.returnValue(result)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
async def _publish_stream(self, name, bid, claim_dict, file_path=None, certificate=None,
|
||||||
def _publish_stream(self, name, bid, claim_dict, file_path=None, certificate=None,
|
|
||||||
claim_address=None, change_address=None):
|
claim_address=None, change_address=None):
|
||||||
publisher = Publisher(
|
publisher = Publisher(
|
||||||
self.blob_manager, self.payment_rate_manager, self.storage,
|
self.blob_manager, self.payment_rate_manager, self.storage,
|
||||||
|
@ -412,11 +408,11 @@ class Daemon(AuthJSONRPCServer):
|
||||||
)
|
)
|
||||||
parse_lbry_uri(name)
|
parse_lbry_uri(name)
|
||||||
if not file_path:
|
if not file_path:
|
||||||
stream_hash = yield self.storage.get_stream_hash_for_sd_hash(
|
stream_hash = await d2f(self.storage.get_stream_hash_for_sd_hash(
|
||||||
claim_dict['stream']['source']['source'])
|
claim_dict['stream']['source']['source']))
|
||||||
tx = yield publisher.publish_stream(name, bid, claim_dict, stream_hash, claim_address)
|
tx = await publisher.publish_stream(name, bid, claim_dict, stream_hash, claim_address)
|
||||||
else:
|
else:
|
||||||
tx = yield publisher.create_and_publish_stream(name, bid, claim_dict, file_path, claim_address)
|
tx = await publisher.create_and_publish_stream(name, bid, claim_dict, file_path, claim_address)
|
||||||
if conf.settings['reflect_uploads']:
|
if conf.settings['reflect_uploads']:
|
||||||
d = reupload.reflect_file(publisher.lbry_file)
|
d = reupload.reflect_file(publisher.lbry_file)
|
||||||
d.addCallbacks(lambda _: log.info("Reflected new publication to lbry://%s", name),
|
d.addCallbacks(lambda _: log.info("Reflected new publication to lbry://%s", name),
|
||||||
|
@ -425,13 +421,13 @@ class Daemon(AuthJSONRPCServer):
|
||||||
nout = 0
|
nout = 0
|
||||||
txo = tx.outputs[nout]
|
txo = tx.outputs[nout]
|
||||||
log.info("Success! Published to lbry://%s txid: %s nout: %d", name, tx.id, nout)
|
log.info("Success! Published to lbry://%s txid: %s nout: %d", name, tx.id, nout)
|
||||||
defer.returnValue({
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"tx": tx,
|
"tx": tx,
|
||||||
"claim_id": txo.claim_id,
|
"claim_id": txo.claim_id,
|
||||||
"claim_address": self.ledger.hash160_to_address(txo.script.values['pubkey_hash']),
|
"claim_address": self.ledger.hash160_to_address(txo.script.values['pubkey_hash']),
|
||||||
"output": tx.outputs[nout]
|
"output": tx.outputs[nout]
|
||||||
})
|
}
|
||||||
|
|
||||||
def _get_or_download_sd_blob(self, blob, sd_hash):
|
def _get_or_download_sd_blob(self, blob, sd_hash):
|
||||||
if blob:
|
if blob:
|
||||||
|
@ -1043,8 +1039,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_wallet_send(self, amount, address=None, claim_id=None, account_id=None):
|
||||||
def jsonrpc_wallet_send(self, amount, address=None, claim_id=None, account_id=None):
|
|
||||||
"""
|
"""
|
||||||
Send credits. If given an address, send credits to it. If given a claim id, send a tip
|
Send credits. If given an address, send credits to it. If given a claim id, send a tip
|
||||||
to the owner of a claim specified by uri. A tip is a claim support where the recipient
|
to the owner of a claim specified by uri. A tip is a claim support where the recipient
|
||||||
|
@ -1102,11 +1097,11 @@ class Daemon(AuthJSONRPCServer):
|
||||||
if reserved_points is None:
|
if reserved_points is None:
|
||||||
raise InsufficientFundsError()
|
raise InsufficientFundsError()
|
||||||
account = self.get_account_or_default(account_id)
|
account = self.get_account_or_default(account_id)
|
||||||
result = yield self.wallet_manager.send_points_to_address(reserved_points, amount, account)
|
result = await self.wallet_manager.send_points_to_address(reserved_points, amount, account)
|
||||||
self.analytics_manager.send_credits_sent()
|
self.analytics_manager.send_credits_sent()
|
||||||
else:
|
else:
|
||||||
log.info("This command is deprecated for sending tips, please use the newer claim_tip command")
|
log.info("This command is deprecated for sending tips, please use the newer claim_tip command")
|
||||||
result = yield self.jsonrpc_claim_tip(claim_id=claim_id, amount=amount, account_id=account_id)
|
result = await self.jsonrpc_claim_tip(claim_id=claim_id, amount=amount, account_id=account_id)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||||
|
@ -1181,8 +1176,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
confirmations=confirmations, show_seed=show_seed)
|
confirmations=confirmations, show_seed=show_seed)
|
||||||
|
|
||||||
@requires("wallet")
|
@requires("wallet")
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_account_balance(self, account_id=None, confirmations=0):
|
||||||
def jsonrpc_account_balance(self, account_id=None, confirmations=0):
|
|
||||||
"""
|
"""
|
||||||
Return the balance of an account
|
Return the balance of an account
|
||||||
|
|
||||||
|
@ -1199,12 +1193,11 @@ class Daemon(AuthJSONRPCServer):
|
||||||
(decimal) amount of lbry credits in wallet
|
(decimal) amount of lbry credits in wallet
|
||||||
"""
|
"""
|
||||||
account = self.get_account_or_default(account_id)
|
account = self.get_account_or_default(account_id)
|
||||||
dewies = yield account.get_balance(confirmations=confirmations)
|
dewies = await account.get_balance(confirmations=confirmations)
|
||||||
return dewies_to_lbc(dewies)
|
return dewies_to_lbc(dewies)
|
||||||
|
|
||||||
@requires("wallet")
|
@requires("wallet")
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_account_add(
|
||||||
def jsonrpc_account_add(
|
|
||||||
self, account_name, single_key=False, seed=None, private_key=None, public_key=None):
|
self, account_name, single_key=False, seed=None, private_key=None, public_key=None):
|
||||||
"""
|
"""
|
||||||
Add a previously created account from a seed, private key or public key (read-only).
|
Add a previously created account from a seed, private key or public key (read-only).
|
||||||
|
@ -1239,7 +1232,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.ledger.network.is_connected:
|
if self.ledger.network.is_connected:
|
||||||
yield self.ledger.update_account(account)
|
await self.ledger.update_account(account)
|
||||||
|
|
||||||
self.default_wallet.save()
|
self.default_wallet.save()
|
||||||
|
|
||||||
|
@ -1251,8 +1244,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@requires("wallet")
|
@requires("wallet")
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_account_create(self, account_name, single_key=False):
|
||||||
def jsonrpc_account_create(self, account_name, single_key=False):
|
|
||||||
"""
|
"""
|
||||||
Create a new account. Specify --single_key if you want to use
|
Create a new account. Specify --single_key if you want to use
|
||||||
the same address for all transactions (not recommended).
|
the same address for all transactions (not recommended).
|
||||||
|
@ -1275,7 +1267,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.ledger.network.is_connected:
|
if self.ledger.network.is_connected:
|
||||||
yield self.ledger.update_account(account)
|
await self.ledger.update_account(account)
|
||||||
|
|
||||||
self.default_wallet.save()
|
self.default_wallet.save()
|
||||||
|
|
||||||
|
@ -1710,8 +1702,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
defer.returnValue(response)
|
defer.returnValue(response)
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT)
|
@requires(WALLET_COMPONENT)
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_resolve(self, force=False, uri=None, uris=None):
|
||||||
def jsonrpc_resolve(self, force=False, uri=None, uris=[]):
|
|
||||||
"""
|
"""
|
||||||
Resolve given LBRY URIs
|
Resolve given LBRY URIs
|
||||||
|
|
||||||
|
@ -1779,7 +1770,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
uris = tuple(uris)
|
uris = tuple(uris or [])
|
||||||
if uri is not None:
|
if uri is not None:
|
||||||
uris += (uri,)
|
uris += (uri,)
|
||||||
|
|
||||||
|
@ -1793,12 +1784,10 @@ class Daemon(AuthJSONRPCServer):
|
||||||
except URIParseError:
|
except URIParseError:
|
||||||
results[u] = {"error": "%s is not a valid uri" % u}
|
results[u] = {"error": "%s is not a valid uri" % u}
|
||||||
|
|
||||||
resolved = yield self.wallet_manager.resolve(*valid_uris, check_cache=not force)
|
resolved = await self.wallet_manager.resolve(*valid_uris, check_cache=not force)
|
||||||
|
|
||||||
for resolved_uri in resolved:
|
for resolved_uri in resolved:
|
||||||
results[resolved_uri] = resolved[resolved_uri]
|
results[resolved_uri] = resolved[resolved_uri]
|
||||||
response = yield self._render_response(results)
|
return results
|
||||||
defer.returnValue(response)
|
|
||||||
|
|
||||||
@requires(STREAM_IDENTIFIER_COMPONENT, WALLET_COMPONENT, EXCHANGE_RATE_MANAGER_COMPONENT, BLOB_COMPONENT,
|
@requires(STREAM_IDENTIFIER_COMPONENT, WALLET_COMPONENT, EXCHANGE_RATE_MANAGER_COMPONENT, BLOB_COMPONENT,
|
||||||
DHT_COMPONENT, RATE_LIMITER_COMPONENT, PAYMENT_RATE_COMPONENT, DATABASE_COMPONENT,
|
DHT_COMPONENT, RATE_LIMITER_COMPONENT, PAYMENT_RATE_COMPONENT, DATABASE_COMPONENT,
|
||||||
|
@ -2010,8 +1999,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
return self.get_est_cost(uri, size)
|
return self.get_est_cost(uri, size)
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_channel_new(self, channel_name, amount):
|
||||||
def jsonrpc_channel_new(self, channel_name, amount):
|
|
||||||
"""
|
"""
|
||||||
Generate a publisher key and create a new '@' prefixed certificate claim
|
Generate a publisher key and create a new '@' prefixed certificate claim
|
||||||
|
|
||||||
|
@ -2046,7 +2034,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
|
|
||||||
if amount <= 0:
|
if amount <= 0:
|
||||||
raise Exception("Invalid amount")
|
raise Exception("Invalid amount")
|
||||||
tx = yield self.wallet_manager.claim_new_channel(channel_name, amount)
|
tx = await self.wallet_manager.claim_new_channel(channel_name, amount)
|
||||||
self.default_wallet.save()
|
self.default_wallet.save()
|
||||||
self.analytics_manager.send_new_channel()
|
self.analytics_manager.send_new_channel()
|
||||||
nout = 0
|
nout = 0
|
||||||
|
@ -2125,8 +2113,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT, FILE_MANAGER_COMPONENT, BLOB_COMPONENT, PAYMENT_RATE_COMPONENT, DATABASE_COMPONENT,
|
@requires(WALLET_COMPONENT, FILE_MANAGER_COMPONENT, BLOB_COMPONENT, PAYMENT_RATE_COMPONENT, DATABASE_COMPONENT,
|
||||||
conditions=[WALLET_IS_UNLOCKED])
|
conditions=[WALLET_IS_UNLOCKED])
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_publish(self, name, bid, metadata=None, file_path=None, fee=None, title=None,
|
||||||
def jsonrpc_publish(self, name, bid, metadata=None, file_path=None, fee=None, title=None,
|
|
||||||
description=None, author=None, language=None, license=None,
|
description=None, author=None, language=None, license=None,
|
||||||
license_url=None, thumbnail=None, preview=None, nsfw=None, sources=None,
|
license_url=None, thumbnail=None, preview=None, nsfw=None, sources=None,
|
||||||
channel_name=None, channel_id=None,
|
channel_name=None, channel_id=None,
|
||||||
|
@ -2221,7 +2208,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
# raises an error if the address is invalid
|
# raises an error if the address is invalid
|
||||||
decode_address(address)
|
decode_address(address)
|
||||||
|
|
||||||
available = yield self.default_account.get_balance()
|
available = await self.default_account.get_balance()
|
||||||
if amount >= available:
|
if amount >= available:
|
||||||
# TODO: add check for existing claim balance
|
# TODO: add check for existing claim balance
|
||||||
#balance = yield self.wallet.get_max_usable_balance_for_claim(name)
|
#balance = yield self.wallet.get_max_usable_balance_for_claim(name)
|
||||||
|
@ -2273,7 +2260,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
log.warning("Stripping empty fee from published metadata")
|
log.warning("Stripping empty fee from published metadata")
|
||||||
del metadata['fee']
|
del metadata['fee']
|
||||||
elif 'address' not in metadata['fee']:
|
elif 'address' not in metadata['fee']:
|
||||||
address = yield self.default_account.receiving.get_or_create_usable_address()
|
address = await self.default_account.receiving.get_or_create_usable_address()
|
||||||
metadata['fee']['address'] = address
|
metadata['fee']['address'] = address
|
||||||
if 'fee' in metadata and 'version' not in metadata['fee']:
|
if 'fee' in metadata and 'version' not in metadata['fee']:
|
||||||
metadata['fee']['version'] = '_0_0_1'
|
metadata['fee']['version'] = '_0_0_1'
|
||||||
|
@ -2316,7 +2303,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
|
|
||||||
certificate = None
|
certificate = None
|
||||||
if channel_id or channel_name:
|
if channel_id or channel_name:
|
||||||
certificate = yield self.get_channel_or_error(channel_id, channel_name)
|
certificate = await self.get_channel_or_error(channel_id, channel_name)
|
||||||
|
|
||||||
log.info("Publish: %s", {
|
log.info("Publish: %s", {
|
||||||
'name': name,
|
'name': name,
|
||||||
|
@ -2329,13 +2316,13 @@ class Daemon(AuthJSONRPCServer):
|
||||||
'channel_name': channel_name
|
'channel_name': channel_name
|
||||||
})
|
})
|
||||||
|
|
||||||
result = yield self._publish_stream(name, amount, claim_dict, file_path, certificate,
|
return await self._publish_stream(
|
||||||
claim_address, change_address)
|
name, amount, claim_dict, file_path, certificate,
|
||||||
return result
|
claim_address, change_address
|
||||||
|
)
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_claim_abandon(self, claim_id=None, txid=None, nout=None, account_id=None):
|
||||||
def jsonrpc_claim_abandon(self, claim_id=None, txid=None, nout=None, account_id=None):
|
|
||||||
"""
|
"""
|
||||||
Abandon a name and reclaim credits from the claim
|
Abandon a name and reclaim credits from the claim
|
||||||
|
|
||||||
|
@ -2366,16 +2353,12 @@ class Daemon(AuthJSONRPCServer):
|
||||||
if nout is None and txid is not None:
|
if nout is None and txid is not None:
|
||||||
raise Exception('Must specify nout')
|
raise Exception('Must specify nout')
|
||||||
|
|
||||||
tx = yield self.wallet_manager.abandon_claim(claim_id, txid, nout, account)
|
tx = await self.wallet_manager.abandon_claim(claim_id, txid, nout, account)
|
||||||
self.analytics_manager.send_claim_action('abandon')
|
self.analytics_manager.send_claim_action('abandon')
|
||||||
defer.returnValue({
|
return {"success": True, "tx": tx}
|
||||||
"success": True,
|
|
||||||
"tx": tx,
|
|
||||||
})
|
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_claim_new_support(self, name, claim_id, amount, account_id=None):
|
||||||
def jsonrpc_claim_new_support(self, name, claim_id, amount, account_id=None):
|
|
||||||
"""
|
"""
|
||||||
Support a name claim
|
Support a name claim
|
||||||
|
|
||||||
|
@ -2403,13 +2386,12 @@ class Daemon(AuthJSONRPCServer):
|
||||||
"""
|
"""
|
||||||
account = self.get_account_or_default(account_id)
|
account = self.get_account_or_default(account_id)
|
||||||
amount = self.get_dewies_or_error("amount", amount)
|
amount = self.get_dewies_or_error("amount", amount)
|
||||||
result = yield self.wallet_manager.support_claim(name, claim_id, amount, account)
|
result = await self.wallet_manager.support_claim(name, claim_id, amount, account)
|
||||||
self.analytics_manager.send_claim_action('new_support')
|
self.analytics_manager.send_claim_action('new_support')
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||||
@defer.inlineCallbacks
|
async def jsonrpc_claim_tip(self, claim_id, amount, account_id=None):
|
||||||
def jsonrpc_claim_tip(self, claim_id, amount, account_id=None):
|
|
||||||
"""
|
"""
|
||||||
Tip the owner of the claim
|
Tip the owner of the claim
|
||||||
|
|
||||||
|
@ -2437,7 +2419,7 @@ class Daemon(AuthJSONRPCServer):
|
||||||
account = self.get_account_or_default(account_id)
|
account = self.get_account_or_default(account_id)
|
||||||
amount = self.get_dewies_or_error("amount", amount)
|
amount = self.get_dewies_or_error("amount", amount)
|
||||||
validate_claim_id(claim_id)
|
validate_claim_id(claim_id)
|
||||||
result = yield self.wallet_manager.tip_claim(amount, claim_id, account)
|
result = await self.wallet_manager.tip_claim(amount, claim_id, account)
|
||||||
self.analytics_manager.send_claim_action('new_support')
|
self.analytics_manager.send_claim_action('new_support')
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -3294,16 +3276,15 @@ class Daemon(AuthJSONRPCServer):
|
||||||
response['head_blob_availability'].get('is_available')
|
response['head_blob_availability'].get('is_available')
|
||||||
defer.returnValue(response)
|
defer.returnValue(response)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
async def get_channel_or_error(self, channel_id: str = None, channel_name: str = None):
|
||||||
def get_channel_or_error(self, channel_id: str = None, channel_name: str = None):
|
|
||||||
if channel_id is not None:
|
if channel_id is not None:
|
||||||
certificates = yield self.wallet_manager.get_certificates(
|
certificates = await self.wallet_manager.get_certificates(
|
||||||
private_key_accounts=[self.default_account], claim_id=channel_id)
|
private_key_accounts=[self.default_account], claim_id=channel_id)
|
||||||
if not certificates:
|
if not certificates:
|
||||||
raise ValueError("Couldn't find channel with claim_id '{}'." .format(channel_id))
|
raise ValueError("Couldn't find channel with claim_id '{}'." .format(channel_id))
|
||||||
return certificates[0]
|
return certificates[0]
|
||||||
if channel_name is not None:
|
if channel_name is not None:
|
||||||
certificates = yield self.wallet_manager.get_certificates(
|
certificates = await self.wallet_manager.get_certificates(
|
||||||
private_key_accounts=[self.default_account], claim_name=channel_name)
|
private_key_accounts=[self.default_account], claim_name=channel_name)
|
||||||
if not certificates:
|
if not certificates:
|
||||||
raise ValueError("Couldn't find channel with name '{}'.".format(channel_name))
|
raise ValueError("Couldn't find channel with name '{}'.".format(channel_name))
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from twisted.internet import defer
|
|
||||||
|
|
||||||
from lbrynet.file_manager.EncryptedFileCreator import create_lbry_file
|
from lbrynet.file_manager.EncryptedFileCreator import create_lbry_file
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def d2f(d):
|
||||||
|
return d.asFuture(asyncio.get_event_loop())
|
||||||
|
|
||||||
|
|
||||||
class Publisher:
|
class Publisher:
|
||||||
def __init__(self, blob_manager, payment_rate_manager, storage, lbry_file_manager, wallet, certificate):
|
def __init__(self, blob_manager, payment_rate_manager, storage, lbry_file_manager, wallet, certificate):
|
||||||
self.blob_manager = blob_manager
|
self.blob_manager = blob_manager
|
||||||
|
@ -19,8 +22,7 @@ class Publisher:
|
||||||
self.certificate = certificate
|
self.certificate = certificate
|
||||||
self.lbry_file = None
|
self.lbry_file = None
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
async def create_and_publish_stream(self, name, bid, claim_dict, file_path, holding_address=None):
|
||||||
def create_and_publish_stream(self, name, bid, claim_dict, file_path, holding_address=None):
|
|
||||||
"""Create lbry file and make claim"""
|
"""Create lbry file and make claim"""
|
||||||
log.info('Starting publish for %s', name)
|
log.info('Starting publish for %s', name)
|
||||||
if not os.path.isfile(file_path):
|
if not os.path.isfile(file_path):
|
||||||
|
@ -30,10 +32,10 @@ class Publisher:
|
||||||
|
|
||||||
file_name = os.path.basename(file_path)
|
file_name = os.path.basename(file_path)
|
||||||
with open(file_path, 'rb') as read_handle:
|
with open(file_path, 'rb') as read_handle:
|
||||||
self.lbry_file = yield create_lbry_file(
|
self.lbry_file = await d2f(create_lbry_file(
|
||||||
self.blob_manager, self.storage, self.payment_rate_manager, self.lbry_file_manager, file_name,
|
self.blob_manager, self.storage, self.payment_rate_manager, self.lbry_file_manager, file_name,
|
||||||
read_handle
|
read_handle
|
||||||
)
|
))
|
||||||
|
|
||||||
if 'source' not in claim_dict['stream']:
|
if 'source' not in claim_dict['stream']:
|
||||||
claim_dict['stream']['source'] = {}
|
claim_dict['stream']['source'] = {}
|
||||||
|
@ -41,37 +43,36 @@ class Publisher:
|
||||||
claim_dict['stream']['source']['sourceType'] = 'lbry_sd_hash'
|
claim_dict['stream']['source']['sourceType'] = 'lbry_sd_hash'
|
||||||
claim_dict['stream']['source']['contentType'] = get_content_type(file_path)
|
claim_dict['stream']['source']['contentType'] = get_content_type(file_path)
|
||||||
claim_dict['stream']['source']['version'] = "_0_0_1" # need current version here
|
claim_dict['stream']['source']['version'] = "_0_0_1" # need current version here
|
||||||
tx = yield self.wallet.claim_name(
|
tx = await self.wallet.claim_name(
|
||||||
name, bid, claim_dict, self.certificate, holding_address
|
name, bid, claim_dict, self.certificate, holding_address
|
||||||
)
|
)
|
||||||
|
|
||||||
# check if we have a file already for this claim (if this is a publish update with a new stream)
|
# check if we have a file already for this claim (if this is a publish update with a new stream)
|
||||||
old_stream_hashes = yield self.storage.get_old_stream_hashes_for_claim_id(
|
old_stream_hashes = await d2f(self.storage.get_old_stream_hashes_for_claim_id(
|
||||||
tx.outputs[0].claim_id, self.lbry_file.stream_hash
|
tx.outputs[0].claim_id, self.lbry_file.stream_hash
|
||||||
)
|
))
|
||||||
if old_stream_hashes:
|
if old_stream_hashes:
|
||||||
for lbry_file in filter(lambda l: l.stream_hash in old_stream_hashes,
|
for lbry_file in filter(lambda l: l.stream_hash in old_stream_hashes,
|
||||||
list(self.lbry_file_manager.lbry_files)):
|
list(self.lbry_file_manager.lbry_files)):
|
||||||
yield self.lbry_file_manager.delete_lbry_file(lbry_file, delete_file=False)
|
await d2f(self.lbry_file_manager.delete_lbry_file(lbry_file, delete_file=False))
|
||||||
log.info("Removed old stream for claim update: %s", lbry_file.stream_hash)
|
log.info("Removed old stream for claim update: %s", lbry_file.stream_hash)
|
||||||
|
|
||||||
yield self.storage.save_content_claim(
|
await d2f(self.storage.save_content_claim(
|
||||||
self.lbry_file.stream_hash, tx.outputs[0].id
|
self.lbry_file.stream_hash, tx.outputs[0].id
|
||||||
)
|
))
|
||||||
defer.returnValue(tx)
|
return tx
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
async def publish_stream(self, name, bid, claim_dict, stream_hash, holding_address=None):
|
||||||
def publish_stream(self, name, bid, claim_dict, stream_hash, holding_address=None):
|
|
||||||
"""Make a claim without creating a lbry file"""
|
"""Make a claim without creating a lbry file"""
|
||||||
tx = yield self.wallet.claim_name(
|
tx = await self.wallet.claim_name(
|
||||||
name, bid, claim_dict, self.certificate, holding_address
|
name, bid, claim_dict, self.certificate, holding_address
|
||||||
)
|
)
|
||||||
if stream_hash: # the stream_hash returned from the db will be None if this isn't a stream we have
|
if stream_hash: # the stream_hash returned from the db will be None if this isn't a stream we have
|
||||||
yield self.storage.save_content_claim(
|
await d2f(self.storage.save_content_claim(
|
||||||
stream_hash, tx.outputs[0].id
|
stream_hash, tx.outputs[0].id
|
||||||
)
|
))
|
||||||
self.lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == stream_hash][0]
|
self.lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == stream_hash][0]
|
||||||
defer.returnValue(tx)
|
return tx
|
||||||
|
|
||||||
|
|
||||||
def get_content_type(filename):
|
def get_content_type(filename):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from six.moves.urllib import parse as urlparse
|
from six.moves.urllib import parse as urlparse
|
||||||
import json
|
import json
|
||||||
|
@ -7,6 +8,7 @@ import signal
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from twisted.web import server
|
from twisted.web import server
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
from twisted.internet.defer import Deferred
|
||||||
from twisted.python.failure import Failure
|
from twisted.python.failure import Failure
|
||||||
from twisted.internet.error import ConnectionDone, ConnectionLost
|
from twisted.internet.error import ConnectionDone, ConnectionLost
|
||||||
from txjsonrpc import jsonrpclib
|
from txjsonrpc import jsonrpclib
|
||||||
|
@ -141,19 +143,17 @@ class AuthorizedBase(metaclass=JSONRPCServerType):
|
||||||
condition_names = conditions.get("conditions", [])
|
condition_names = conditions.get("conditions", [])
|
||||||
|
|
||||||
def _wrap(fn):
|
def _wrap(fn):
|
||||||
@defer.inlineCallbacks
|
|
||||||
@wraps(fn)
|
@wraps(fn)
|
||||||
def _inner(*args, **kwargs):
|
def _inner(*args, **kwargs):
|
||||||
component_manager = args[0].component_manager
|
component_manager = args[0].component_manager
|
||||||
for condition_name in condition_names:
|
for condition_name in condition_names:
|
||||||
condition_result, err_msg = yield component_manager.evaluate_condition(condition_name)
|
condition_result, err_msg = component_manager.evaluate_condition(condition_name)
|
||||||
if not condition_result:
|
if not condition_result:
|
||||||
raise ComponentStartConditionNotMet(err_msg)
|
raise ComponentStartConditionNotMet(err_msg)
|
||||||
if not component_manager.all_components_running(*components):
|
if not component_manager.all_components_running(*components):
|
||||||
raise ComponentsNotStarted("the following required components have not yet started: "
|
raise ComponentsNotStarted("the following required components have not yet started: "
|
||||||
"%s" % json.dumps(components))
|
"%s" % json.dumps(components))
|
||||||
result = yield fn(*args, **kwargs)
|
return fn(*args, **kwargs)
|
||||||
defer.returnValue(result)
|
|
||||||
return _inner
|
return _inner
|
||||||
return _wrap
|
return _wrap
|
||||||
|
|
||||||
|
@ -446,7 +446,18 @@ class AuthJSONRPCServer(AuthorizedBase):
|
||||||
)
|
)
|
||||||
return server.NOT_DONE_YET
|
return server.NOT_DONE_YET
|
||||||
|
|
||||||
d = defer.maybeDeferred(fn, self, *_args, **_kwargs)
|
try:
|
||||||
|
result = fn(self, *_args, **_kwargs)
|
||||||
|
if isinstance(result, Deferred):
|
||||||
|
d = result
|
||||||
|
elif isinstance(result, Failure):
|
||||||
|
d = defer.fail(result)
|
||||||
|
elif asyncio.iscoroutine(result):
|
||||||
|
d = Deferred.fromFuture(asyncio.ensure_future(result))
|
||||||
|
else:
|
||||||
|
d = defer.succeed(result)
|
||||||
|
except:
|
||||||
|
d = Failure(captureVars=Deferred.debug)
|
||||||
|
|
||||||
# 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
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
|
||||||
|
@ -265,7 +266,8 @@ class LbryWalletManager(BaseWalletManager):
|
||||||
ledger: MainNetLedger = self.default_account.ledger
|
ledger: MainNetLedger = self.default_account.ledger
|
||||||
results = await ledger.resolve(page, page_size, *uris)
|
results = await ledger.resolve(page, page_size, *uris)
|
||||||
await self.old_db.save_claims_for_resolve(
|
await self.old_db.save_claims_for_resolve(
|
||||||
(value for value in results.values() if 'error' not in value))
|
(value for value in results.values() if 'error' not in value)
|
||||||
|
).asFuture(asyncio.get_event_loop())
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def get_claims_for_name(self, name: str):
|
def get_claims_for_name(self, name: str):
|
||||||
|
@ -362,7 +364,7 @@ class LbryWalletManager(BaseWalletManager):
|
||||||
await account.ledger.broadcast(tx)
|
await account.ledger.broadcast(tx)
|
||||||
await self.old_db.save_claims([self._old_get_temp_claim_info(
|
await self.old_db.save_claims([self._old_get_temp_claim_info(
|
||||||
tx, tx.outputs[0], claim_address, claim_dict, name, amount
|
tx, tx.outputs[0], claim_address, claim_dict, name, amount
|
||||||
)])
|
)]).asFuture(asyncio.get_event_loop())
|
||||||
# TODO: release reserved tx outputs in case anything fails by this point
|
# TODO: release reserved tx outputs in case anything fails by this point
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,11 @@ import tempfile
|
||||||
import logging
|
import logging
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
from orchstr8.testcase import IntegrationTestCase
|
from twisted.trial import unittest
|
||||||
|
from twisted.internet import utils, defer
|
||||||
|
from twisted.internet.utils import runWithWarningsSuppressed as originalRunWith
|
||||||
|
|
||||||
|
from orchstr8.testcase import IntegrationTestCase as BaseIntegrationTestCase
|
||||||
|
|
||||||
import lbryschema
|
import lbryschema
|
||||||
lbryschema.BLOCKCHAIN_NAME = 'lbrycrd_regtest'
|
lbryschema.BLOCKCHAIN_NAME = 'lbrycrd_regtest'
|
||||||
|
@ -86,13 +90,34 @@ class FakeAnalytics:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IntegrationTestCase(unittest.TestCase, BaseIntegrationTestCase):
|
||||||
|
|
||||||
|
async def setUp(self):
|
||||||
|
await self.asyncSetUp()
|
||||||
|
|
||||||
|
async def tearDown(self):
|
||||||
|
await self.asyncTearDown()
|
||||||
|
|
||||||
|
|
||||||
|
def run_with_async_support(suppress, f, *a, **kw):
|
||||||
|
if asyncio.iscoroutinefunction(f):
|
||||||
|
def test_method(*args, **kwargs):
|
||||||
|
return defer.Deferred.fromFuture(asyncio.ensure_future(f(*args, **kwargs)))
|
||||||
|
else:
|
||||||
|
test_method = f
|
||||||
|
return originalRunWith(suppress, test_method, *a, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
utils.runWithWarningsSuppressed = run_with_async_support
|
||||||
|
|
||||||
|
|
||||||
class CommandTestCase(IntegrationTestCase):
|
class CommandTestCase(IntegrationTestCase):
|
||||||
|
|
||||||
timeout = 180
|
timeout = 180
|
||||||
WALLET_MANAGER = LbryWalletManager
|
WALLET_MANAGER = LbryWalletManager
|
||||||
|
|
||||||
async def asyncSetUp(self):
|
async def setUp(self):
|
||||||
await super().asyncSetUp()
|
await super().setUp()
|
||||||
|
|
||||||
if self.VERBOSE:
|
if self.VERBOSE:
|
||||||
log.setLevel(logging.DEBUG)
|
log.setLevel(logging.DEBUG)
|
||||||
|
@ -139,8 +164,8 @@ class CommandTestCase(IntegrationTestCase):
|
||||||
self.daemon.wallet_manager = self.wallet_component.wallet_manager
|
self.daemon.wallet_manager = self.wallet_component.wallet_manager
|
||||||
self.manager.old_db = self.daemon.storage
|
self.manager.old_db = self.daemon.storage
|
||||||
|
|
||||||
async def asyncTearDown(self):
|
async def tearDown(self):
|
||||||
await super().asyncTearDown()
|
await super().tearDown()
|
||||||
self.wallet_component._running = False
|
self.wallet_component._running = False
|
||||||
await d2f(self.daemon._shutdown())
|
await d2f(self.daemon._shutdown())
|
||||||
|
|
||||||
|
@ -300,7 +325,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
|
||||||
file.write(b'Totally un-cliched ending')
|
file.write(b'Totally un-cliched ending')
|
||||||
file.write(b'**Audience Gasps**')
|
file.write(b'**Audience Gasps**')
|
||||||
file.flush()
|
file.flush()
|
||||||
claim3 = yield self.out(self.daemon.jsonrpc_publish(
|
claim3 = await self.out(self.daemon.jsonrpc_publish(
|
||||||
'fresh-start', '1.0', file_path=file.name, channel_name='@spam'
|
'fresh-start', '1.0', file_path=file.name, channel_name='@spam'
|
||||||
))
|
))
|
||||||
self.assertTrue(claim3['success'])
|
self.assertTrue(claim3['success'])
|
||||||
|
@ -360,7 +385,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
|
||||||
file.write(b'I know right? Totally a hit song')
|
file.write(b'I know right? Totally a hit song')
|
||||||
file.write(b'That\'s what goes around for songs these days anyways')
|
file.write(b'That\'s what goes around for songs these days anyways')
|
||||||
file.flush()
|
file.flush()
|
||||||
claim4 = yield self.out(self.daemon.jsonrpc_publish(
|
claim4 = await self.out(self.daemon.jsonrpc_publish(
|
||||||
'hit-song', '1.0', file_path=file.name, channel_id=channel['claim_id']
|
'hit-song', '1.0', file_path=file.name, channel_id=channel['claim_id']
|
||||||
))
|
))
|
||||||
self.assertTrue(claim4['success'])
|
self.assertTrue(claim4['success'])
|
||||||
|
@ -384,7 +409,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
|
||||||
|
|
||||||
class AccountManagement(CommandTestCase):
|
class AccountManagement(CommandTestCase):
|
||||||
|
|
||||||
VERBOSE = True
|
VERBOSE = False
|
||||||
|
|
||||||
async def test_performing_account_management_commands(self):
|
async def test_performing_account_management_commands(self):
|
||||||
# check initial account
|
# check initial account
|
||||||
|
@ -393,7 +418,7 @@ class AccountManagement(CommandTestCase):
|
||||||
|
|
||||||
# change account name and gap
|
# change account name and gap
|
||||||
account_id = response['lbc_regtest'][0]['id']
|
account_id = response['lbc_regtest'][0]['id']
|
||||||
await self.daemon.jsonrpc_account_set(
|
self.daemon.jsonrpc_account_set(
|
||||||
account_id=account_id, new_name='test account',
|
account_id=account_id, new_name='test account',
|
||||||
receiving_gap=95, receiving_max_uses=96,
|
receiving_gap=95, receiving_max_uses=96,
|
||||||
change_gap=97, change_max_uses=98
|
change_gap=97, change_max_uses=98
|
||||||
|
@ -424,7 +449,7 @@ class AccountManagement(CommandTestCase):
|
||||||
account_seed = response['lbc_regtest'][1]['seed']
|
account_seed = response['lbc_regtest'][1]['seed']
|
||||||
|
|
||||||
# remove account
|
# remove account
|
||||||
await self.daemon.jsonrpc_account_remove(response['lbc_regtest'][1]['id'])
|
self.daemon.jsonrpc_account_remove(response['lbc_regtest'][1]['id'])
|
||||||
response = await self.daemon.jsonrpc_account_list()
|
response = await self.daemon.jsonrpc_account_list()
|
||||||
self.assertEqual(len(response['lbc_regtest']), 1)
|
self.assertEqual(len(response['lbc_regtest']), 1)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue