From 6252f903eeadee0349e59fe38db0f1e92a785dca Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Wed, 11 Nov 2015 15:06:14 -0500 Subject: [PATCH 1/6] automatically give LBC to users on the first run and update RUNNING.md for prompt interface --- RUNNING.md | 23 +++--- lbrynet/core/LBRYcrdWallet.py | 25 ++++++- lbrynet/lbrynet_console/ControlHandlers.py | 49 ++++++++++++- lbrynet/lbrynet_console/LBRYConsole.py | 54 +++++++++++++- lbrynet/lbrynet_gui/GuiApp.py | 2 +- lbrynet/lbrynet_gui/LBRYGui.py | 85 +++++++++++----------- 6 files changed, 178 insertions(+), 60 deletions(-) diff --git a/RUNNING.md b/RUNNING.md index d1b94c808..e2a975236 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -8,7 +8,7 @@ Download the file https://raw.githubusercontent.com/lbryio/lbry-setup/master/lbr Once it's done building, type: -./lbrycrd/src/lbrycrdd -server -daemon -gen +./lbrycrd/src/lbrycrdd -server -daemon lbrynet-gui @@ -91,12 +91,13 @@ In order to use lbrynet-console or lbrynet-gui, lbyrcrdd must be running. If you ran the easy install script, the lbrycrd folder will be in the directory you ran lbry_setup.sh from. Otherwise it is the root of the cloned lbrycrd repository. Go to that directory. +./src/lbrycrdd -server -daemon + +If you want to mine LBC, also use the flag '-gen', so: + ./src/lbrycrdd -server -daemon -gen It will take a few minutes for your client to download the whole block chain. -Once it has caught up, it will start mining coins. - -If you don't want to mine, leave off the '-gen' flag. lbrycrdd must be running in order for lbrynet to function. @@ -112,19 +113,15 @@ In your terminal: lbrynet-console -You should now be presented with a list of options. +You should be presented with a prompt. Watch It's a Wonderful Life via LBRY -Choose the option labeled Add a stream from a short name by typing the number next to it and pressing the enter key. +Type into the prompt: -You will be prompted for a name. Type in "wonderfullife" and hit enter. After a few seconds, you will prompted to choose what you want to do with the file. Select the option labeled Stream. +get wonderfullife -You will be shown some options related to the file which you do not care about. Type 'n' and hit enter. - -You will be prompted to choose if you really want to download this file. Type 'y' and hit enter. - -To shut it down, type ctrl-c at any time or enter the option to shut down from the main menu. +To shut it down, type ctrl-c at any time or enter 'exit' into the prompt. ### Option 2) Running lbrynet-gui @@ -137,4 +134,4 @@ lbrynet-gui A window should pop up with an entry box. Type 'wonderfullife' into the box, hit go, and then choose to save it or stream it. Enjoy! -Any questions or problems, email jimmy@lbry.io \ No newline at end of file +Any questions or problems, email jimmy@lbry.io diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 936a441cb..fc45f18d2 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -312,7 +312,7 @@ class LBRYcrdWallet(object): def get_name_and_validity_for_sd_hash(self, sd_hash): d = self._get_claim_metadata_for_sd_hash(sd_hash) - d.addCallback(lambda name_txid: self._get_status_of_claim(name_txid[1], name_txid[0], sd_hash) if name_txid is not None else None) + d.addCallback(lambda name_txid: threads.deferToThread(self._get_status_of_claim, name_txid[1], name_txid[0], sd_hash) if name_txid is not None else None) return d def get_available_balance(self): @@ -321,6 +321,15 @@ class LBRYcrdWallet(object): def get_new_address(self): return threads.deferToThread(self._get_new_address) + def check_first_run(self): + d = threads.deferToThread(self._get_wallet_balance) + d.addCallback(lambda bal: threads.deferToThread(self._get_num_addresses) if bal == 0 else 2) + d.addCallback(lambda num_addresses: True if num_addresses <= 1 else False) + return d + + def get_most_recent_blocktime(self): + return threads.deferToThread(self._get_best_block_time) + def get_rpc_conf(self): settings = {"username": "rpcuser", "password": "rpcpassword", @@ -509,6 +518,20 @@ class LBRYcrdWallet(object): return name, "unconfirmed" return None + @_catch_connection_error + def _get_num_addresses(self): + rpc_conn = self._get_rpc_conn() + return len(rpc_conn.getaddressesbyaccount("")) + + @_catch_connection_error + def _get_best_block_time(self): + rpc_conn = self._get_rpc_conn() + best_block_hash = rpc_conn.getbestblockhash() + block = rpc_conn.getblock(best_block_hash) + if 'time' in block: + return block['time'] + raise ValueError("Could not get a block time") + @_catch_connection_error def _rpc_stop(self): diff --git a/lbrynet/lbrynet_console/ControlHandlers.py b/lbrynet/lbrynet_console/ControlHandlers.py index 171da8983..52ac944f1 100644 --- a/lbrynet/lbrynet_console/ControlHandlers.py +++ b/lbrynet/lbrynet_console/ControlHandlers.py @@ -12,6 +12,7 @@ from lbrynet.core.Error import UnknownNameError, InvalidBlobHashError, Insuffici from lbrynet.core.Error import InvalidStreamInfoError from lbrynet.core.utils import is_valid_blobhash from twisted.internet import defer, threads +import datetime import os @@ -2349,4 +2350,50 @@ class StatusFactory(CommandHandlerFactory): "Show the list of files that are currently downloading " \ "or have been downloaded, and give the option to " \ "toggle whether the file is actively downloading or " \ - "to remove the file." \ No newline at end of file + "to remove the file." + + +class BlockchainStatus(CommandHandler): + def __init__(self, console, wallet=None): + CommandHandler.__init__(self, console) + self.wallet = wallet + + def start(self): + d = self.wallet.get_most_recent_blocktime() + d.addCallbacks(self._show_time_behind_blockchain, self._show_error) + d.chainDeferred(self.finished_deferred) + return d + + def _show_time_behind_blockchain(self, best_block_time): + best_time = datetime.datetime.utcfromtimestamp(best_block_time) + diff = datetime.datetime.utcnow() - best_time + unit = None + val = None + if diff.days > 0: + if diff.days >= 7: + val = diff.days // 7 + unit = "week" + else: + val = diff.days + unit = "day" + elif diff.seconds >= 60 * 90: + if diff.seconds >= 60 * 60: + val = diff.seconds // (60 * 60) + unit = "hour" + if unit is not None: + if val != 1: + unit += "s" + self.console.sendLine("This application is %d %s behind the LBC blockchain." % (val, unit)) + else: + self.console.sendLine("This application is up to date with the LBC blockchain.") + + def _show_error(self, err): + logging.error(err.getTraceback()) + self.console.sendLine("Unable to determine the status of the blockchain.") + + +class BlockchainStatusFactory(CommandHandlerFactory): + control_handler_class = BlockchainStatus + command = "get-blockchain-status" + short_help = "Show whether this application has caught up with the LBC blockchain" + full_help = "Show whether this applications has caught up with the LBC blockchain" \ No newline at end of file diff --git a/lbrynet/lbrynet_console/LBRYConsole.py b/lbrynet/lbrynet_console/LBRYConsole.py index 60dac2679..738d20541 100644 --- a/lbrynet/lbrynet_console/LBRYConsole.py +++ b/lbrynet/lbrynet_console/LBRYConsole.py @@ -2,6 +2,8 @@ import logging from lbrynet.core.Session import LBRYSession import os.path import argparse +import requests +import locale from yapsy.PluginManager import PluginManager from twisted.internet import defer, threads, stdio, task, error from lbrynet.lbrynet_console.ConsoleControl import ConsoleControl @@ -33,6 +35,7 @@ from lbrynet.lbrynet_console.ControlHandlers import ClaimNameFactory, GetNewWall from lbrynet.lbrynet_console.ControlHandlers import ShowServerStatusFactory, ModifyServerSettingsFactory from lbrynet.lbrynet_console.ControlHandlers import ModifyLBRYFileOptionsChooserFactory, StatusFactory from lbrynet.lbrynet_console.ControlHandlers import PeerStatsAndSettingsChooserFactory, PublishFactory +from lbrynet.lbrynet_console.ControlHandlers import BlockchainStatusFactory from lbrynet.core.LBRYcrdWallet import LBRYcrdWallet @@ -234,7 +237,8 @@ class LBRYConsole(): if not lbrycrdd_path: lbrycrdd_path = self.default_lbrycrdd_path d = defer.succeed(LBRYcrdWallet(self.db_dir, wallet_dir=self.lbrycrd_dir, - wallet_conf=self.lbrycrd_conf, lbrycrdd_path=lbrycrdd_path)) + wallet_conf=self.lbrycrd_conf, + lbrycrdd_path=lbrycrdd_path)) else: d = defer.succeed(PTCWallet(self.db_dir)) d.addCallback(lambda wallet: {"wallet": wallet}) @@ -267,8 +271,51 @@ class LBRYConsole(): dl.addCallback(lambda _: self.session.setup()) + dl.addCallback(lambda _: self.check_first_run()) + + dl.addCallback(self._show_first_run_result) + return dl + def check_first_run(self): + d = self.session.wallet.check_first_run() + d.addCallback(lambda is_first_run: self._do_first_run() if is_first_run else 0.0) + return d + + def _do_first_run(self): + d = self.session.wallet.get_new_address() + + def send_request(url, data): + r = requests.post(url, json=data) + if r.status_code == 200: + return r.json()['credits_sent'] + return 0.0 + + def log_error(err): + log.warning("unable to request free credits. %s", err.getErrorMessage()) + return 0.0 + + def request_credits(address): + url = "http://credreq.lbry.io/requestcredits" + data = {"address": address} + d = threads.deferToThread(send_request, url, data) + d.addErrback(log_error) + return d + + d.addCallback(request_credits) + return d + + @staticmethod + def _show_first_run_result(credits_received): + if credits_received != 0.0: + points_string = locale.format_string("%.2f LBC", (round(credits_received, 2),), + grouping=True) + alert.info("Thank you for using LBRY! You have been given %s for free because we " + "love you. Please give them a few minutes to show up while you catch up " + "with our blockchain.\nTo check whether you've caught up with the blockchain, " + "use the command 'get-blockchain-status'.\nDownloading some files " + "may not work until you have downloaded the LBC blockchain.", points_string) + def _setup_lbry_file_manager(self): self.lbry_file_metadata_manager = DBLBRYFileMetadataManager(self.db_dir) d = self.lbry_file_metadata_manager.setup() @@ -318,10 +365,11 @@ class LBRYConsole(): lbrycrd_handlers = [ AddStreamFromLBRYcrdNameFactory(self.sd_identifier, self.session, self.session.wallet), - ClaimNameFactory(self.session. wallet, self.lbry_file_manager, + ClaimNameFactory(self.session.wallet, self.lbry_file_manager, self.session.blob_manager), GetNewWalletAddressFactory(self.session.wallet), - PublishFactory(self.session, self.lbry_file_manager, self.session.wallet) + PublishFactory(self.session, self.lbry_file_manager, self.session.wallet), + BlockchainStatusFactory(self.session.wallet) ] self.add_control_handlers(lbrycrd_handlers) if self.peer_port is not None: diff --git a/lbrynet/lbrynet_gui/GuiApp.py b/lbrynet/lbrynet_gui/GuiApp.py index 8f5081002..573ac1df6 100644 --- a/lbrynet/lbrynet_gui/GuiApp.py +++ b/lbrynet/lbrynet_gui/GuiApp.py @@ -226,7 +226,7 @@ class DownloaderApp(object): def _start_downloader(self): self.downloader = LBRYDownloader() d = self.downloader.start() - d.addCallback(lambda _: self.downloader.do_first_run()) + d.addCallback(lambda _: self.downloader.check_first_run()) d.addCallback(self._show_welcome_message) return d diff --git a/lbrynet/lbrynet_gui/LBRYGui.py b/lbrynet/lbrynet_gui/LBRYGui.py index f8cdfa8c4..4253cc4c4 100644 --- a/lbrynet/lbrynet_gui/LBRYGui.py +++ b/lbrynet/lbrynet_gui/LBRYGui.py @@ -32,8 +32,6 @@ class LBRYDownloader(object): self.known_dht_nodes = [('104.236.42.182', 4000)] self.db_dir = os.path.join(os.path.expanduser("~"), ".lbrydownloader") self.blobfile_dir = os.path.join(self.db_dir, "blobfiles") - self.wallet_dir = os.path.join(os.path.expanduser("~"), ".lbrycrd") - self.wallet_conf = os.path.join(self.wallet_dir, "lbrycrd.conf") self.peer_port = 3333 self.dht_node_port = 4444 self.run_server = True @@ -42,8 +40,10 @@ class LBRYDownloader(object): if os.name == "nt": from lbrynet.winhelpers.knownpaths import get_path, FOLDERID, UserHandle self.download_directory = get_path(FOLDERID.Downloads, UserHandle.current) + self.wallet_dir = os.path.join(get_path(FOLDERID.RoamingAppData, UserHandle.current), "lbrycrd") else: self.download_directory = os.getcwd() + self.wallet_conf = os.path.join(self.wallet_dir, "lbrycrd.conf") self.wallet_user = None self.wallet_password = None self.sd_identifier = StreamDescriptorIdentifier() @@ -267,26 +267,26 @@ class LBRYDownloader(object): if not os.path.exists(self.blobfile_dir): os.makedirs(self.blobfile_dir) log.debug("Created the data directory: %s", str(self.blobfile_dir)) - if not os.path.exists(self.wallet_dir): - os.makedirs(self.wallet_dir) - if not os.path.exists(self.wallet_conf): - lbrycrd_conf = open(self.wallet_conf, mode='w') - self.wallet_user = "rpcuser" - lbrycrd_conf.write("rpcuser=%s\n" % self.wallet_user) - self.wallet_password = binascii.hexlify(Random.new().read(20)) - lbrycrd_conf.write("rpcpassword=%s\n" % self.wallet_password) - lbrycrd_conf.write("server=1\n") - lbrycrd_conf.close() - self.first_run = True - else: - lbrycrd_conf = open(self.wallet_conf) - for l in lbrycrd_conf: - if l.startswith("rpcuser="): - self.wallet_user = l[8:].rstrip('\n') - if l.startswith("rpcpassword="): - self.wallet_password = l[12:].rstrip('\n') - if l.startswith("rpcport="): - self.wallet_rpc_port = int(l[8:-1].rstrip('\n')) + if os.name == "nt": + if not os.path.exists(self.wallet_dir): + os.makedirs(self.wallet_dir) + if not os.path.exists(self.wallet_conf): + lbrycrd_conf = open(self.wallet_conf, mode='w') + self.wallet_user = "rpcuser" + lbrycrd_conf.write("rpcuser=%s\n" % self.wallet_user) + self.wallet_password = binascii.hexlify(Random.new().read(20)) + lbrycrd_conf.write("rpcpassword=%s\n" % self.wallet_password) + lbrycrd_conf.write("server=1\n") + lbrycrd_conf.close() + else: + lbrycrd_conf = open(self.wallet_conf) + for l in lbrycrd_conf: + if l.startswith("rpcuser="): + self.wallet_user = l[8:].rstrip('\n') + if l.startswith("rpcpassword="): + self.wallet_password = l[12:].rstrip('\n') + if l.startswith("rpcport="): + self.wallet_rpc_port = int(l[8:-1].rstrip('\n')) def _get_session(self): lbrycrdd_path = None @@ -349,30 +349,33 @@ class LBRYDownloader(object): self.session.wallet) self.sd_identifier.add_stream_downloader_factory(LBRYFileStreamType, file_opener_factory) - def do_first_run(self): - if self.first_run is True: - d = self.session.wallet.get_new_address() + def check_first_run(self): + d = self.session.wallet.check_first_run() + d.addCallback(lambda is_first_run: self._do_first_run() if is_first_run else 0.0) + return d - def send_request(url, data): - r = requests.post(url, json=data) - if r.status_code == 200: - return r.json()['credits_sent'] - return 0.0 + def _do_first_run(self): + d = self.session.wallet.get_new_address() - def log_error(err): - log.warning("unable to request free credits. %s", err.getErrorMessage()) - return 0.0 + def send_request(url, data): + r = requests.post(url, json=data) + if r.status_code == 200: + return r.json()['credits_sent'] + return 0.0 - def request_credits(address): - url = "http://credreq.lbry.io/requestcredits" - data = {"address": address} - d = threads.deferToThread(send_request, url, data) - d.addErrback(log_error) - return d + def log_error(err): + log.warning("unable to request free credits. %s", err.getErrorMessage()) + return 0.0 - d.addCallback(request_credits) + def request_credits(address): + url = "http://credreq.lbry.io/requestcredits" + data = {"address": address} + d = threads.deferToThread(send_request, url, data) + d.addErrback(log_error) return d - return defer.succeed(0.0) + + d.addCallback(request_credits) + return d def _resolve_name(self, uri): return self.session.wallet.get_stream_info_for_name(uri) From e4c2585e234165c11c7bf121c4d5602ca49480e7 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Tue, 17 Nov 2015 17:28:17 -0500 Subject: [PATCH 2/6] pass console object to all control handlers --- lbrynet/lbrynet_console/ControlHandlers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbrynet/lbrynet_console/ControlHandlers.py b/lbrynet/lbrynet_console/ControlHandlers.py index 7cef8fee2..dc560ba16 100644 --- a/lbrynet/lbrynet_console/ControlHandlers.py +++ b/lbrynet/lbrynet_console/ControlHandlers.py @@ -837,7 +837,7 @@ class LBRYFileChooser(RecursiveCommandHandler): def _get_control_handler_factories(self): control_handler_factories = [] for lbry_file in self.lbry_file_manager.lbry_files: - control_handler_factories.append(self.factory_class(lbry_file, *self.args)) + control_handler_factories.append(self.factory_class(self.console, lbry_file, *self.args)) return control_handler_factories From 7a3bdf93e9adc609a6f7cc1cbc514acb29ba7ba6 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Thu, 19 Nov 2015 23:20:17 -0500 Subject: [PATCH 3/6] make sure upnp is neither set nor unset if upnp is disabled --- lbrynet/core/Session.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lbrynet/core/Session.py b/lbrynet/core/Session.py index 21fd4c979..cc31c08ff 100644 --- a/lbrynet/core/Session.py +++ b/lbrynet/core/Session.py @@ -148,7 +148,8 @@ class LBRYSession(object): ds.append(defer.maybeDeferred(self.wallet.stop)) if self.blob_manager is not None: ds.append(defer.maybeDeferred(self.blob_manager.stop)) - ds.append(defer.maybeDeferred(self._unset_upnp)) + if self.use_upnp is True: + ds.append(defer.maybeDeferred(self._unset_upnp)) return defer.DeferredList(ds) def _try_upnp(self): From c8afce2a3a697a74dd58c95bc752bb452286e73a Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Mon, 23 Nov 2015 15:11:34 -0500 Subject: [PATCH 4/6] stop console from crashing on input before it is started --- lbrynet/lbrynet_console/ConsoleControl.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lbrynet/lbrynet_console/ConsoleControl.py b/lbrynet/lbrynet_console/ConsoleControl.py index a69b73350..4d49fd6d4 100644 --- a/lbrynet/lbrynet_console/ConsoleControl.py +++ b/lbrynet/lbrynet_console/ConsoleControl.py @@ -12,6 +12,8 @@ class ConsoleControl(basic.LineReceiver): def __init__(self): self.connected = False self.buffer = [] + self.command_handlers = {} + self.current_handler = None def start(self, command_handlers): self.command_handlers = {h.command: h for h in command_handlers} @@ -83,6 +85,8 @@ class ConsoleControl(basic.LineReceiver): self.show_prompt() def lineReceived(self, line): + if not self.command_handlers: + return if self.current_handler is None: words = line.split() if len(words) == 0: From a148d4f446d8d443ed4e0f768cf15f243f920b14 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Wed, 25 Nov 2015 10:31:43 -0500 Subject: [PATCH 5/6] use specific version of python-bitcoinrpc --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 32dae8153..03a076268 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, find_packages setup(name='lbrynet', version='0.0.4', packages=find_packages(), - install_requires=['pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', 'python-bitcoinrpc', 'txJSON-RPC', 'requests', 'unqlite', 'leveldb'], + install_requires=['pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests', 'unqlite', 'leveldb'], entry_points={ 'console_scripts': [ 'lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch_lbry_console', From d04981969fff56c77068cb4737f80deb7a41fd87 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Wed, 25 Nov 2015 11:16:27 -0500 Subject: [PATCH 6/6] increase the time limit for waiting for lbrycrdd to start up --- lbrynet/core/LBRYcrdWallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index fc45f18d2..476457391 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -384,7 +384,7 @@ class LBRYcrdWallet(object): except (socket.error, JSONRPCException): tries += 1 log.warning("Failed to connect to lbrycrdd.") - if tries < 5: + if tries < 6: time.sleep(2 ** tries) log.warning("Trying again in %d seconds", 2 ** tries) else: