forked from LBRYCommunity/lbry-sdk
changes from jacks review
This commit is contained in:
parent
e6fd8cc0f2
commit
3686b1d970
10 changed files with 201 additions and 1685 deletions
|
@ -1,4 +1,16 @@
|
|||
import sys
|
||||
from twisted.internet import asyncioreactor
|
||||
if 'twisted.internet.reactor' not in sys.modules:
|
||||
asyncioreactor.install()
|
||||
else:
|
||||
from twisted.internet import reactor
|
||||
if not isinstance(reactor, asyncioreactor.AsyncioSelectorReactor):
|
||||
# pyinstaller hooks install the default reactor before
|
||||
# any of our code runs, see kivy for similar problem:
|
||||
# https://github.com/kivy/kivy/issues/4182
|
||||
del sys.modules['twisted.internet.reactor']
|
||||
asyncioreactor.install()
|
||||
|
||||
import json
|
||||
import asyncio
|
||||
from aiohttp.client_exceptions import ClientConnectorError
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -73,7 +73,7 @@ class ClientProtocol(Protocol, TimeoutMixin):
|
|||
log.debug("Connection lost to %s: %s", self.peer, reason)
|
||||
self.setTimeout(None)
|
||||
self.connection_closed = True
|
||||
if reason.check(error.ConnectionDone) or reason is None:
|
||||
if reason is None or reason.check(error.ConnectionDone):
|
||||
err = failure.Failure(ConnectionClosedBeforeResponseError())
|
||||
else:
|
||||
err = reason
|
||||
|
|
|
@ -6,19 +6,7 @@ import urllib
|
|||
import json
|
||||
import textwrap
|
||||
|
||||
#import sys
|
||||
#from twisted.internet import asyncioreactor
|
||||
#if 'twisted.internet.reactor' not in sys.modules:
|
||||
# asyncioreactor.install()
|
||||
#else:
|
||||
# from twisted.internet import reactor
|
||||
# if not isinstance(reactor, asyncioreactor.AsyncioSelectorReactor):
|
||||
# # pyinstaller hooks install the default reactor before
|
||||
# # any of our code runs, see kivy for similar problem:
|
||||
# # https://github.com/kivy/kivy/issues/4182
|
||||
# del sys.modules['twisted.internet.reactor']
|
||||
# asyncioreactor.install()
|
||||
|
||||
from operator import itemgetter
|
||||
from binascii import hexlify, unhexlify
|
||||
from copy import deepcopy
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
@ -92,6 +80,7 @@ DIRECTION_ASCENDING = 'asc'
|
|||
DIRECTION_DESCENDING = 'desc'
|
||||
DIRECTIONS = DIRECTION_ASCENDING, DIRECTION_DESCENDING
|
||||
|
||||
|
||||
class IterableContainer:
|
||||
def __iter__(self):
|
||||
for attr in dir(self):
|
||||
|
@ -251,7 +240,10 @@ class Daemon(AuthJSONRPCServer):
|
|||
|
||||
@property
|
||||
def ledger(self):
|
||||
return self.wallet.default_account.ledger
|
||||
try:
|
||||
return self.wallet.default_account.ledger
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def setup(self):
|
||||
|
@ -395,51 +387,15 @@ class Daemon(AuthJSONRPCServer):
|
|||
log.exception)
|
||||
self.analytics_manager.send_claim_action('publish')
|
||||
nout = 0
|
||||
log.info("Success! Published to lbry://%s txid: %s nout: %d", name, tx.id, nout)
|
||||
defer.returnValue(self._txo_to_response(tx, nout))
|
||||
|
||||
def _txo_to_response(self, tx, nout):
|
||||
txo = tx.outputs[nout]
|
||||
return {
|
||||
log.info("Success! Published to lbry://%s txid: %s nout: %d", name, tx.id, nout)
|
||||
defer.returnValue({
|
||||
"success": True,
|
||||
"txid": tx.id,
|
||||
"nout": nout,
|
||||
"tx": hexlify(tx.raw),
|
||||
"fee": str(Decimal(tx.fee) / COIN),
|
||||
"tx": tx,
|
||||
"claim_id": txo.claim_id,
|
||||
"value": hexlify(txo.claim).decode(),
|
||||
"claim_address": self.ledger.hash160_to_address(txo.script.values['pubkey_hash'])
|
||||
}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _resolve(self, *uris, **kwargs):
|
||||
"""Resolves a URI. Can check the cache first before going out to the blockchain and stores the result.
|
||||
|
||||
Args:
|
||||
name: the lbry://<name> to resolve
|
||||
force_refresh: if True, always go out to the blockchain to resolve.
|
||||
"""
|
||||
|
||||
page = kwargs.get('page', 0)
|
||||
page_size = kwargs.get('page_size', 10)
|
||||
check_cache = kwargs.get('check_cache', False) # TODO: put caching back (was force_refresh parameter)
|
||||
results = yield self.wallet.resolve(*uris, page=page, page_size=page_size)
|
||||
self.save_claims((value for value in results.values() if 'error' not in value))
|
||||
yield defer.returnValue(results)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def save_claims(self, claim_infos):
|
||||
to_save = []
|
||||
for info in claim_infos:
|
||||
if 'value' in info:
|
||||
if info['value']:
|
||||
to_save.append(info)
|
||||
else:
|
||||
if 'certificate' in info and info['certificate']['value']:
|
||||
to_save.append(info['certificate'])
|
||||
if 'claim' in info and info['claim']['value']:
|
||||
to_save.append(info['claim'])
|
||||
yield self.storage.save_claims(to_save)
|
||||
"claim_address": self.ledger.hash160_to_address(txo.script.values['pubkey_hash']),
|
||||
"output": tx.outputs[nout]
|
||||
})
|
||||
|
||||
def _get_or_download_sd_blob(self, blob, sd_hash):
|
||||
if blob:
|
||||
|
@ -484,7 +440,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
|
||||
cost = self._get_est_cost_from_stream_size(size)
|
||||
|
||||
resolved = yield self._resolve(uri)
|
||||
resolved = yield self.wallet.resolve(uri)
|
||||
|
||||
if uri in resolved and 'claim' in resolved[uri]:
|
||||
claim = ClaimDict.load_dict(resolved[uri]['claim']['value'])
|
||||
|
@ -531,7 +487,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
Resolve a name and return the estimated stream cost
|
||||
"""
|
||||
|
||||
resolved = (yield self._resolve(uri))[uri]
|
||||
resolved = (yield self.wallet.resolve(uri))[uri]
|
||||
if resolved:
|
||||
claim_response = resolved[uri]
|
||||
else:
|
||||
|
@ -1012,7 +968,8 @@ class Daemon(AuthJSONRPCServer):
|
|||
Returns:
|
||||
(float) amount of lbry credits in wallet
|
||||
"""
|
||||
assert address is None, "Limiting by address needs to be re-implemented in new wallet."
|
||||
if address is not None:
|
||||
raise NotImplementedError("Limiting by address needs to be re-implemented in new wallet.")
|
||||
dewies = yield self.wallet.default_account.get_balance(
|
||||
0 if include_unconfirmed else 6
|
||||
)
|
||||
|
@ -1046,7 +1003,6 @@ class Daemon(AuthJSONRPCServer):
|
|||
defer.returnValue(response)
|
||||
|
||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||
@defer.inlineCallbacks
|
||||
def jsonrpc_wallet_decrypt(self):
|
||||
"""
|
||||
Decrypt an encrypted wallet, this will remove the wallet password
|
||||
|
@ -1060,13 +1016,9 @@ class Daemon(AuthJSONRPCServer):
|
|||
Returns:
|
||||
(bool) true if wallet is decrypted, otherwise false
|
||||
"""
|
||||
|
||||
result = self.wallet.decrypt_wallet()
|
||||
response = yield self._render_response(result)
|
||||
defer.returnValue(response)
|
||||
return defer.succeed(self.wallet.decrypt_wallet())
|
||||
|
||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||
@defer.inlineCallbacks
|
||||
def jsonrpc_wallet_encrypt(self, new_password):
|
||||
"""
|
||||
Encrypt a wallet with a password, if the wallet is already encrypted this will update
|
||||
|
@ -1081,13 +1033,11 @@ class Daemon(AuthJSONRPCServer):
|
|||
Returns:
|
||||
(bool) true if wallet is decrypted, otherwise false
|
||||
"""
|
||||
|
||||
self.wallet.encrypt_wallet(new_password)
|
||||
response = yield self._render_response(self.wallet.wallet.use_encryption)
|
||||
defer.returnValue(response)
|
||||
return defer.succeed(self.wallet.encrypt_wallet(new_password))
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def jsonrpc_stop(self):
|
||||
@AuthJSONRPCServer.deprecated("stop")
|
||||
def jsonrpc_daemon_stop(self):
|
||||
"""
|
||||
Stop lbrynet-daemon
|
||||
|
||||
|
@ -1100,11 +1050,24 @@ class Daemon(AuthJSONRPCServer):
|
|||
Returns:
|
||||
(string) Shutdown message
|
||||
"""
|
||||
return self.jsonrpc_stop()
|
||||
|
||||
def jsonrpc_stop(self):
|
||||
"""
|
||||
Stop lbrynet
|
||||
|
||||
Usage:
|
||||
stop
|
||||
|
||||
Options:
|
||||
None
|
||||
|
||||
Returns:
|
||||
(string) Shutdown message
|
||||
"""
|
||||
log.info("Shutting down lbrynet daemon")
|
||||
response = yield self._render_response("Shutting down")
|
||||
reactor.callLater(0.1, reactor.fireSystemEvent, "shutdown")
|
||||
defer.returnValue(response)
|
||||
defer.returnValue("Shutting down")
|
||||
|
||||
@requires(FILE_MANAGER_COMPONENT)
|
||||
@defer.inlineCallbacks
|
||||
|
@ -1198,7 +1161,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
|
||||
try:
|
||||
name = parse_lbry_uri(name).name
|
||||
metadata = yield self._resolve(name, check_cache=not force)
|
||||
metadata = yield self.wallet.resolve(name, check_cache=not force)
|
||||
if name in metadata:
|
||||
metadata = metadata[name]
|
||||
except UnknownNameError:
|
||||
|
@ -1337,7 +1300,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
except URIParseError:
|
||||
results[u] = {"error": "%s is not a valid uri" % u}
|
||||
|
||||
resolved = yield self._resolve(*valid_uris, check_cache=not force)
|
||||
resolved = yield self.wallet.resolve(*valid_uris, check_cache=not force)
|
||||
|
||||
for resolved_uri in resolved:
|
||||
results[resolved_uri] = resolved[resolved_uri]
|
||||
|
@ -1398,7 +1361,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
if parsed_uri.is_channel and not parsed_uri.path:
|
||||
raise Exception("cannot download a channel claim, specify a /path")
|
||||
|
||||
resolved_result = yield self._resolve(uri)
|
||||
resolved_result = yield self.wallet.resolve(uri)
|
||||
if resolved_result and uri in resolved_result:
|
||||
resolved = resolved_result[uri]
|
||||
else:
|
||||
|
@ -1584,13 +1547,30 @@ class Daemon(AuthJSONRPCServer):
|
|||
'claim_id' : (str) claim ID of the resulting claim
|
||||
}
|
||||
"""
|
||||
try:
|
||||
parsed = parse_lbry_uri(channel_name)
|
||||
if not parsed.is_channel:
|
||||
raise Exception("Cannot make a new channel for a non channel name")
|
||||
if parsed.path:
|
||||
raise Exception("Invalid channel uri")
|
||||
except (TypeError, URIParseError):
|
||||
raise Exception("Invalid channel name")
|
||||
if amount <= 0:
|
||||
raise Exception("Invalid amount")
|
||||
amount = int(amount * COIN)
|
||||
tx = yield self.wallet.claim_new_channel(channel_name, amount)
|
||||
self.wallet.save()
|
||||
result = self._txo_to_response(tx, 0)
|
||||
self.analytics_manager.send_new_channel()
|
||||
log.info("Claimed a new channel! Result: %s", result)
|
||||
defer.returnValue(result)
|
||||
nout = 0
|
||||
txo = tx.outputs[nout]
|
||||
log.info("Claimed a new channel! lbry://%s txid: %s nout: %d", channel_name, tx.id, nout)
|
||||
defer.returnValue({
|
||||
"success": True,
|
||||
"tx": tx,
|
||||
"claim_id": txo.claim_id,
|
||||
"claim_address": self.ledger.hash160_to_address(txo.script.values['pubkey_hash']),
|
||||
"output": txo
|
||||
})
|
||||
|
||||
@requires(WALLET_COMPONENT)
|
||||
@defer.inlineCallbacks
|
||||
|
@ -1764,6 +1744,11 @@ class Daemon(AuthJSONRPCServer):
|
|||
|
||||
bid = int(bid * COIN)
|
||||
|
||||
for address in [claim_address, change_address]:
|
||||
if address is not None:
|
||||
# raises an error if the address is invalid
|
||||
decode_address(address)
|
||||
|
||||
available = yield self.wallet.default_account.get_balance()
|
||||
if bid >= available:
|
||||
# TODO: add check for existing claim balance
|
||||
|
@ -1880,8 +1865,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
|
||||
result = yield self._publish_stream(name, bid, claim_dict, file_path, certificate,
|
||||
claim_address, change_address)
|
||||
response = yield self._render_response(result)
|
||||
defer.returnValue(response)
|
||||
defer.returnValue(result)
|
||||
|
||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||
@defer.inlineCallbacks
|
||||
|
@ -2179,7 +2163,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
except URIParseError:
|
||||
results[chan_uri] = {"error": "%s is not a valid uri" % chan_uri}
|
||||
|
||||
resolved = yield self._resolve(*valid_uris, page=page, page_size=page_size)
|
||||
resolved = yield self.wallet.resolve(*valid_uris, page=page, page_size=page_size)
|
||||
for u in resolved:
|
||||
if 'error' in resolved[u]:
|
||||
results[u] = resolved[u]
|
||||
|
@ -2384,6 +2368,32 @@ class Daemon(AuthJSONRPCServer):
|
|||
d.addCallback(lambda address: self._render_response(address))
|
||||
return d
|
||||
|
||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||
@AuthJSONRPCServer.deprecated("wallet_send")
|
||||
@defer.inlineCallbacks
|
||||
def jsonrpc_send_amount_to_address(self, amount, address):
|
||||
"""
|
||||
Queue a payment of credits to an address
|
||||
Usage:
|
||||
send_amount_to_address (<amount> | --amount=<amount>) (<address> | --address=<address>)
|
||||
Options:
|
||||
--amount=<amount> : (float) amount to send
|
||||
--address=<address> : (str) address to send credits to
|
||||
Returns:
|
||||
(bool) true if payment successfully scheduled
|
||||
"""
|
||||
if amount < 0:
|
||||
raise NegativeFundsError()
|
||||
elif not amount:
|
||||
raise NullFundsError()
|
||||
|
||||
reserved_points = self.wallet.reserve_points(address, amount)
|
||||
if reserved_points is None:
|
||||
raise InsufficientFundsError()
|
||||
yield self.wallet.send_points_to_address(reserved_points, amount)
|
||||
self.analytics_manager.send_credits_sent()
|
||||
defer.returnValue(True)
|
||||
|
||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||
@defer.inlineCallbacks
|
||||
def jsonrpc_wallet_send(self, amount, address=None, claim_id=None):
|
||||
|
@ -2749,7 +2759,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
"""
|
||||
if uri or stream_hash or sd_hash:
|
||||
if uri:
|
||||
metadata = (yield self._resolve(uri))[uri]
|
||||
metadata = (yield self.wallet.resolve(uri))[uri]
|
||||
sd_hash = utils.get_sd_hash(metadata)
|
||||
stream_hash = yield self.storage.get_stream_hash_for_sd_hash(sd_hash)
|
||||
elif stream_hash:
|
||||
|
@ -2898,7 +2908,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
hosts = {}
|
||||
|
||||
for k, v in data_store.items():
|
||||
for contact, _ in v:
|
||||
for contact in map(itemgetter(0), v):
|
||||
hosts.setdefault(contact, []).append(hexlify(k).decode())
|
||||
|
||||
contact_set = set()
|
||||
|
@ -2907,7 +2917,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
|
||||
for i in range(len(self.dht_node._routingTable._buckets)):
|
||||
for contact in self.dht_node._routingTable._buckets[i]._contacts:
|
||||
blobs = [hexlify(raw_hash).decode() for raw_hash in hosts.pop(contact)] if contact in hosts else []
|
||||
blobs = list(hosts.pop(contact)) if contact in hosts else []
|
||||
blob_hashes.update(blobs)
|
||||
host = {
|
||||
"address": contact.address,
|
||||
|
@ -2949,6 +2959,24 @@ class Daemon(AuthJSONRPCServer):
|
|||
|
||||
return self._blob_availability(blob_hash, search_timeout, blob_timeout)
|
||||
|
||||
@requires(UPNP_COMPONENT, WALLET_COMPONENT, DHT_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||
@AuthJSONRPCServer.deprecated("stream_availability")
|
||||
def jsonrpc_get_availability(self, uri, sd_timeout=None, peer_timeout=None):
|
||||
"""
|
||||
Get stream availability for lbry uri
|
||||
Usage:
|
||||
get_availability (<uri> | --uri=<uri>) [<sd_timeout> | --sd_timeout=<sd_timeout>]
|
||||
[<peer_timeout> | --peer_timeout=<peer_timeout>]
|
||||
Options:
|
||||
--uri=<uri> : (str) check availability for this uri
|
||||
--sd_timeout=<sd_timeout> : (int) sd blob download timeout
|
||||
--peer_timeout=<peer_timeout> : (int) how long to look for peers
|
||||
Returns:
|
||||
(float) Peers per blob / total blobs
|
||||
"""
|
||||
|
||||
return self.jsonrpc_stream_availability(uri, peer_timeout, sd_timeout)
|
||||
|
||||
@requires(UPNP_COMPONENT, WALLET_COMPONENT, DHT_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||
@defer.inlineCallbacks
|
||||
def jsonrpc_stream_availability(self, uri, search_timeout=None, blob_timeout=None):
|
||||
|
@ -3002,7 +3030,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
}
|
||||
|
||||
try:
|
||||
resolved_result = (yield self._resolve(uri))[uri]
|
||||
resolved_result = (yield self.wallet.resolve(uri))[uri]
|
||||
response['did_resolve'] = True
|
||||
except UnknownNameError:
|
||||
response['error'] = "Failed to resolve name"
|
||||
|
@ -3229,10 +3257,9 @@ class Daemon(AuthJSONRPCServer):
|
|||
everything=False, outputs=1, broadcast=False):
|
||||
"""
|
||||
Transfer some amount (or --everything) to an account from another
|
||||
account (can be the same account). Decimal amounts are interpreted
|
||||
as LBC and non-decimal amounts are interpreted as dewies. You can
|
||||
also spread the transfer across a number of --outputs (cannot be
|
||||
used together with --everything).
|
||||
account (can be the same account). Amounts are interpreted as LBC.
|
||||
You can also spread the transfer across a number of --outputs (cannot
|
||||
be used together with --everything).
|
||||
|
||||
Usage:
|
||||
fund (<to_account> | --to_account=<to_account>)
|
||||
|
@ -3244,7 +3271,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
Options:
|
||||
--to_account=<to_account> : (str) send to this account
|
||||
--from_account=<from_account> : (str) spend from this account
|
||||
--amount=<amount> : (str) the amount to transfer (lbc or dewies)
|
||||
--amount=<amount> : (str) the amount to transfer lbc
|
||||
--everything : (bool) transfer everything (excluding claims), default: false.
|
||||
--outputs=<outputs> : (int) split payment across many outputs, default: 1.
|
||||
--broadcast : (bool) actually broadcast the transaction, default: false.
|
||||
|
@ -3263,25 +3290,7 @@ class Daemon(AuthJSONRPCServer):
|
|||
return from_account.fund(
|
||||
to_account=to_account, amount=amount, everything=everything,
|
||||
outputs=outputs, broadcast=broadcast
|
||||
).addCallback(lambda tx: self.tx_to_json(tx, from_account.ledger))
|
||||
|
||||
@staticmethod
|
||||
def tx_to_json(tx, ledger):
|
||||
return {
|
||||
'txid': tx.id,
|
||||
'inputs': [
|
||||
{'amount': txi.amount, 'address': txi.txo_ref.txo.get_address(ledger)}
|
||||
for txi in tx.inputs
|
||||
],
|
||||
'outputs': [
|
||||
{'amount': txo.amount, 'address': txo.get_address(ledger)}
|
||||
for txo in tx.outputs
|
||||
],
|
||||
'total_input': tx.input_sum,
|
||||
'total_output': tx.input_sum,
|
||||
'total_fee': tx.fee,
|
||||
'xhex': hexlify(tx.raw).decode(),
|
||||
}
|
||||
)
|
||||
|
||||
def get_account_or_error(self, argument: str, account_name: str, lbc_only=False):
|
||||
for account in self.wallet.default_wallet.accounts:
|
||||
|
@ -3306,9 +3315,9 @@ class Daemon(AuthJSONRPCServer):
|
|||
if '.' in amount:
|
||||
return int(Decimal(amount) * COIN)
|
||||
elif amount.isdigit():
|
||||
return int(amount)
|
||||
elif isinstance(amount, int):
|
||||
return amount
|
||||
amount = int(amount)
|
||||
if isinstance(amount, int):
|
||||
return amount * COIN
|
||||
raise ValueError("Invalid value for '{}' argument: {}".format(argument, amount))
|
||||
|
||||
|
||||
|
|
|
@ -1,225 +0,0 @@
|
|||
# pylint: skip-file
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import colorama
|
||||
from docopt import docopt
|
||||
from collections import OrderedDict
|
||||
from lbrynet import conf
|
||||
from lbrynet.core import utils
|
||||
from lbrynet.daemon.auth.client import JSONRPCException, LBRYAPIClient, AuthAPIClient
|
||||
from lbrynet.daemon.Daemon import Daemon
|
||||
from lbrynet.core.system_info import get_platform
|
||||
from jsonrpc.common import RPCError
|
||||
from requests.exceptions import ConnectionError
|
||||
from urllib2 import URLError, HTTPError
|
||||
from httplib import UNAUTHORIZED
|
||||
|
||||
|
||||
def remove_brackets(key):
|
||||
if key.startswith("<") and key.endswith(">"):
|
||||
return str(key[1:-1])
|
||||
return key
|
||||
|
||||
|
||||
def set_kwargs(parsed_args):
|
||||
kwargs = OrderedDict()
|
||||
for key, arg in parsed_args.iteritems():
|
||||
if arg is None:
|
||||
continue
|
||||
elif key.startswith("--") and remove_brackets(key[2:]) not in kwargs:
|
||||
k = remove_brackets(key[2:])
|
||||
elif remove_brackets(key) not in kwargs:
|
||||
k = remove_brackets(key)
|
||||
kwargs[k] = guess_type(arg, k)
|
||||
return kwargs
|
||||
|
||||
|
||||
def main():
|
||||
argv = sys.argv[1:]
|
||||
|
||||
# check if a config file has been specified. If so, shift
|
||||
# all the arguments so that the parsing can continue without
|
||||
# noticing
|
||||
if len(argv) and argv[0] == "--conf":
|
||||
if len(argv) < 2:
|
||||
print_error("No config file specified for --conf option")
|
||||
print_help()
|
||||
return
|
||||
|
||||
conf.conf_file = argv[1]
|
||||
argv = argv[2:]
|
||||
|
||||
if len(argv):
|
||||
method, args = argv[0], argv[1:]
|
||||
else:
|
||||
print_help()
|
||||
return
|
||||
|
||||
if method in ['help', '--help', '-h']:
|
||||
if len(args) == 1:
|
||||
print_help_for_command(args[0])
|
||||
else:
|
||||
print_help()
|
||||
return
|
||||
|
||||
elif method in ['version', '--version']:
|
||||
print(utils.json_dumps_pretty(get_platform(get_ip=False)))
|
||||
return
|
||||
|
||||
if method not in Daemon.callable_methods:
|
||||
if method not in Daemon.deprecated_methods:
|
||||
print_error("\"%s\" is not a valid command." % method)
|
||||
return
|
||||
new_method = Daemon.deprecated_methods[method].new_command
|
||||
print_error("\"%s\" is deprecated, using \"%s\"." % (method, new_method))
|
||||
method = new_method
|
||||
|
||||
fn = Daemon.callable_methods[method]
|
||||
|
||||
parsed = docopt(fn.__doc__, args)
|
||||
kwargs = set_kwargs(parsed)
|
||||
colorama.init()
|
||||
conf.initialize_settings()
|
||||
|
||||
try:
|
||||
api = LBRYAPIClient.get_client()
|
||||
api.status()
|
||||
except (URLError, ConnectionError) as err:
|
||||
if isinstance(err, HTTPError) and err.code == UNAUTHORIZED:
|
||||
api = AuthAPIClient.config()
|
||||
# this can happen if the daemon is using auth with the --http-auth flag
|
||||
# when the config setting is to not use it
|
||||
try:
|
||||
api.status()
|
||||
except:
|
||||
print_error("Daemon requires authentication, but none was provided.",
|
||||
suggest_help=False)
|
||||
return 1
|
||||
else:
|
||||
print_error("Could not connect to daemon. Are you sure it's running?",
|
||||
suggest_help=False)
|
||||
return 1
|
||||
|
||||
# TODO: check if port is bound. Error if its not
|
||||
|
||||
try:
|
||||
result = api.call(method, kwargs)
|
||||
if isinstance(result, basestring):
|
||||
# printing the undumped string is prettier
|
||||
print(result)
|
||||
else:
|
||||
print(utils.json_dumps_pretty(result))
|
||||
except (RPCError, KeyError, JSONRPCException, HTTPError) as err:
|
||||
if isinstance(err, HTTPError):
|
||||
error_body = err.read()
|
||||
try:
|
||||
error_data = json.loads(error_body)
|
||||
except ValueError:
|
||||
print(
|
||||
"There was an error, and the response was not valid JSON.\n" +
|
||||
"Raw JSONRPC response:\n" + error_body
|
||||
)
|
||||
return 1
|
||||
|
||||
print_error(error_data['error']['message'] + "\n", suggest_help=False)
|
||||
|
||||
if 'data' in error_data['error'] and 'traceback' in error_data['error']['data']:
|
||||
print("Here's the traceback for the error you encountered:")
|
||||
print("\n".join(error_data['error']['data']['traceback']))
|
||||
|
||||
print_help_for_command(method)
|
||||
elif isinstance(err, RPCError):
|
||||
print_error(err.msg, suggest_help=False)
|
||||
# print_help_for_command(method)
|
||||
else:
|
||||
print_error("Something went wrong\n", suggest_help=False)
|
||||
print(str(err))
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
def guess_type(x, key=None):
|
||||
if not isinstance(x, (unicode, str)):
|
||||
return x
|
||||
if key in ('uri', 'channel_name', 'name', 'file_name', 'download_directory'):
|
||||
return x
|
||||
if x in ('true', 'True', 'TRUE'):
|
||||
return True
|
||||
if x in ('false', 'False', 'FALSE'):
|
||||
return False
|
||||
if '.' in x:
|
||||
try:
|
||||
return float(x)
|
||||
except ValueError:
|
||||
# not a float
|
||||
pass
|
||||
try:
|
||||
return int(x)
|
||||
except ValueError:
|
||||
return x
|
||||
|
||||
|
||||
def print_help_suggestion():
|
||||
print("See `{} help` for more information.".format(os.path.basename(sys.argv[0])))
|
||||
|
||||
|
||||
def print_error(message, suggest_help=True):
|
||||
error_style = colorama.Style.BRIGHT + colorama.Fore.RED
|
||||
print(error_style + "ERROR: " + message + colorama.Style.RESET_ALL)
|
||||
if suggest_help:
|
||||
print_help_suggestion()
|
||||
|
||||
|
||||
def print_help():
|
||||
print("\n".join([
|
||||
"NAME",
|
||||
" lbrynet-cli - LBRY command line client.",
|
||||
"",
|
||||
"USAGE",
|
||||
" lbrynet-cli [--conf <config file>] <command> [<args>]",
|
||||
"",
|
||||
"EXAMPLES",
|
||||
" lbrynet-cli commands # list available commands",
|
||||
" lbrynet-cli status # get daemon status",
|
||||
" lbrynet-cli --conf ~/l1.conf status # like above but using ~/l1.conf as config file",
|
||||
" lbrynet-cli resolve_name what # resolve a name",
|
||||
" lbrynet-cli help resolve_name # get help for a command",
|
||||
]))
|
||||
|
||||
|
||||
def print_help_for_command(command):
|
||||
fn = Daemon.callable_methods.get(command)
|
||||
if fn:
|
||||
print("Help for %s method:\n%s" % (command, fn.__doc__))
|
||||
|
||||
|
||||
def wrap_list_to_term_width(l, width=None, separator=', ', prefix=''):
|
||||
if width is None:
|
||||
try:
|
||||
_, width = os.popen('stty size', 'r').read().split()
|
||||
width = int(width)
|
||||
except:
|
||||
pass
|
||||
if not width:
|
||||
width = 80
|
||||
|
||||
lines = []
|
||||
curr_line = ''
|
||||
for item in l:
|
||||
new_line = curr_line + item + separator
|
||||
if len(new_line) + len(prefix) > width:
|
||||
lines.append(curr_line)
|
||||
curr_line = item + separator
|
||||
else:
|
||||
curr_line = new_line
|
||||
lines.append(curr_line)
|
||||
|
||||
ret = prefix + ("\n" + prefix).join(lines)
|
||||
if ret.endswith(separator):
|
||||
ret = ret[:-len(separator)]
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
|
@ -64,15 +64,6 @@ def start(argv=None, conf_path=None):
|
|||
log_support.configure_loggly_handler()
|
||||
log.debug('Final Settings: %s', conf.settings.get_current_settings_dict())
|
||||
|
||||
# fixme: fix that, JSONRPCProxy is gone on py3
|
||||
#try:
|
||||
# log.debug('Checking for an existing lbrynet daemon instance')
|
||||
# JSONRPCProxy.from_url(conf.settings.get_api_connection_string()).status()
|
||||
# log.info("lbrynet-daemon is already running")
|
||||
# return
|
||||
#except Exception:
|
||||
# log.debug('No lbrynet instance found, continuing to start')
|
||||
|
||||
log.info("Starting lbrynet-daemon from command line")
|
||||
|
||||
if test_internet_connection():
|
||||
|
|
|
@ -22,6 +22,7 @@ from lbrynet.daemon.ComponentManager import ComponentManager
|
|||
from .util import APIKey, get_auth_message, LBRY_SECRET
|
||||
from .undecorated import undecorated
|
||||
from .factory import AuthJSONRPCResource
|
||||
from lbrynet.daemon.json_response_encoder import JSONResponseEncoder
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
EMPTY_PARAMS = [{}]
|
||||
|
@ -85,11 +86,6 @@ class JSONRPCError:
|
|||
return cls(message, code=code, traceback=traceback)
|
||||
|
||||
|
||||
def default_decimal(obj):
|
||||
if isinstance(obj, Decimal):
|
||||
return float(obj)
|
||||
|
||||
|
||||
class UnknownAPIMethodError(Exception):
|
||||
pass
|
||||
|
||||
|
@ -109,7 +105,7 @@ def jsonrpc_dumps_pretty(obj, **kwargs):
|
|||
else:
|
||||
data = {"jsonrpc": "2.0", "result": obj, "id": id_}
|
||||
|
||||
return json.dumps(data, cls=jsonrpclib.JSONRPCEncoder, sort_keys=True, indent=2, **kwargs) + "\n"
|
||||
return json.dumps(data, cls=JSONResponseEncoder, sort_keys=True, indent=2, **kwargs) + "\n"
|
||||
|
||||
|
||||
class JSONRPCServerType(type):
|
||||
|
@ -314,7 +310,7 @@ class AuthJSONRPCServer(AuthorizedBase):
|
|||
# last resort, just cast it as a string
|
||||
error = JSONRPCError(str(failure))
|
||||
|
||||
response_content = jsonrpc_dumps_pretty(error, id=id_)
|
||||
response_content = jsonrpc_dumps_pretty(error, id=id_, ledger=self.ledger)
|
||||
self._set_headers(request, response_content)
|
||||
request.setResponseCode(200)
|
||||
self._render_message(request, response_content)
|
||||
|
@ -575,7 +571,7 @@ class AuthJSONRPCServer(AuthorizedBase):
|
|||
|
||||
def _callback_render(self, result, request, id_, auth_required=False):
|
||||
try:
|
||||
message = jsonrpc_dumps_pretty(result, id=id_, default=default_decimal)
|
||||
message = jsonrpc_dumps_pretty(result, id=id_, ledger=self.ledger)
|
||||
request.setResponseCode(200)
|
||||
self._set_headers(request, message, auth_required)
|
||||
self._render_message(request, message)
|
||||
|
|
44
lbrynet/daemon/json_response_encoder.py
Normal file
44
lbrynet/daemon/json_response_encoder.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
from decimal import Decimal
|
||||
from binascii import hexlify
|
||||
from datetime import datetime
|
||||
from json import JSONEncoder
|
||||
from wallet.transaction import Transaction, Output
|
||||
|
||||
|
||||
class JSONResponseEncoder(JSONEncoder):
|
||||
|
||||
def __init__(self, *args, ledger, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.ledger = ledger
|
||||
|
||||
def default(self, obj):
|
||||
if isinstance(obj, Transaction):
|
||||
return self.encode_transaction(obj)
|
||||
if isinstance(obj, Output):
|
||||
return self.encode_output(obj)
|
||||
if isinstance(obj, datetime):
|
||||
return obj.strftime("%Y%m%dT%H:%M:%S")
|
||||
if isinstance(obj, Decimal):
|
||||
return float(obj)
|
||||
return super().default(obj)
|
||||
|
||||
def encode_transaction(self, tx):
|
||||
return {
|
||||
'txid': tx.id,
|
||||
'inputs': [self.encode_input(txo) for txo in tx.inputs],
|
||||
'outputs': [self.encode_output(txo) for txo in tx.outputs],
|
||||
'total_input': tx.input_sum,
|
||||
'total_output': tx.input_sum - tx.fee,
|
||||
'total_fee': tx.fee,
|
||||
'hex': hexlify(tx.raw).decode(),
|
||||
}
|
||||
|
||||
def encode_output(self, txo):
|
||||
return {
|
||||
'nout': txo.position,
|
||||
'amount': txo.amount,
|
||||
'address': txo.get_address(self.ledger)
|
||||
}
|
||||
|
||||
def encode_input(self, txi):
|
||||
return self.encode_output(txi.txo_ref.txo)
|
|
@ -656,6 +656,19 @@ class SQLiteStorage:
|
|||
if support_dl:
|
||||
yield defer.DeferredList(support_dl)
|
||||
|
||||
def save_claims_for_resolve(self, claim_infos):
|
||||
to_save = []
|
||||
for info in claim_infos:
|
||||
if 'value' in info:
|
||||
if info['value']:
|
||||
to_save.append(info)
|
||||
else:
|
||||
if 'certificate' in info and info['certificate']['value']:
|
||||
to_save.append(info['certificate'])
|
||||
if 'claim' in info and info['claim']['value']:
|
||||
to_save.append(info['claim'])
|
||||
return self.save_claims(to_save)
|
||||
|
||||
def get_old_stream_hashes_for_claim_id(self, claim_id, new_stream_hash):
|
||||
return self.run_and_return_list(
|
||||
"select f.stream_hash from file f "
|
||||
|
|
|
@ -147,11 +147,16 @@ class LbryWalletManager(BaseWalletManager):
|
|||
def get_info_exchanger(self):
|
||||
return LBRYcrdAddressRequester(self)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def resolve(self, *uris, **kwargs):
|
||||
page = kwargs.get('page', 0)
|
||||
page_size = kwargs.get('page_size', 10)
|
||||
check_cache = kwargs.get('check_cache', False) # TODO: put caching back (was force_refresh parameter)
|
||||
ledger = self.default_account.ledger # type: MainNetLedger
|
||||
return ledger.resolve(page, page_size, *uris)
|
||||
results = ledger.resolve(page, page_size, *uris)
|
||||
yield self.old_db.save_claims_for_resolve(
|
||||
(value for value in results.values() if 'error' not in value))
|
||||
defer.returnValue(results)
|
||||
|
||||
def get_name_claims(self):
|
||||
return defer.succeed([])
|
||||
|
@ -214,16 +219,6 @@ class LbryWalletManager(BaseWalletManager):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def claim_new_channel(self, channel_name, amount):
|
||||
try:
|
||||
parsed = parse_lbry_uri(channel_name)
|
||||
if not parsed.is_channel:
|
||||
raise Exception("Cannot make a new channel for a non channel name")
|
||||
if parsed.path:
|
||||
raise Exception("Invalid channel uri")
|
||||
except (TypeError, URIParseError):
|
||||
raise Exception("Invalid channel name")
|
||||
if amount <= 0:
|
||||
raise Exception("Invalid amount")
|
||||
account = self.default_account
|
||||
address = yield account.receiving.get_or_create_usable_address()
|
||||
cert, key = generate_certificate()
|
||||
|
|
Loading…
Reference in a new issue