updated code base to use generated errors

This commit is contained in:
Lex Berezhny 2019-11-19 13:57:14 -05:00
parent 86617f1bda
commit 57fd3c5801
11 changed files with 503 additions and 203 deletions

View file

@ -1,12 +1,12 @@
Code | Name | Message | Comment Code | Name | Message | Comment
---:|---|---|--- ---:|---|---|---
**1xx** | External | **Daemon `start` and other CLI command failures (non-recoverable)** **1xx** | Initialization | **Daemon `start` and other CLI command failures (non-recoverable)**
**10x** | Meta | Meta error codes not presented by `lbrynet` itself but from apps trying to interact with `lbrynet`. **10x** | Client | Error codes reported by clients connecting to `lbrynet` daemon.
104 | SDKConnectionError | Failed to establish HTTP connection to `lbrynet`. (Is it running?) 101 | RPCConnection | Failed to establish HTTP connection to `lbrynet`. (Is it running?)
105 | SDKRPCUnresponsive | HTTP connection established but daemon is not responding to commands. 102 | RPCUnresponsive | HTTP connection established but daemon is not responding to commands.
106 | SDKWebSocketUnresponsive | Failed to establish WebSocket connection to `lbrynet`. (Is it running?) 103 | WebSocketConnection | WebSocket connection established but daemon is not responding to commands.
107 | SDKWebSocketConnectionError | WebSocket connection established but daemon is not responding to commands. 104 | WebSocketUnresponsive | Failed to establish WebSocket connection to `lbrynet`. (Is it running?)
**11x** | System | Enough of `lbrynet` was able to start to determine external factors causing eventual failure. **11x** | Hardware | Enough of `lbrynet` was able to start to determine external factors causing eventual failure.
110 | OutOfSpace | Out of disk space. 110 | OutOfSpace | Out of disk space.
111 | OutOfRAM | Out of RAM. 111 | OutOfRAM | Out of RAM.
**12x** | Environment | Internal factors preventing `lbrynet` from bootstrapping itself. **12x** | Environment | Internal factors preventing `lbrynet` from bootstrapping itself.
@ -53,6 +53,9 @@ Code | Name | Message | Comment
**32x** | ChannelSigning | Channel signing. **32x** | ChannelSigning | Channel signing.
320 | ChannelKeyNotFound | Channel signing key not found. 320 | ChannelKeyNotFound | Channel signing key not found.
321 | ChannelKeyInvalid | Channel signing key is out of date. | For example, channel was updated but you don't have the updated key. 321 | ChannelKeyInvalid | Channel signing key is out of date. | For example, channel was updated but you don't have the updated key.
**33x** | Resolve | Errors while resolving urls.
331 | ResolveError | Failed to resolve '{uri}'.
332 | ResolveTimeout | Failed to resolve '{uri}' within the timeout.
**4xx** | Blob | **Blobs** **4xx** | Blob | **Blobs**
**40x** | BlobAvailability | Blob availability. **40x** | BlobAvailability | Blob availability.
400 | BlobNotFound | Blob not found. 400 | BlobNotFound | Blob not found.
@ -64,3 +67,19 @@ Code | Name | Message | Comment
411 | CorruptBlob | Blobs is corrupted. 411 | CorruptBlob | Blobs is corrupted.
**42x** | BlobEncryption | Encrypting / Creating **42x** | BlobEncryption | Encrypting / Creating
420 | BlobFailedEncryption | Failed to encrypt blob. 420 | BlobFailedEncryption | Failed to encrypt blob.
**43x** | BlobRelated | Exceptions carried over from old error system.
431 | DownloadCancelled | Download was canceled.
432 | DownloadSDTimeout | Failed to download sd blob {download} within timeout.
433 | DownloadDataTimeout | Failed to download data blobs for sd hash {download} within timeout.
434 | InvalidStreamDescriptor | {message}
435 | InvalidData | {message}
436 | InvalidBlobHash | {message}
**5xx** | Component | **Components**
501 | ComponentStartConditionNotMet | Unresolved dependencies for: {components}
502 | ComponentsNotStarted | {message}
**6xx** | CurrencyExchange | **Currency Exchange**
601 | InvalidExchangeRateResponse | Failed to get exchange rate from {source}: {reason}
602 | CurrencyConversion | {message}
603 | InvalidCurrency | Invalid currency: {currency} is not a supported currency.
**7xx** | Purchase | Purchase process errors.
701 | KeyFeeAboveMaxAllowed | {message}

View file

@ -1,202 +1,473 @@
class RPCError(Exception): from .base import BaseError
code = 0
class PriceDisagreementError(Exception): class InitializationError(BaseError):
pass """
**Daemon `start` and other CLI command failures (non-recoverable)**
"""
class DuplicateStreamHashError(Exception): class ClientError(InitializationError):
pass """
Error codes reported by clients connecting to `lbrynet` daemon.
"""
class DownloadCancelledError(Exception): class RPCConnectionError(ClientError):
pass def __init__(self):
super().__init__("Failed to establish HTTP connection to `lbrynet`. (Is it running?)")
class DownloadSDTimeout(Exception): class RPCUnresponsiveError(ClientError):
def __init__(self, download): def __init__(self):
super().__init__(f'Failed to download sd blob {download} within timeout') super().__init__("HTTP connection established but daemon is not responding to commands.")
self.download = download
class DownloadTimeoutError(Exception): class WebSocketConnectionError(ClientError):
def __init__(self, download): def __init__(self):
super().__init__(f'Failed to download {download} within timeout') super().__init__("WebSocket connection established but daemon is not responding to commands.")
self.download = download
class DownloadDataTimeout(Exception): class WebSocketUnresponsiveError(ClientError):
def __init__(self, download): def __init__(self):
super().__init__(f'Failed to download data blobs for sd hash {download} within timeout') super().__init__("Failed to establish WebSocket connection to `lbrynet`. (Is it running?)")
self.download = download
class ResolveTimeout(Exception): class HardwareError(InitializationError):
"""
Enough of `lbrynet` was able to start to determine external factors causing eventual failure.
"""
class OutOfSpaceError(HardwareError):
def __init__(self):
super().__init__("Out of disk space.")
class OutOfRAMError(HardwareError):
def __init__(self):
super().__init__("Out of RAM.")
class EnvironmentError(InitializationError):
"""
Internal factors preventing `lbrynet` from bootstrapping itself.
"""
class IncompatiblePythonError(EnvironmentError):
def __init__(self):
super().__init__("Incompatible version of Python.")
class IncompatibleDependencyError(EnvironmentError):
def __init__(self):
super().__init__("Incompatible version of some library.")
class ConfigurationError(InitializationError):
"""
Configuration errors.
"""
class CannotWriteConfigurationError(ConfigurationError):
"""
When writing the default config fails on startup, such as due to permission issues.
"""
def __init__(self, path):
super().__init__(f"Cannot write configuration file '{path}'.")
class CannotOpenConfigurationError(ConfigurationError):
"""
Can't open the config file user provided via command line args.
"""
def __init__(self, path):
super().__init__(f"Cannot find provided configuration file '{path}'.")
class CannotParseConfigurationError(ConfigurationError):
"""
Includes the syntax error / line number to help user fix it.
"""
def __init__(self, path):
super().__init__(f"Failed to parse the configuration file '{path}'.")
class ConfigurationMissingError(ConfigurationError):
def __init__(self, path):
super().__init__(f"Configuration file '{path}' is missing setting that has no default / fallback.")
class ConfigurationInvalidError(ConfigurationError):
def __init__(self, path):
super().__init__(f"Configuration file '{path}' has setting with invalid value.")
class CommandError(InitializationError):
"""
Errors preparing to execute commands.
"""
class CommandDoesNotExistError(CommandError):
def __init__(self, command):
super().__init__(f"Command '{command}' does not exist.")
class CommandDeprecatedError(CommandError):
def __init__(self, command):
super().__init__(f"Command '{command}' is deprecated.")
class CommandInvalidArgumentError(CommandError):
def __init__(self, command):
super().__init__(f"Invalid arguments for command '{command}'.")
class CommandTemporarilyUnavailableError(CommandError):
"""
Such as waiting for required components to start.
"""
def __init__(self, command):
super().__init__(f"Command '{command}' is temporarily unavailable.")
class CommandPermanentlyUnavailableError(CommandError):
"""
such as when required component was intentionally configured not to start.
"""
def __init__(self, command):
super().__init__(f"Command '{command}' is permanently unavailable.")
class NetworkingError(BaseError):
"""
**Networking**
"""
class ConnectivityError(NetworkingError):
"""
General connectivity.
"""
class NoInternetError(ConnectivityError):
def __init__(self):
super().__init__("No internet connection.")
class NoUPnPSupportError(ConnectivityError):
def __init__(self):
super().__init__("Router does not support UPnP.")
class WalletConnectivityError(NetworkingError):
"""
Wallet server connectivity.
"""
class WalletConnectionError(WalletConnectivityError):
"""
Should normally not need to be handled higher up as `lbrynet` will retry other servers.
"""
def __init__(self):
super().__init__("Failed connecting to a lbryumx server.")
class WalletConnectionsError(WalletConnectivityError):
"""
Will need to bubble up and require user to do something.
"""
def __init__(self):
super().__init__("Failed connecting to all known lbryumx servers.")
class WalletConnectionDroppedError(WalletConnectivityError):
"""
Maybe we were being bad?
"""
def __init__(self):
super().__init__("lbryumx droppped our connection.")
class WalletDisconnectedError(NetworkingError):
"""
Wallet connection dropped.
"""
class WalletServerSuspiciousError(WalletDisconnectedError):
def __init__(self):
super().__init__("Disconnected from lbryumx server due to suspicious responses. *generic*")
class WalletServerValidationError(WalletDisconnectedError):
def __init__(self):
super().__init__("Disconnected from lbryumx server due to SPV validation failure.")
class WalletServerHeaderError(WalletDisconnectedError):
def __init__(self):
super().__init__("Disconnected from lbryumx server due to incorrect header received.")
class WalletServerVersionError(WalletDisconnectedError):
def __init__(self):
super().__init__("Disconnected from lbryumx server due to incompatible protocol version.")
class WalletServerUnresponsiveError(WalletDisconnectedError):
def __init__(self):
super().__init__("Disconnected from lbryumx server due to unresponsiveness.")
class DataConnectivityError(NetworkingError):
"""
P2P connection errors.
"""
class DataNetworkError(NetworkingError):
"""
P2P download errors.
"""
class DataDownloadError(DataNetworkError):
def __init__(self):
super().__init__("Failed to download blob. *generic*")
class DataUploadError(NetworkingError):
"""
P2P upload errors.
"""
class DHTConnectivityError(NetworkingError):
"""
DHT connectivity issues.
"""
class DHTProtocolError(NetworkingError):
"""
DHT protocol issues.
"""
class BlockchainError(BaseError):
"""
**Blockchain**
"""
class TransactionRejectionError(BlockchainError):
"""
Transaction rejected.
"""
class TransactionRejectedError(TransactionRejectionError):
def __init__(self):
super().__init__("Transaction rejected, unknown reason.")
class TransactionFeeTooLowError(TransactionRejectionError):
def __init__(self):
super().__init__("Fee too low.")
class TransactionInvalidSignatureError(TransactionRejectionError):
def __init__(self):
super().__init__("Invalid signature.")
class InsufficientFundsError(BlockchainError):
"""
determined by wallet prior to attempting to broadcast a tx; this is different for example from a TX
being created and sent but then rejected by lbrycrd for unspendable utxos.
"""
class ChannelSigningError(BlockchainError):
"""
Channel signing.
"""
class ChannelKeyNotFoundError(ChannelSigningError):
def __init__(self):
super().__init__("Channel signing key not found.")
class ChannelKeyInvalidError(ChannelSigningError):
"""
For example, channel was updated but you don't have the updated key.
"""
def __init__(self):
super().__init__("Channel signing key is out of date.")
class ResolveError(BlockchainError):
"""
Errors while resolving urls.
"""
class ResolveErrorError(ResolveError):
def __init__(self, uri): def __init__(self, uri):
super().__init__(f'Failed to resolve "{uri}" within the timeout') super().__init__(f"Failed to resolve '{uri}'.")
self.uri = uri
class RequestCanceledError(Exception): class ResolveTimeoutError(ResolveError):
pass def __init__(self, uri):
super().__init__(f"Failed to resolve '{uri}' within the timeout.")
class NegativeFundsError(Exception): class BlobError(BaseError):
pass """
**Blobs**
"""
class NullFundsError(Exception): class BlobAvailabilityError(BlobError):
pass """
Blob availability.
"""
class InsufficientFundsError(RPCError): class BlobNotFoundError(BlobAvailabilityError):
code = -310 def __init__(self):
super().__init__("Blob not found.")
class CurrencyConversionError(Exception): class BlobPermissionDeniedError(BlobAvailabilityError):
pass def __init__(self):
super().__init__("Permission denied to read blob.")
class FileOpenError(ValueError): class BlobTooBigError(BlobAvailabilityError):
# this extends ValueError because it is replacing a ValueError in EncryptedFileDownloader def __init__(self):
# and I don't know where it might get caught upstream super().__init__("Blob is too big.")
pass
class ResolveError(Exception): class BlobEmptyError(BlobAvailabilityError):
pass def __init__(self):
super().__init__("Blob is empty.")
class ConnectionClosedBeforeResponseError(Exception): class BlobDecryptionError(BlobError):
pass """
Decryption / Assembly
"""
class KeyFeeAboveMaxAllowed(Exception): class BlobFailedDecryptionError(BlobDecryptionError):
pass def __init__(self):
super().__init__("Failed to decrypt blob.")
class InvalidExchangeRateResponse(Exception): class CorruptBlobError(BlobDecryptionError):
def __init__(self):
super().__init__("Blobs is corrupted.")
class BlobEncryptionError(BlobError):
"""
Encrypting / Creating
"""
class BlobFailedEncryptionError(BlobEncryptionError):
def __init__(self):
super().__init__("Failed to encrypt blob.")
class BlobRelatedError(BlobError):
"""
Exceptions carried over from old error system.
"""
class DownloadCancelledError(BlobRelatedError):
def __init__(self):
super().__init__("Download was canceled.")
class DownloadSDTimeoutError(BlobRelatedError):
def __init__(self, download):
super().__init__(f"Failed to download sd blob {download} within timeout.")
class DownloadDataTimeoutError(BlobRelatedError):
def __init__(self, download):
super().__init__(f"Failed to download data blobs for sd hash {download} within timeout.")
class InvalidStreamDescriptorError(BlobRelatedError):
def __init__(self, message):
super().__init__(f"{message}")
class InvalidDataError(BlobRelatedError):
def __init__(self, message):
super().__init__(f"{message}")
class InvalidBlobHashError(BlobRelatedError):
def __init__(self, message):
super().__init__(f"{message}")
class ComponentError(BaseError):
"""
**Components**
"""
class ComponentStartConditionNotMetError(ComponentError):
def __init__(self, components):
super().__init__(f"Unresolved dependencies for: {components}")
class ComponentsNotStartedError(ComponentError):
def __init__(self, message):
super().__init__(f"{message}")
class CurrencyExchangeError(BaseError):
"""
**Currency Exchange**
"""
class InvalidExchangeRateResponseError(CurrencyExchangeError):
def __init__(self, source, reason): def __init__(self, source, reason):
super().__init__(f'Failed to get exchange rate from {source}:{reason}') super().__init__(f"Failed to get exchange rate from {source}: {reason}")
self.source = source
self.reason = reason
class UnknownNameError(Exception): class CurrencyConversionError(CurrencyExchangeError):
def __init__(self, name): def __init__(self, message):
super().__init__(f'Name {name} is unknown') super().__init__(f"{message}")
self.name = name
class UnknownClaimID(Exception): class InvalidCurrencyError(CurrencyExchangeError):
def __init__(self, claim_id):
super().__init__(f'Claim {claim_id} is unknown')
self.claim_id = claim_id
class UnknownURI(Exception):
def __init__(self, uri):
super().__init__(f'URI {uri} cannot be resolved')
self.name = uri
class UnknownOutpoint(Exception):
def __init__(self, outpoint):
super().__init__(f'Outpoint {outpoint} cannot be resolved')
self.outpoint = outpoint
class InvalidName(Exception):
def __init__(self, name, invalid_characters):
self.name = name
self.invalid_characters = invalid_characters
super().__init__(
'URI contains invalid characters: {}'.format(','.join(invalid_characters)))
class UnknownStreamTypeError(Exception):
def __init__(self, stream_type):
self.stream_type = stream_type
def __str__(self):
return repr(self.stream_type)
class InvalidStreamDescriptorError(Exception):
pass
class InvalidStreamInfoError(Exception):
def __init__(self, name, stream_info):
msg = f'{name} has claim with invalid stream info: {stream_info}'
super().__init__(msg)
self.name = name
self.stream_info = stream_info
class MisbehavingPeerError(Exception):
pass
class InvalidDataError(MisbehavingPeerError):
pass
class NoResponseError(MisbehavingPeerError):
pass
class InvalidResponseError(MisbehavingPeerError):
pass
class NoSuchBlobError(Exception):
pass
class NoSuchStreamHash(Exception):
pass
class NoSuchSDHash(Exception):
"""
Raised if sd hash is not known
"""
class InvalidBlobHashError(Exception):
pass
class InvalidHeaderError(Exception):
pass
class InvalidAuthenticationToken(Exception):
pass
class NegotiationError(Exception):
pass
class InvalidCurrencyError(Exception):
def __init__(self, currency): def __init__(self, currency):
self.currency = currency super().__init__(f"Invalid currency: {currency} is not a supported currency.")
super().__init__(
f'Invalid currency: {currency} is not a supported currency.')
class NoSuchDirectoryError(Exception): class PurchaseError(BaseError):
def __init__(self, directory): """
self.directory = directory Purchase process errors.
super().__init__(f'No such directory {directory}') """
class ComponentStartConditionNotMet(Exception): class KeyFeeAboveMaxAllowedError(PurchaseError):
pass def __init__(self, message):
super().__init__(f"{message}")
class ComponentsNotStarted(Exception):
pass

