update lbrynet api and tests

This commit is contained in:
Jack Robison 2017-04-06 20:45:05 -04:00
parent ccc94a0db9
commit e9cfbea75f
5 changed files with 139 additions and 61 deletions

View file

@ -135,7 +135,7 @@ class EncryptedFileManager(object):
rowid, stream_hash, payment_rate_manager, blob_data_rate=options) rowid, stream_hash, payment_rate_manager, blob_data_rate=options)
yield downloader.restore() yield downloader.restore()
except Exception: except Exception:
log.exception('An error occurred while starting a lbry file (%s, %s, %s)', log.error('An error occurred while starting a lbry file (%s, %s, %s)',
rowid, stream_hash, options) rowid, stream_hash, options)
@defer.inlineCallbacks @defer.inlineCallbacks

View file

@ -12,15 +12,10 @@ from requests import exceptions as requests_exceptions
import random import random
from twisted.web import server from twisted.web import server
from twisted.internet import defer, threads, error, reactor, task from twisted.internet import defer, threads, error, reactor
from twisted.internet.task import LoopingCall from twisted.internet.task import LoopingCall
from twisted.python.failure import Failure from twisted.python.failure import Failure
from lbryschema.decode import smart_decode
from lbryschema.claim import ClaimDict
from lbryschema.uri import parse_lbry_uri
from lbryschema.error import DecodeError
# TODO: importing this when internet is disabled raises a socket.gaierror # TODO: importing this when internet is disabled raises a socket.gaierror
from lbryum.version import LBRYUM_VERSION from lbryum.version import LBRYUM_VERSION
from lbrynet import __version__ as LBRYNET_VERSION from lbrynet import __version__ as LBRYNET_VERSION
@ -30,7 +25,7 @@ from lbrynet.reflector import reupload
from lbrynet.reflector import ServerFactory as reflector_server_factory from lbrynet.reflector import ServerFactory as reflector_server_factory
from lbrynet.metadata.Fee import FeeValidator from lbrynet.metadata.Fee import FeeValidator
from lbrynet.metadata.Metadata import verify_name_characters from lbrynet.metadata.Metadata import verify_name_characters
from lbryschema.decode import smart_decode
from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileSaverFactory from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileSaverFactory
from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileOpenerFactory from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileOpenerFactory
from lbrynet.lbryfile.client.EncryptedFileOptions import add_lbry_file_to_sd_identifier from lbrynet.lbryfile.client.EncryptedFileOptions import add_lbry_file_to_sd_identifier
@ -737,9 +732,10 @@ class Daemon(AuthJSONRPCServer):
defer.returnValue(result) defer.returnValue(result)
@defer.inlineCallbacks @defer.inlineCallbacks
def _publish_stream(self, name, bid, claim_dict, file_path=None): def _publish_stream(self, name, bid, claim_dict, file_path=None, certificate_id=None):
publisher = Publisher(self.session, self.lbry_file_manager, self.session.wallet) publisher = Publisher(self.session, self.lbry_file_manager, self.session.wallet,
certificate_id)
verify_name_characters(name) verify_name_characters(name)
if bid <= 0.0: if bid <= 0.0:
raise Exception("Invalid bid") raise Exception("Invalid bid")
@ -916,7 +912,7 @@ class Daemon(AuthJSONRPCServer):
lbry_file.txid, lbry_file.txid,
lbry_file.nout) lbry_file.nout)
try: try:
metadata = smart_decode(claim['value']).claim_dict metadata = claim['value']
except: except:
metadata = None metadata = None
try: try:
@ -972,6 +968,7 @@ class Daemon(AuthJSONRPCServer):
lbry_file_dict = yield self._get_lbry_file_dict(lbry_file, full_status=full_status) lbry_file_dict = yield self._get_lbry_file_dict(lbry_file, full_status=full_status)
file_dicts.append(lbry_file_dict) file_dicts.append(lbry_file_dict)
lbry_files = file_dicts lbry_files = file_dicts
log.info("Collected %i lbry files", len(lbry_files))
defer.returnValue(lbry_files) defer.returnValue(lbry_files)
# TODO: do this and get_blobs_for_sd_hash in the stream info manager # TODO: do this and get_blobs_for_sd_hash in the stream info manager
@ -1363,10 +1360,6 @@ class Daemon(AuthJSONRPCServer):
resolvable resolvable
""" """
if not name:
# TODO: seems like we should raise an error here
defer.returnValue(None)
try: try:
metadata = yield self._resolve_name(name, force_refresh=force) metadata = yield self._resolve_name(name, force_refresh=force)
except UnknownNameError: except UnknownNameError:
@ -1412,6 +1405,31 @@ class Daemon(AuthJSONRPCServer):
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
def jsonrpc_resolve(self, uri):
"""
Resolve a LBRY URI
Args:
'uri': (str) uri to download
Returns:
{
'claim_id': (str) claim id,
'claim_sequence': (int) claim sequence number,
'decoded_claim': (bool) whether or not the claim value was decoded,
'depth': (int) claim depth,
'has_signature': (bool) included if decoded_claim
'name': (str) claim name,
'txid': (str) claim txid,
'nout': (str) claim nout,
'signature_is_valid': (bool), included if has_signature,
'value': ClaimDict if decoded, otherwise hex string
}
"""
resolved = yield self.session.wallet.resolve_uri(uri)
results = yield self._render_response(resolved)
defer.returnValue(results)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
def jsonrpc_get(self, uri, file_name=None, timeout=None, download_directory=None): def jsonrpc_get(self, uri, file_name=None, timeout=None, download_directory=None):
@ -1536,7 +1554,7 @@ class Daemon(AuthJSONRPCServer):
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
def jsonrpc_file_delete(self, delete_target_file=True, **kwargs): def jsonrpc_file_delete(self, delete_target_file=True, delete_all=False, **kwargs):
""" """
Delete a lbry file Delete a lbry file
@ -1556,21 +1574,27 @@ class Daemon(AuthJSONRPCServer):
""" """
lbry_files = yield self._get_lbry_files(return_json=False, **kwargs) lbry_files = yield self._get_lbry_files(return_json=False, **kwargs)
if len(lbry_files) > 1: if len(lbry_files) > 1:
log.warning("There are %i files to delete, use narrower filters to select one", if not delete_all:
len(lbry_files)) log.warning("There are %i files to delete, use narrower filters to select one",
result = False len(lbry_files))
elif not lbry_files: result = False
else:
log.warning("Deleting %i files",
len(lbry_files))
if not lbry_files:
log.warning("There is no file to delete") log.warning("There is no file to delete")
result = False result = False
else: else:
lbry_file = lbry_files[0] for lbry_file in lbry_files:
file_name, stream_hash = lbry_file.file_name, lbry_file.stream_hash file_name, stream_hash = lbry_file.file_name, lbry_file.stream_hash
if lbry_file.claim_id in self.streams: if lbry_file.claim_id in self.streams:
del self.streams[lbry_file.claim_id] del self.streams[lbry_file.claim_id]
yield self.lbry_file_manager.delete_lbry_file(lbry_file, yield self.lbry_file_manager.delete_lbry_file(lbry_file,
delete_file=delete_target_file) delete_file=delete_target_file)
log.info("Deleted %s (%s)", file_name, utils.short_hash(stream_hash)) log.info("Deleted %s (%s)", file_name, utils.short_hash(stream_hash))
result = True result = True
response = yield self._render_response(result) response = yield self._render_response(result)
defer.returnValue(response) defer.returnValue(response)
@ -1596,11 +1620,51 @@ class Daemon(AuthJSONRPCServer):
cost = yield self.get_est_cost(name, size) cost = yield self.get_est_cost(name, size)
defer.returnValue(cost) defer.returnValue(cost)
@AuthJSONRPCServer.auth_required
@defer.inlineCallbacks
def jsonrpc_channel_new(self, channel_name, amount):
"""
Generate a publisher key and create a new certificate claim
Args:
'name': (str) '@' prefixed name
'amount': (float) amount to claim name
Returns:
(dict) Dictionary containing result of the claim
{
'tx' : (str) hex encoded transaction
'txid' : (str) txid of resulting claim
'nout' : (int) nout of the resulting claim
'fee' : (float) fee paid for the claim transaction
'claim_id' : (str) claim ID of the resulting claim
}
"""
result = yield self.session.wallet.claim_new_channel(channel_name, amount)
response = yield self._render_response(result)
defer.returnValue(response)
@AuthJSONRPCServer.auth_required
@defer.inlineCallbacks
def jsonrpc_channel_list_mine(self):
"""
Get my channels
Returns:
(list) ClaimDict
"""
result = yield self.session.wallet.channel_list()
response = yield self._render_response(result)
defer.returnValue(response)
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
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):
""" """
Make a new name claim and publish associated data to lbrynet, Make a new name claim and publish associated data to lbrynet,
update over existing claim if user already has a claim for name. update over existing claim if user already has a claim for name.
@ -1640,6 +1704,7 @@ class Daemon(AuthJSONRPCServer):
'preview'(optional): (str) preview URL for the file 'preview'(optional): (str) preview URL for the file
'nsfw'(optional): (bool) True if not safe for work 'nsfw'(optional): (bool) True if not safe for work
'sources'(optional): (dict){'lbry_sd_hash':sd_hash} specifies sd hash of file 'sources'(optional): (dict){'lbry_sd_hash':sd_hash} specifies sd hash of file
'channel_name' (optional): (str) name of the publisher channel
Returns: Returns:
(dict) Dictionary containing result of the claim (dict) Dictionary containing result of the claim
@ -1690,10 +1755,11 @@ class Daemon(AuthJSONRPCServer):
else: else:
address = fee_dict['address'] address = fee_dict['address']
new_fee_dict = { new_fee_dict = {
'version':'_0_0_1', 'version': '_0_0_1',
'currency': currency, 'currency': currency,
'address':address, 'address': address,
'amount':fee_dict['amount']} 'amount': fee_dict['amount']
}
metadata['fee'] = new_fee_dict metadata['fee'] = new_fee_dict
log.info("Publish: %s", { log.info("Publish: %s", {
@ -1705,14 +1771,30 @@ class Daemon(AuthJSONRPCServer):
}) })
claim_dict = { claim_dict = {
'version':'_0_0_1', 'version': '_0_0_1',
'claimType':'streamType', 'claimType': 'streamType',
'stream':{'metadata':metadata, 'version':'_0_0_1'}} 'stream': {
'metadata': metadata,
'version': '_0_0_1'
}
}
if sources is not None: if sources is not None:
claim_dict['stream']['source'] = sources claim_dict['stream']['source'] = sources
result = yield self._publish_stream(name, bid, claim_dict, file_path) if channel_name:
certificate_id = None
my_certificates = yield self.session.wallet.channel_list()
for certificate in my_certificates:
if channel_name == certificate['name']:
certificate_id = certificate['claim_id']
break
if not certificate_id:
raise Exception("Cannot publish using channel %s" % channel_name)
else:
certificate_id = None
result = yield self._publish_stream(name, bid, claim_dict, file_path, certificate_id)
response = yield self._render_response(result) response = yield self._render_response(result)
defer.returnValue(response) defer.returnValue(response)
@ -1725,13 +1807,12 @@ class Daemon(AuthJSONRPCServer):
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
def jsonrpc_claim_abandon(self, txid, nout): def jsonrpc_claim_abandon(self, claim_id):
""" """
Abandon a name and reclaim credits from the claim Abandon a name and reclaim credits from the claim
Args: Args:
'txid': (str) txid of claim 'claim_id': (str) claim_id of claim
'nout': (int) nout of claim
Return: Return:
(dict) Dictionary containing result of the claim (dict) Dictionary containing result of the claim
{ {
@ -1741,7 +1822,7 @@ class Daemon(AuthJSONRPCServer):
""" """
try: try:
abandon_claim_tx = yield self.session.wallet.abandon_claim(txid, nout) abandon_claim_tx = yield self.session.wallet.abandon_claim(claim_id)
response = yield self._render_response(abandon_claim_tx) response = yield self._render_response(abandon_claim_tx)
except BaseException as err: except BaseException as err:
log.warning(err) log.warning(err)
@ -1861,6 +1942,7 @@ class Daemon(AuthJSONRPCServer):
""" """
return self.jsonrpc_claim_list(**kwargs) return self.jsonrpc_claim_list(**kwargs)
@defer.inlineCallbacks
def jsonrpc_claim_list(self, name): def jsonrpc_claim_list(self, name):
""" """
Get claims for a name Get claims for a name
@ -1889,10 +1971,8 @@ class Daemon(AuthJSONRPCServer):
} }
""" """
d = self.session.wallet.get_claims_for_name(name) claims = yield self.session.wallet.get_claims_for_name(name)
d.addCallback(format_json_out_amount_as_float) defer.returnValue(claims)
d.addCallback(lambda r: self._render_response(r))
return d
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_get_transaction_history(self): def jsonrpc_get_transaction_history(self):
@ -2409,7 +2489,7 @@ class _ResolveNameHelper(object):
def get_deferred(self): def get_deferred(self):
if self.need_fresh_stream(): if self.need_fresh_stream():
log.info("Resolving stream info for lbry://%s", self.name) log.info("Resolving stream info for lbry://%s", self.name)
d = self.wallet.get_stream_info_for_name(self.name) d = self.wallet.get_claim_by_name(self.name)
d.addCallback(self._cache_stream_info) d.addCallback(self._cache_stream_info)
else: else:
log.debug("Returning cached stream info for lbry://%s", self.name) log.debug("Returning cached stream info for lbry://%s", self.name)
@ -2433,11 +2513,10 @@ class _ResolveNameHelper(object):
def _cache_stream_info(self, stream_info): def _cache_stream_info(self, stream_info):
self.daemon.name_cache[self.name] = { self.daemon.name_cache[self.name] = {
'claim_metadata': stream_info, 'claim_metadata': stream_info['value'],
'timestamp': self.now() 'timestamp': self.now()
} }
d = self.wallet.get_txid_for_name(self.name) d = self._add_txid(stream_info['txid'])
d.addCallback(self._add_txid)
d.addCallback(lambda _: self.daemon._update_claim_cache()) d.addCallback(lambda _: self.daemon._update_claim_cache())
d.addCallback(lambda _: self.name_data['claim_metadata']) d.addCallback(lambda _: self.name_data['claim_metadata'])
return d return d