View file

@ -1,11 +1,14 @@
import re import re
from textwrap import fill, indent
CLASS = """ CLASS = """
class {name}Error({parent}Error):{doc} class {name}Error({parent}Error):{doc}
"""
INIT = """\
def __init__({args}): def __init__({args}):
super().__init__(f'{desc}') super().__init__({format}"{desc}")
""" """
INDENT = ' ' * 4 INDENT = ' ' * 4
@ -13,6 +16,7 @@ INDENT = ' ' * 4
def main(): def main():
with open('README.md', 'r') as readme: with open('README.md', 'r') as readme:
print('from .base import BaseError\n')
stack = {} stack = {}
started = False started = False
for line in readme.readlines(): for line in readme.readlines():
@ -25,19 +29,29 @@ def main():
columns = [c.strip() for c in line.split('|')] columns = [c.strip() for c in line.split('|')]
(h, code, desc), comment = columns[:3], "" (h, code, desc), comment = columns[:3], ""
if len(columns) == 4: if len(columns) == 4:
comment = columns[3] comment = columns[3].strip()
if h.startswith('**'): if h.startswith('**'):
if h.count('x') == 1: if h.count('x') == 1:
parent = stack[h[2:3]][0] parent = stack[h[2:3]][0]
stack[h.replace('**', '').replace('x', '')] = (code, desc) stack[h.replace('**', '').replace('x', '')] = (code, desc)
else: if h.count('x') == 2:
parent = stack[h[:2]][0] stack[h.replace('**', '').replace('x', '')+'0'] = (code, desc)
comment = f'\n{INDENT}"""\n{indent(fill(comment or desc, 100), INDENT)}\n{INDENT}"""'
print(CLASS.format(name=code, parent=parent, doc=comment))
continue
parent = stack[h[:2]][0]
args = ['self'] args = ['self']
for arg in re.findall('{([a-z0-1]+)}', desc): for arg in re.findall('{([a-z0-1]+)}', desc):
args.append(arg) args.append(arg)
fmt = ""
if len(args) > 1:
fmt = "f"
if comment: if comment:
comment = f'\n{INDENT}"""\n{INDENT}{comment}\n{INDENT}"""' comment = f'\n{INDENT}"""\n{INDENT}{comment}\n{INDENT}"""'
print(CLASS.format(name=code, parent=parent, args=', '.join(args), desc=desc, doc=comment)) print((CLASS+INIT).format(
name=code, parent=parent, args=', '.join(args),
desc=desc, doc=comment, format=fmt
))
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -1,7 +1,7 @@
import logging import logging
import asyncio import asyncio
from lbry.conf import Config from lbry.conf import Config
from lbry.error import ComponentStartConditionNotMet from lbry.error import ComponentStartConditionNotMetError
from lbry.dht.peer import PeerManager from lbry.dht.peer import PeerManager
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -106,7 +106,7 @@ class ComponentManager:
staged.update(to_stage) staged.update(to_stage)
steps.append(step) steps.append(step)
elif components: elif components:
raise ComponentStartConditionNotMet("Unresolved dependencies for: %s" % components) raise ComponentStartConditionNotMetError(components)
if reverse: if reverse:
steps.reverse() steps.reverse()
return steps return steps