View file

@ -64,7 +64,6 @@ class MarketFeed(object):
self.rate = ExchangeRate(self.market, price, int(time.time())) self.rate = ExchangeRate(self.market, price, int(time.time()))
def _log_error(self, err): def _log_error(self, err):
log.error(err)
log.warning( log.warning(
"There was a problem updating %s exchange rate information from %s", "There was a problem updating %s exchange rate information from %s",
self.market, self.name) self.market, self.name)

View file

@ -13,10 +13,11 @@ log = logging.getLogger(__name__)
class Publisher(object): class Publisher(object):
def __init__(self, session, lbry_file_manager, wallet): def __init__(self, session, lbry_file_manager, wallet, certificate_id):
self.session = session self.session = session
self.lbry_file_manager = lbry_file_manager self.lbry_file_manager = lbry_file_manager
self.wallet = wallet self.wallet = wallet
self.certificate_id = certificate_id
self.lbry_file = None self.lbry_file = None
""" """
@ -56,7 +57,8 @@ class Publisher(object):
@defer.inlineCallbacks @defer.inlineCallbacks
def make_claim(self, name, bid, claim_dict): def make_claim(self, name, bid, claim_dict):
claim_out = yield self.wallet.claim_name(name, bid, claim_dict) claim_out = yield self.wallet.claim_name(name, bid, claim_dict,
certificate_id=self.certificate_id)
defer.returnValue(claim_out) defer.returnValue(claim_out)