View file

@ -25,8 +25,7 @@ from lbry.conf import Config, Setting
from lbry.blob.blob_file import is_valid_blobhash, BlobBuffer from lbry.blob.blob_file import is_valid_blobhash, BlobBuffer
from lbry.blob_exchange.downloader import download_blob from lbry.blob_exchange.downloader import download_blob
from lbry.dht.peer import make_kademlia_peer from lbry.dht.peer import make_kademlia_peer
from lbry.error import DownloadSDTimeout, ComponentsNotStarted from lbry.error import DownloadSDTimeoutError, ComponentsNotStartedError, ComponentStartConditionNotMetError
from lbry.error import NullFundsError, NegativeFundsError, ComponentStartConditionNotMet
from lbry.extras import system_info from lbry.extras import system_info
from lbry.extras.daemon import analytics from lbry.extras.daemon import analytics
from lbry.extras.daemon.Components import WALLET_COMPONENT, DATABASE_COMPONENT, DHT_COMPONENT, BLOB_COMPONENT from lbry.extras.daemon.Components import WALLET_COMPONENT, DATABASE_COMPONENT, DHT_COMPONENT, BLOB_COMPONENT
@ -68,10 +67,11 @@ def requires(*components, **conditions):
for condition_name in condition_names: for condition_name in condition_names:
condition_result, err_msg = 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 ComponentStartConditionNotMetError(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 ComponentsNotStartedError(
"%s" % json.dumps(components)) f"the following required components have not yet started: {json.dumps(components)}"
)
return fn(*args, **kwargs) return fn(*args, **kwargs)
return _inner return _inner
@ -962,7 +962,7 @@ class Daemon(metaclass=JSONRPCServerType):
save_file=save_file, wallet=wallet save_file=save_file, wallet=wallet
) )
if not stream: if not stream:
raise DownloadSDTimeout(uri) raise DownloadSDTimeoutError(uri)
except Exception as e: except Exception as e:
log.warning("Error downloading %s: %s", uri, str(e)) log.warning("Error downloading %s: %s", uri, str(e))
return {"error": str(e)} return {"error": str(e)}
@ -1292,10 +1292,6 @@ class Daemon(metaclass=JSONRPCServerType):
accounts = wallet.get_accounts_or_all(funding_account_ids) accounts = wallet.get_accounts_or_all(funding_account_ids)
amount = self.get_dewies_or_error("amount", amount) amount = self.get_dewies_or_error("amount", amount)
if not amount:
raise NullFundsError
if amount < 0:
raise NegativeFundsError()
if addresses and not isinstance(addresses, list): if addresses and not isinstance(addresses, list):
addresses = [addresses] addresses = [addresses]

View file

@ -5,7 +5,7 @@ import json
from decimal import Decimal from decimal import Decimal
from typing import Optional from typing import Optional
from aiohttp.client_exceptions import ClientError from aiohttp.client_exceptions import ClientError
from lbry.error import InvalidExchangeRateResponse, CurrencyConversionError from lbry.error import InvalidExchangeRateResponseError, CurrencyConversionError
from lbry.utils import aiohttp_request from lbry.utils import aiohttp_request
from lbry.wallet.dewies import lbc_to_dewies from lbry.wallet.dewies import lbc_to_dewies
@ -81,7 +81,7 @@ class MarketFeed:
try: try:
response = await asyncio.wait_for(self._make_request(), self.REQUESTS_TIMEOUT) response = await asyncio.wait_for(self._make_request(), self.REQUESTS_TIMEOUT)
self._save_price(self._subtract_fee(self._handle_response(response))) self._save_price(self._subtract_fee(self._handle_response(response)))
except (asyncio.TimeoutError, InvalidExchangeRateResponse, ClientError) as err: except (asyncio.TimeoutError, InvalidExchangeRateResponseError, ClientError) as err:
self._on_error(err) self._on_error(err)
await asyncio.sleep(self.EXCHANGE_RATE_UPDATE_RATE_SEC) await asyncio.sleep(self.EXCHANGE_RATE_UPDATE_RATE_SEC)
@ -108,14 +108,14 @@ class BittrexFeed(MarketFeed):
def _handle_response(self, response): def _handle_response(self, response):
json_response = json.loads(response) json_response = json.loads(response)
if 'result' not in json_response: if 'result' not in json_response:
raise InvalidExchangeRateResponse(self.name, 'result not found') raise InvalidExchangeRateResponseError(self.name, 'result not found')
trades = json_response['result'] trades = json_response['result']
if len(trades) == 0: if len(trades) == 0:
raise InvalidExchangeRateResponse(self.market, 'trades not found') raise InvalidExchangeRateResponseError(self.market, 'trades not found')
totals = sum([i['Total'] for i in trades]) totals = sum([i['Total'] for i in trades])
qtys = sum([i['Quantity'] for i in trades]) qtys = sum([i['Quantity'] for i in trades])
if totals <= 0 or qtys <= 0: if totals <= 0 or qtys <= 0:
raise InvalidExchangeRateResponse(self.market, 'quantities were not positive') raise InvalidExchangeRateResponseError(self.market, 'quantities were not positive')
vwap = totals / qtys vwap = totals / qtys
return float(1.0 / vwap) return float(1.0 / vwap)
@ -133,7 +133,7 @@ class LBRYioFeed(MarketFeed):
def _handle_response(self, response): def _handle_response(self, response):
json_response = json.loads(response) json_response = json.loads(response)
if 'data' not in json_response: if 'data' not in json_response:
raise InvalidExchangeRateResponse(self.name, 'result not found') raise InvalidExchangeRateResponseError(self.name, 'result not found')
return 1.0 / json_response['data']['lbc_btc'] return 1.0 / json_response['data']['lbc_btc']
@ -151,9 +151,9 @@ class LBRYioBTCFeed(MarketFeed):
try: try:
json_response = json.loads(response) json_response = json.loads(response)
except ValueError: except ValueError:
raise InvalidExchangeRateResponse(self.name, "invalid rate response : %s" % response) raise InvalidExchangeRateResponseError(self.name, "invalid rate response : %s" % response)
if 'data' not in json_response: if 'data' not in json_response:
raise InvalidExchangeRateResponse(self.name, 'result not found') raise InvalidExchangeRateResponseError(self.name, 'result not found')
return 1.0 / json_response['data']['btc_usd'] return 1.0 / json_response['data']['btc_usd']
@ -171,10 +171,10 @@ class CryptonatorBTCFeed(MarketFeed):
try: try:
json_response = json.loads(response) json_response = json.loads(response)
except ValueError: except ValueError:
raise InvalidExchangeRateResponse(self.name, "invalid rate response") raise InvalidExchangeRateResponseError(self.name, "invalid rate response")
if 'ticker' not in json_response or len(json_response['ticker']) == 0 or \ if 'ticker' not in json_response or len(json_response['ticker']) == 0 or \
'success' not in json_response or json_response['success'] is not True: 'success' not in json_response or json_response['success'] is not True:
raise InvalidExchangeRateResponse(self.name, 'result not found') raise InvalidExchangeRateResponseError(self.name, 'result not found')
return float(json_response['ticker']['price']) return float(json_response['ticker']['price'])
@ -192,10 +192,10 @@ class CryptonatorFeed(MarketFeed):
try: try:
json_response = json.loads(response) json_response = json.loads(response)
except ValueError: except ValueError:
raise InvalidExchangeRateResponse(self.name, "invalid rate response") raise InvalidExchangeRateResponseError(self.name, "invalid rate response")
if 'ticker' not in json_response or len(json_response['ticker']) == 0 or \ if 'ticker' not in json_response or len(json_response['ticker']) == 0 or \
'success' not in json_response or json_response['success'] is not True: 'success' not in json_response or json_response['success'] is not True:
raise InvalidExchangeRateResponse(self.name, 'result not found') raise InvalidExchangeRateResponseError(self.name, 'result not found')
return float(json_response['ticker']['price']) return float(json_response['ticker']['price'])