View file

@ -4,7 +4,7 @@ from twisted.trial import unittest
from twisted.internet import threads, defer from twisted.internet import threads, defer
from lbrynet.core.Error import InsufficientFundsError from lbrynet.core.Error import InsufficientFundsError
from lbrynet.core.Wallet import Wallet, ReservedPoints from lbrynet.core.Wallet import Wallet, ReservedPoints, InMemoryStorage
test_metadata = { test_metadata = {
'license': 'NASA', 'license': 'NASA',
@ -29,6 +29,8 @@ class MocLbryumWallet(Wallet):
self.wallet_balance = Decimal(10.0) self.wallet_balance = Decimal(10.0)
self.total_reserved_points = Decimal(0.0) self.total_reserved_points = Decimal(0.0)
self.queued_payments = defaultdict(Decimal) self.queued_payments = defaultdict(Decimal)
self._storage = InMemoryStorage()
def get_name_claims(self): def get_name_claims(self):
return threads.deferToThread(lambda: []) return threads.deferToThread(lambda: [])
@ -50,7 +52,7 @@ class WalletTest(unittest.TestCase):
def test_successful_send_name_claim(self): def test_successful_send_name_claim(self):
expected_claim_out = { expected_claim_out = {
"claimid": "f43dc06256a69988bdbea09a58c80493ba15dcfa", "claim_id": "f43dc06256a69988bdbea09a58c80493ba15dcfa",
"fee": "0.00012", "fee": "0.00012",
"nout": 0, "nout": 0,
"success": True, "success": True,
@ -59,12 +61,12 @@ class WalletTest(unittest.TestCase):
def check_out(claim_out): def check_out(claim_out):
self.assertTrue('success' not in claim_out) self.assertTrue('success' not in claim_out)
self.assertEqual(expected_claim_out['claimid'], claim_out['claimid']) self.assertEqual(expected_claim_out['claim_id'], claim_out['claim_id'])
self.assertEqual(expected_claim_out['fee'], claim_out['fee']) self.assertEqual(expected_claim_out['fee'], claim_out['fee'])
self.assertEqual(expected_claim_out['nout'], claim_out['nout']) self.assertEqual(expected_claim_out['nout'], claim_out['nout'])
self.assertEqual(expected_claim_out['txid'], claim_out['txid']) self.assertEqual(expected_claim_out['txid'], claim_out['txid'])
def success_send_name_claim(self, name, val, amount): def success_send_name_claim(self, name, val, amount, certificate_id=None):
return expected_claim_out return expected_claim_out
MocLbryumWallet._send_name_claim = success_send_name_claim MocLbryumWallet._send_name_claim = success_send_name_claim
@ -111,8 +113,8 @@ class WalletTest(unittest.TestCase):
return threads.deferToThread(lambda: claim_out) return threads.deferToThread(lambda: claim_out)
MocLbryumWallet._abandon_claim = failed_abandon_claim MocLbryumWallet._abandon_claim = failed_abandon_claim
wallet = MocLbryumWallet() wallet = MocLbryumWallet()
d = wallet.abandon_claim("11030a76521e5f552ca87ad70765d0cc52e6ea4c0dc0063335e6cf2a9a85085f", 1) d = wallet.abandon_claim("f43dc06256a69988bdbea09a58c80493ba15dcfa")
self.assertFailure(d,Exception) self.assertFailure(d, Exception)
return d return d
def test_successful_abandon(self): def test_successful_abandon(self):
@ -132,7 +134,7 @@ class WalletTest(unittest.TestCase):
MocLbryumWallet._abandon_claim = success_abandon_claim MocLbryumWallet._abandon_claim = success_abandon_claim
wallet = MocLbryumWallet() wallet = MocLbryumWallet()
d = wallet.abandon_claim("0578c161ad8d36a7580c557d7444f967ea7f988e194c20d0e3c42c3cabf110dd", 1) d = wallet.abandon_claim("f43dc06256a69988bdbea09a58c80493ba15dcfa")
d.addCallback(lambda claim_out: check_out(claim_out)) d.addCallback(lambda claim_out: check_out(claim_out))
return d return d
@ -187,7 +189,3 @@ class WalletTest(unittest.TestCase):
d.addCallback(lambda _: wallet.support_claim('test', "f43dc06256a69988bdbea09a58c80493ba15dcfa", 4)) d.addCallback(lambda _: wallet.support_claim('test', "f43dc06256a69988bdbea09a58c80493ba15dcfa", 4))
self.assertFailure(d,InsufficientFundsError) self.assertFailure(d,InsufficientFundsError)
return d return d