View file

@ -4,7 +4,7 @@ import logging
import binascii import binascii
from lbry.dht.peer import make_kademlia_peer from lbry.dht.peer import make_kademlia_peer
from lbry.error import DownloadSDTimeout from lbry.error import DownloadSDTimeoutError
from lbry.utils import resolve_host, lru_cache_concurrent from lbry.utils import resolve_host, lru_cache_concurrent
from lbry.stream.descriptor import StreamDescriptor from lbry.stream.descriptor import StreamDescriptor
from lbry.blob_exchange.downloader import BlobDownloader from lbry.blob_exchange.downloader import BlobDownloader
@ -82,7 +82,7 @@ class StreamDownloader:
log.info("downloaded sd blob %s", self.sd_hash) log.info("downloaded sd blob %s", self.sd_hash)
self.time_to_descriptor = self.loop.time() - now self.time_to_descriptor = self.loop.time() - now
except asyncio.TimeoutError: except asyncio.TimeoutError:
raise DownloadSDTimeout(self.sd_hash) raise DownloadSDTimeoutError(self.sd_hash)
# parse the descriptor # parse the descriptor
self.descriptor = await StreamDescriptor.from_stream_descriptor_blob( self.descriptor = await StreamDescriptor.from_stream_descriptor_blob(

View file

@ -6,7 +6,7 @@ import logging
import binascii import binascii
from aiohttp.web import Request, StreamResponse, HTTPRequestRangeNotSatisfiable from aiohttp.web import Request, StreamResponse, HTTPRequestRangeNotSatisfiable
from lbry.utils import generate_id from lbry.utils import generate_id
from lbry.error import DownloadSDTimeout from lbry.error import DownloadSDTimeoutError
from lbry.schema.mime_types import guess_media_type from lbry.schema.mime_types import guess_media_type
from lbry.stream.downloader import StreamDownloader from lbry.stream.downloader import StreamDownloader
from lbry.stream.descriptor import StreamDescriptor, sanitize_file_name from lbry.stream.descriptor import StreamDescriptor, sanitize_file_name
@ -253,7 +253,7 @@ class ManagedStream:
await asyncio.wait_for(self.downloader.start(node), timeout, loop=self.loop) await asyncio.wait_for(self.downloader.start(node), timeout, loop=self.loop)
except asyncio.TimeoutError: except asyncio.TimeoutError:
self._running.clear() self._running.clear()
raise DownloadSDTimeout(self.sd_hash) raise DownloadSDTimeoutError(self.sd_hash)
if self.delayed_stop_task and not self.delayed_stop_task.done(): if self.delayed_stop_task and not self.delayed_stop_task.done():
self.delayed_stop_task.cancel() self.delayed_stop_task.cancel()

View file

@ -7,7 +7,7 @@ import typing
from typing import Optional from typing import Optional
from aiohttp.web import Request from aiohttp.web import Request
from lbry.error import ResolveError, InvalidStreamDescriptorError from lbry.error import ResolveError, InvalidStreamDescriptorError
from lbry.error import ResolveTimeout, DownloadDataTimeout from lbry.error import ResolveTimeoutError, DownloadDataTimeoutError
from lbry.utils import cache_concurrent from lbry.utils import cache_concurrent
from lbry.stream.descriptor import StreamDescriptor from lbry.stream.descriptor import StreamDescriptor
from lbry.stream.managed_stream import ManagedStream from lbry.stream.managed_stream import ManagedStream
@ -371,7 +371,7 @@ class StreamManager:
) )
resolved_result = self._convert_to_old_resolve_output(manager, response) resolved_result = self._convert_to_old_resolve_output(manager, response)
except asyncio.TimeoutError: except asyncio.TimeoutError:
raise ResolveTimeout(uri) raise ResolveTimeoutError(uri)
except Exception as err: except Exception as err:
if isinstance(err, asyncio.CancelledError): if isinstance(err, asyncio.CancelledError):
raise raise
@ -437,7 +437,7 @@ class StreamManager:
loop=self.loop) loop=self.loop)
return stream return stream
except asyncio.TimeoutError: except asyncio.TimeoutError:
error = DownloadDataTimeout(stream.sd_hash) error = DownloadDataTimeoutError(stream.sd_hash)
raise error raise error
except Exception as err: # forgive data timeout, don't delete stream except Exception as err: # forgive data timeout, don't delete stream
log.exception("Unexpected error downloading stream:") log.exception("Unexpected error downloading stream:")

View file

@ -9,7 +9,7 @@ from torba.client.basemanager import BaseWalletManager
from torba.client.wallet import ENCRYPT_ON_DISK from torba.client.wallet import ENCRYPT_ON_DISK
from torba.rpc.jsonrpc import CodeMessageError from torba.rpc.jsonrpc import CodeMessageError
from lbry.error import KeyFeeAboveMaxAllowed from lbry.error import KeyFeeAboveMaxAllowedError
from lbry.wallet.dewies import dewies_to_lbc from lbry.wallet.dewies import dewies_to_lbc
from lbry.wallet.account import Account from lbry.wallet.account import Account
from lbry.wallet.ledger import MainNetLedger from lbry.wallet.ledger import MainNetLedger
@ -199,7 +199,7 @@ class LbryWalletManager(BaseWalletManager):
error_max_fee = f"{dewies_to_lbc(max_fee_amount)} LBC" error_max_fee = f"{dewies_to_lbc(max_fee_amount)} LBC"
if max_fee['currency'] != 'LBC': if max_fee['currency'] != 'LBC':
error_max_fee += f" ({max_fee['amount']} {max_fee['currency']})" error_max_fee += f" ({max_fee['amount']} {max_fee['currency']})"
raise KeyFeeAboveMaxAllowed( raise KeyFeeAboveMaxAllowedError(
f"Purchase price of {error_fee} exceeds maximum " f"Purchase price of {error_fee} exceeds maximum "
f"configured price of {error_max_fee}." f"configured price of {error_max_fee}."
) )

View file

@ -205,12 +205,12 @@ class FileCommands(CommandTestCase):
await self.server.blob_manager.delete_blobs(all_except_sd) await self.server.blob_manager.delete_blobs(all_except_sd)
resp = await self.daemon.jsonrpc_get('lbry://foo', timeout=2, save_file=True) resp = await self.daemon.jsonrpc_get('lbry://foo', timeout=2, save_file=True)
self.assertIn('error', resp) self.assertIn('error', resp)
self.assertEqual('Failed to download data blobs for sd hash %s within timeout' % sd_hash, resp['error']) self.assertEqual('Failed to download data blobs for sd hash %s within timeout.' % sd_hash, resp['error'])
self.assertTrue(await self.daemon.jsonrpc_file_delete(claim_name='foo'), "data timeout didn't create a file") self.assertTrue(await self.daemon.jsonrpc_file_delete(claim_name='foo'), "data timeout didn't create a file")
await self.server.blob_manager.delete_blobs([sd_hash]) await self.server.blob_manager.delete_blobs([sd_hash])
resp = await self.daemon.jsonrpc_get('lbry://foo', timeout=2, save_file=True) resp = await self.daemon.jsonrpc_get('lbry://foo', timeout=2, save_file=True)
self.assertIn('error', resp) self.assertIn('error', resp)
self.assertEqual('Failed to download sd blob %s within timeout' % sd_hash, resp['error']) self.assertEqual('Failed to download sd blob %s within timeout.' % sd_hash, resp['error'])
async def wait_files_to_complete(self): async def wait_files_to_complete(self):
while await self.file_list(status='running'): while await self.file_list(status='running'):