From 27ccb37646ef06cb5df485227d5a7061966d94f0 Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 8 Mar 2016 12:15:49 -0500 Subject: [PATCH 01/32] update daemon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check that managed files still exist, if they don’t remove them from the manager --- lbrynet/lbryfilemanager/LBRYFileManager.py | 29 ++++++++++-- .../lbrynet_daemon/Apps/LBRYOSXStatusBar.py | 4 +- lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py | 23 +++++---- lbrynet/lbrynet_daemon/LBRYDaemon.py | 47 ++++++++++++++----- lbrynet/lbrynet_daemon/LBRYDownloader.py | 5 +- 5 files changed, 76 insertions(+), 32 deletions(-) diff --git a/lbrynet/lbryfilemanager/LBRYFileManager.py b/lbrynet/lbryfilemanager/LBRYFileManager.py index ed4c75a79..fb14ec199 100644 --- a/lbrynet/lbryfilemanager/LBRYFileManager.py +++ b/lbrynet/lbryfilemanager/LBRYFileManager.py @@ -3,17 +3,19 @@ Keep track of which LBRY Files are downloading and store their LBRY File specifi """ import logging - -from twisted.enterprise import adbapi - +import datetime import os import sys + +from twisted.internet.task import LoopingCall +from twisted.enterprise import adbapi +from twisted.internet import defer, task, reactor +from twisted.python.failure import Failure + from lbrynet.lbryfilemanager.LBRYFileDownloader import ManagedLBRYFileDownloader from lbrynet.lbryfilemanager.LBRYFileDownloader import ManagedLBRYFileDownloaderFactory from lbrynet.lbryfile.StreamDescriptor import LBRYFileStreamType from lbrynet.core.PaymentRateManager import PaymentRateManager -from twisted.internet import defer, task, reactor -from twisted.python.failure import Failure from lbrynet.cryptstream.client.CryptStreamDownloader import AlreadyStoppedError, CurrentlyStoppingError from lbrynet.core.sqlite_helpers import rerun_if_locked @@ -32,6 +34,7 @@ class LBRYFileManager(object): self.sd_identifier = sd_identifier self.lbry_files = [] self.sql_db = None + self.check_exists_loop = LoopingCall(self.check_files_exist) if sys.platform.startswith("darwin"): self.download_directory = os.path.join(os.path.expanduser("~"), 'Downloads') else: @@ -39,11 +42,25 @@ class LBRYFileManager(object): log.debug("Download directory for LBRYFileManager: %s", str(self.download_directory)) def setup(self): + self.check_exists_loop.start(1) + d = self._open_db() d.addCallback(lambda _: self._add_to_sd_identifier()) d.addCallback(lambda _: self._start_lbry_files()) return d + def check_files_exist(self): + def _disp(deleted_files): + if deleted_files[0][0]: + for file in bad_files: + print "[" + str(datetime.datetime.now()) + "] Detected " + file.file_name + " was deleted, removing from file manager" + + bad_files = [lbry_file for lbry_file in self.lbry_files + if lbry_file.completed == True and + os.path.isfile(os.path.join(self.download_directory, lbry_file.file_name)) == False] + d = defer.DeferredList([self.delete_lbry_file(lbry_file) for lbry_file in bad_files], consumeErrors=True) + d.addCallback(lambda files: _disp(files) if len(files) else defer.succeed(None)) + def get_lbry_file_status(self, lbry_file): return self._get_lbry_file_status(lbry_file.rowid) @@ -152,6 +169,8 @@ class LBRYFileManager(object): return defer.fail(Failure(ValueError("Could not find that LBRY file"))) def stop(self): + self.check_exists_loop.stop() + ds = [] def wait_for_finished(lbry_file, count=2): diff --git a/lbrynet/lbrynet_daemon/Apps/LBRYOSXStatusBar.py b/lbrynet/lbrynet_daemon/Apps/LBRYOSXStatusBar.py index c55fed0d2..5ca433f72 100644 --- a/lbrynet/lbrynet_daemon/Apps/LBRYOSXStatusBar.py +++ b/lbrynet/lbrynet_daemon/Apps/LBRYOSXStatusBar.py @@ -39,7 +39,7 @@ class DaemonStatusBarApp(rumps.App): daemon = xmlrpclib.ServerProxy("http://localhost:7080/") try: daemon.is_running() - webbrowser.open("lbry://lbry") + webbrowser.get('safari').open("lbry://lbry") except: try: rumps.notification(title='LBRY', subtitle='', message="Couldn't connect to lbrynet daemon", sound=True) @@ -51,7 +51,7 @@ class DaemonStatusBarApp(rumps.App): daemon = xmlrpclib.ServerProxy("http://localhost:7080/") try: daemon.is_running() - webbrowser.open("lbry://settings") + webbrowser.get('safari').open("lbry://settings") except: rumps.notification(title='LBRY', subtitle='', message="Couldn't connect to lbrynet daemon", sound=True) diff --git a/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py b/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py index eea94cb94..1cc1bf3f8 100644 --- a/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py +++ b/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py @@ -30,22 +30,25 @@ def main(args): else: r = daemon.get(args[0][7:]) - path = r['path'] - if path[0] != '/': - path = '/' + path + if r[0] == 200: + path = r[1]['path'] + if path[0] != '/': + path = '/' + path - filename = os.path.basename(path) - extension = os.path.splitext(filename)[1] + filename = os.path.basename(path) + extension = os.path.splitext(filename)[1] - if extension in ['mp4', 'flv', 'mov']: - html = render_video(path) - daemon.render_html(html) + if extension in ['mp4', 'flv', 'mov']: + html = render_video(path) + daemon.render_html(html) + else: + webbrowser.get('safari').open('file://' + str(path)) else: - webbrowser.open('file://' + str(path)) + webbrowser.get('safari').open('http://lbry.io/get') except: - webbrowser.open('http://lbry.io/get') + webbrowser.get('safari').open('http://lbry.io/get') if __name__ == "__main__": diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 1e68f0f76..410da8a81 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -41,21 +41,21 @@ from lbrynet.lbryfilemanager.LBRYFileManager import LBRYFileManager from lbrynet.lbryfile.LBRYFileMetadataManager import DBLBRYFileMetadataManager, TempLBRYFileMetadataManager log = logging.getLogger(__name__) - - # logging.basicConfig(level=logging.DEBUG) # TODO add login credentials in a conf file - -# issues with delete: -# TODO when stream is stopped the generated file is deleted - # functions to add: # TODO send credits to address # TODO alert if your copy of a lbry file is out of date with the name record +BAD_REQUEST = (400, "Bad request") +NOT_FOUND = (404, "Not found") + +OK_CODE = 200 + + class LBRYDaemon(xmlrpc.XMLRPC): """ LBRYnet daemon @@ -556,8 +556,11 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = self._check_history(name) d.addCallback(lambda lbry_file: _get_stream(name) if not lbry_file else _disp_file(lbry_file)) d.addCallback(lambda _: self._check_history(name)) - d.addCallback(lambda lbry_file: self._path_from_lbry_file(lbry_file) if lbry_file else 'Not found') - d.addErrback(lambda err: str(err)) + d.addCallback(lambda lbry_file: (OK_CODE, {'stream_hash': lbry_file.stream_hash, + 'path': os.path.join(self.download_directory, + lbry_file.file_name)}) + if lbry_file else NOT_FOUND) + d.addErrback(lambda _: NOT_FOUND) return d @@ -612,6 +615,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): def finish_deletion(lbry_file): d = lbry_file.delete_data() d.addCallback(lambda _: _delete_stream_data(lbry_file)) + d.addCallback(lambda _: _delete_file(lbry_file)) return d def _delete_stream_data(lbry_file): @@ -621,6 +625,9 @@ class LBRYDaemon(xmlrpc.XMLRPC): d.addCallback(lambda c: self.stream_info_manager.delete_stream(s_h) if c == 0 else True) return d + def _delete_file(lbry_file): + os.remove(os.path.join(self.download_directory, lbry_file.file_name)) + d.addCallback(lambda _: finish_deletion(lbry_file)) return d @@ -807,7 +814,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): if name: d = self._download_name(name) else: - d = defer.succeed('No name provided') + d = defer.succeed(BAD_REQUEST) return d def xmlrpc_stop_lbry_file(self, stream_hash): @@ -875,8 +882,12 @@ class LBRYDaemon(xmlrpc.XMLRPC): return err d = defer.Deferred() - d.addCallback(lambda _: webbrowser.open( - "file://" + str(os.path.join(self.download_directory, "lbryio/view/page/gui.html")))) + if sys.platform == 'darwin': + d.addCallback(lambda _: webbrowser.get('safari').open( + "file://" + str(os.path.join(self.download_directory, "lbryio/view/page/gui.html")))) + else: + d.addCallback(lambda _: webbrowser.open( + "file://" + str(os.path.join(self.download_directory, "lbryio/view/page/gui.html")))) d.addErrback(_disp_err) d.callback(None) @@ -967,13 +978,16 @@ class LBRYDaemon(xmlrpc.XMLRPC): return d def xmlrpc_publish(self, metadata): - metadata = json.loads(metadata) + try: + metadata = json.loads(metadata) + except: + return defer.succeed(BAD_REQUEST) required = ['name', 'file_path', 'bid'] for r in required: if not r in metadata.keys(): - return defer.fail() + return defer.succeed(BAD_REQUEST) # if not os.path.isfile(metadata['file_path']): # return defer.fail() @@ -1023,6 +1037,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): p = Publisher(self.session, self.lbry_file_manager, self.session.wallet) d = p.start(name, file_path, bid, title, description, thumbnail, key_fee, key_fee_address, content_license) + d.addCallback(lambda msg: (OK_CODE, msg)) return d @@ -1145,6 +1160,12 @@ class LBRYDaemon(xmlrpc.XMLRPC): else: return "Status bar not implemented on non OS X" + def xmlrpc___dir__(self): + return ['is_running', 'get_settings', 'set_settings', 'start_fetcher', 'stop_fetcher', 'fetcher_status', + 'get_balance', 'stop', 'get_lbry_files', 'resolve_name', 'get', 'search_nametrie', + 'delete_lbry_file', 'check', 'publish', 'abandon_name', 'get_name_claims', + 'get_time_behind_blockchain', 'get_new_address', 'toggle_fetcher_verbose', 'check_for_new_version'] + def stop(): daemon = xmlrpclib.ServerProxy("http://localhost:7080/") diff --git a/lbrynet/lbrynet_daemon/LBRYDownloader.py b/lbrynet/lbrynet_daemon/LBRYDownloader.py index 4ea161c81..c5bfea81f 100644 --- a/lbrynet/lbrynet_daemon/LBRYDownloader.py +++ b/lbrynet/lbrynet_daemon/LBRYDownloader.py @@ -7,6 +7,7 @@ from twisted.internet.task import LoopingCall from lbrynet.core.Error import InvalidStreamInfoError, InsufficientFundsError from lbrynet.core.PaymentRateManager import PaymentRateManager from lbrynet.core.StreamDescriptor import download_sd_blob +from lbrynet.lbryfilemanager.LBRYFileDownloader import ManagedLBRYFileDownloaderFactory log = logging.getLogger(__name__) @@ -62,8 +63,8 @@ class GetStream(object): d = defer.Deferred(None) d.addCallback(lambda _: download_sd_blob(self.session, self.stream_hash, self.payment_rate_manager)) d.addCallback(self.sd_identifier.get_metadata_for_sd_blob) - d.addCallback(lambda metadata: - metadata.factories[1].make_downloader(metadata, [self.data_rate, True], self.payment_rate_manager)) + d.addCallback(lambda metadata: (next(factory for factory in metadata.factories if isinstance(factory, ManagedLBRYFileDownloaderFactory)), metadata)) + d.addCallback(lambda (factory, metadata): factory.make_downloader(metadata, [self.data_rate, True], self.payment_rate_manager)) d.addErrback(lambda err: err.trap(defer.CancelledError)) d.addErrback(lambda err: log.error("An exception occurred attempting to load the stream descriptor: %s", err.getTraceback())) d.addCallback(self._start_download) From 5bf895eefe958b06f641f17c03f998896d3ed8af Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Wed, 9 Mar 2016 12:26:07 -0500 Subject: [PATCH 02/32] update documentation to reflect using lbryum by default --- INSTALL.md | 38 ++--------- README.md | 2 +- RUNNING.md | 75 ++++++++++++---------- lbrynet/lbrynet_console/ConsoleControl.py | 12 +--- lbrynet/lbrynet_console/ControlHandlers.py | 8 +-- 5 files changed, 55 insertions(+), 80 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index a964c8a8f..6dc552bcf 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,38 +1,14 @@ -Prerequisites -------------- - -To use the LBRYWallet, which enables spending and accepting LBRYcrds in exchange for data, the -LBRYcrd application (insert link to LBRYcrd website here) must be installed and running. If -this is not desired, the testing client can be used to simulate trading points, which is -built into LBRYnet. - -on Ubuntu: - -``` -sudo apt-get install libgmp3-dev build-essential python-dev python-pip -``` - -Getting the source ------------------- - -Don't you already have it? - -Setting up the environment +#### Installing lbrynet on Linux -------------------------- -It's recommended that you use a virtualenv +The following packages are necessary (the following are their names on Ubuntu): +libgmp3-dev build-essential python2.7 python2.7-dev python-pip -``` -sudo apt-get install python-virtualenv -cd -virtualenv . -source bin/activate -``` +To install them on Ubuntu: +sudo apt-get install libgmp3-dev build-essential python2.7 python2.7-dev python-pip -(to deactivate the virtualenv, enter 'deactivate') - -``` -python setup.py install +python setup.py build bdist_egg +sudo python setup.py install ``` this will install all of the libraries and a few applications diff --git a/README.md b/README.md index d9f7cd98e..dc8b5c81f 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ See [INSTALL](INSTALL.md) ## Developers Documentation: doc.lbry.io -Source code: trac.lbry.io/browser +Source code: https://github.com/lbryio/lbry To contribute to the development of LBRYnet or lbrynet-console, contact jimmy@lbry.io diff --git a/RUNNING.md b/RUNNING.md index 137487360..b9f60acc9 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -9,20 +9,38 @@ Download the file https://raw.githubusercontent.com/lbryio/lbry-setup/master/lbr Once it's done building, type: ``` -./lbrycrd/src/lbrycrdd -server -daemon -lbrynet-gui +lbrynet-console ``` -A window should show up with an entry box +A console application will load, and after a moment you will be presented with a ">" signifying +that the console is ready for commands. -Type wonderfullife into the box, hit go, and choose to stream or save +If it's your first time running lbrynet-console, you should be given some credits to test the +network. If they don't show up within a minute or two, let us know, and we'll send you some. -To stop lbrycrdd: `./lbrycrd/src/lbrycrd-cli stop` +After your credits have shown up, type + +``` +get wonderfullife +``` + +into the prompt and hit enter. + +You will be asked if you want to cancel, change options, save, and perhaps stream the file. + +Enter 's' for save and then hit enter. + +The file should start downloading. Enter the command 'status' to check on the status of files +that are in the process of being downloaded. + +To stop lbrynet-console, enter the command 'exit'. ## Slightly longer install guide -### Installing lbrycrd from source +### Installing lbrycrd, the full blockchain client + +Note: this process takes upwards of an hour and is not necessary to use lbrynet. ``` git clone --depth=1 -b alpha https://github.com/lbryio/lbrycrd.git @@ -89,11 +107,21 @@ sudo python setup.py install ## Slightly longer running guide -###In order to use lbrynet-console or lbrynet-gui, lbyrcrd must be running. +### lbrynet-console can be set to use lbrycrdd instead of the built in lightweight client. -### Running lbrycrd +To run lbrynet-console with lbrycrdd: -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. +``` +lbrynet-console +``` + +If lbrycrdd is not already running, lbrynet will launch it at that path, and will shut it down +when lbrynet exits. If lbrycrdd is already running, lbrynet will not launch it and will not +shut it down, but it will connect to it and use it. + +### Running lbrycrdd manually + +From the lbrycrd directory, run: ``` ./src/lbrycrdd -server -daemon @@ -105,37 +133,14 @@ If you want to mine LBC, also use the flag '-gen', so: ./src/lbrycrdd -server -daemon -gen ``` +Warning: This will put a heavy load on your CPU + It will take a few minutes for your client to download the whole block chain. -lbrycrdd must be running in order for lbrynet to function. - -To shut lbrycrdd down: from the lbrycrd directory, run +To shut lbrycrdd down: from the lbrycrd directory, run: ``` ./src/lbrycrd-cli stop ``` -### Option 1) Running lbrynet-console - -If you used the virtualenv instructions above, make sure the virtualenv is still active. If not, reactivate it according to the instructions above, under "Installing lbrynet from source" - -In your terminal: `lbrynet-console` - -You should be presented with a prompt. - -Watch It's a Wonderful Life via LBRY - -Type into the prompt: `get wonderfullife` - -To shut it down, press ctrl-c at any time or enter `exit` into the prompt. - -### Option 2) Running lbrynet-gui - -If you used the virtualenv instructions above, make sure the virtualenv is still active. If not, reactivate it according to the instructions above, under "Installing lbrynet from source" - -In your terminal: `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 diff --git a/lbrynet/lbrynet_console/ConsoleControl.py b/lbrynet/lbrynet_console/ConsoleControl.py index 8b6552e6e..be52da843 100644 --- a/lbrynet/lbrynet_console/ConsoleControl.py +++ b/lbrynet/lbrynet_console/ConsoleControl.py @@ -29,16 +29,10 @@ class ConsoleControl(basic.LineReceiver): def send_initial_prompt(self): self.sendLine("") - self.sendLine("In this early release of LBRY, some functions will not work\n" - "until you have downloaded a full copy of our blockchain. To\n" - "check whether you've caught up with the blockchain, use the\n" - "command 'get-blockchain-status'.\n\n" - "If, for example, you are unable to download some files or\n" - "your balance is showing 0 when you know it shouldn't be, it\n" - "is likely that the culprit is the blockchain.\n\n" - "You should have received 1000 LBC the first time you ran\n" + self.sendLine("You should have received 1000 LBC the first time you ran\n" "this program. If you did not, let us know! But first give\n" - "them a couple of minutes to show up.\n\n" + "them a moment to show up. The block time is currently 30\n" + "seconds so they should show up within a couple of minutes.\n\n" "Welcome to lbrynet-console!") self.sendLine("") self.sendLine("Enter a command. Try 'get wonderfullife' or 'help' to see more options.") diff --git a/lbrynet/lbrynet_console/ControlHandlers.py b/lbrynet/lbrynet_console/ControlHandlers.py index 6cac5da64..6542505c2 100644 --- a/lbrynet/lbrynet_console/ControlHandlers.py +++ b/lbrynet/lbrynet_console/ControlHandlers.py @@ -323,7 +323,7 @@ class GetWalletBalances(CommandHandler): def _show_time_behind_blockchain(self, rounded_time): if rounded_time.unit >= RoundedTime.HOUR: self.console.sendLine("\n\nYour balance may be out of date. This application\n" - "is %s behind the LBC blockchain. It should take a few minutes to\n" + "is %s behind the LBC blockchain. It may take a few minutes to\n" "catch up the first time you run this early version of LBRY.\n" "Please be patient =).\n\n" % str(rounded_time)) else: @@ -797,7 +797,7 @@ class AddStream(CommandHandler): self.console.sendLine("\nThis application is %s behind the LBC blockchain, so some of your\n" "funds may not be available. Use 'get-blockchain-status' to check if\n" "your application is up to date with the blockchain.\n\n" - "It should take a few minutes to catch up the first time you run this\n" + "It may take a few minutes to catch up the first time you run this\n" "early version of LBRY. Please be patient =).\n\n" % str(rounded_time)) def _log_recent_blockchain_time_error_download(self, err): @@ -913,7 +913,7 @@ class AddStreamFromLBRYcrdName(AddStreamFromHash): self.console.sendLine("\nThis application is %s behind the LBC blockchain, which may be\n" "preventing this name from being resolved correctly. Use 'get-blockchain-status'\n" "to check if your application is up to date with the blockchain.\n\n" - "It should take a few minutes to catch up the first time you run\n" + "It may take a few minutes to catch up the first time you run\n" "this early version of LBRY. Please be patient =).\n\n" % str(rounded_time)) else: self.console.sendLine("\n") @@ -1850,7 +1850,7 @@ class Publish(CommandHandler): if rounded_time.unit >= RoundedTime.HOUR: self.console.sendLine("This application is %s behind the LBC blockchain\n" "and therefore may not have all of the funds you expect\n" - "available at this time. It should take a few minutes to\n" + "available at this time. It may take a few minutes to\n" "catch up the first time you run this early version of LBRY.\n" "Please be patient =).\n" % str(rounded_time)) From e91f34f09b5cb30e65c11630e798c8dd432997ab Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Sat, 12 Mar 2016 14:25:46 -0500 Subject: [PATCH 03/32] change metadata structure to use sources key --- lbrynet/core/LBRYcrdWallet.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 09bc1e7bc..ef7c95baf 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -297,10 +297,19 @@ class LBRYWallet(object): except (ValueError, TypeError): return Failure(InvalidStreamInfoError(name)) known_fields = ['stream_hash', 'name', 'description', 'key_fee', 'key_fee_address', 'thumbnail', - 'content_license'] + 'content_license', 'sources'] + known_sources = ['lbry_sd_hash'] for field in known_fields: if field in value_dict: - r_dict[field] = value_dict[field] + if field == 'sources': + for source in known_sources: + if source in value_dict[field]: + if source == 'lbry_sd_hash': + r_dict['stream_hash'] = value_dict[field][source] + else: + r_dict[source] = value_dict[field][source] + else: + r_dict[field] = value_dict[field] if 'stream_hash' in r_dict and 'txid' in result: d = self._save_name_metadata(name, r_dict['stream_hash'], str(result['txid'])) else: @@ -312,8 +321,8 @@ class LBRYWallet(object): return Failure(UnknownNameError(name)) def claim_name(self, name, sd_hash, amount, description=None, key_fee=None, - key_fee_address=None, thumbnail=None, content_license=None): - value = {"stream_hash": sd_hash} + key_fee_address=None, thumbnail=None, content_license=None): + value = {"sources": {'lbry_sd_hash': sd_hash}} if description is not None: value['description'] = description if key_fee is not None: @@ -397,7 +406,12 @@ class LBRYWallet(object): value_dict = json.loads(claim['value']) except (ValueError, TypeError): return None - if 'stream_hash' in value_dict and str(value_dict['stream_hash']) == sd_hash: + claim_sd_hash = None + if 'stream_hash' in value_dict: + claim_sd_hash = str(value_dict['stream_hash']) + if 'sources' in value_dict and 'lbrynet_sd_hash' in value_dict['sources']: + claim_sd_hash = str(value_dict['sources']['lbry_sd_hash']) + if claim_sd_hash is not None and claim_sd_hash == sd_hash: if 'is controlling' in claim and claim['is controlling']: return name, "valid" if claim['in claim trie']: From 14ab2b52e94afc9c1a81b0932db224b25c52289a Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Sat, 12 Mar 2016 14:42:57 -0500 Subject: [PATCH 04/32] create fee field in metadata --- lbrynet/core/LBRYcrdWallet.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index ef7c95baf..153b27e56 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -297,8 +297,9 @@ class LBRYWallet(object): except (ValueError, TypeError): return Failure(InvalidStreamInfoError(name)) known_fields = ['stream_hash', 'name', 'description', 'key_fee', 'key_fee_address', 'thumbnail', - 'content_license', 'sources'] + 'content_license', 'sources', 'fee'] known_sources = ['lbry_sd_hash'] + known_fee_types = {'LBC': ['amount', 'address']} for field in known_fields: if field in value_dict: if field == 'sources': @@ -308,6 +309,18 @@ class LBRYWallet(object): r_dict['stream_hash'] = value_dict[field][source] else: r_dict[source] = value_dict[field][source] + elif field == 'fee': + fee = value_dict['fee'] + if 'type' in fee: + if fee['type'] in known_fee_types: + fee_fields = known_fee_types[fee['type']] + if all([f in fee for f in fee_fields]): + r_dict['key_fee'] = fee['amount'] + r_dict['key_fee_address'] = fee['address'] + else: + for f in ['key_fee', 'key_fee_address']: + if f in r_dict: + del r_dict[f] else: r_dict[field] = value_dict[field] if 'stream_hash' in r_dict and 'txid' in result: @@ -325,10 +338,8 @@ class LBRYWallet(object): value = {"sources": {'lbry_sd_hash': sd_hash}} if description is not None: value['description'] = description - if key_fee is not None: - value['key_fee'] = key_fee - if key_fee_address is not None: - value['key_fee_address'] = key_fee_address + if key_fee is not None and key_fee_address is not None: + value['fee'] = {'type': 'LBC', 'amount': key_fee, 'address': key_fee_address} if thumbnail is not None: value['thumbnail'] = thumbnail if content_license is not None: From dff0fcb1fd9d9d1303036cd361be3d097bd7b4a4 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Sat, 12 Mar 2016 14:58:58 -0500 Subject: [PATCH 05/32] ensure the lbryum wallet is caught up before giving the prompt --- lbrynet/core/LBRYcrdWallet.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 153b27e56..88a9686ef 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -869,7 +869,7 @@ class LBRYumWallet(LBRYWallet): def setup_network(): self.config = SimpleConfig() self.network = Network(self.config) - alert.info("Starting the wallet...") + alert.info("Loading the wallet...") return defer.succeed(self.network.start()) d = setup_network() @@ -882,7 +882,6 @@ class LBRYumWallet(LBRYWallet): return False start_check.stop() if self.network.is_connected(): - alert.info("Wallet started.") network_start_d.callback(True) else: network_start_d.errback(ValueError("Failed to connect to network.")) @@ -926,9 +925,24 @@ class LBRYumWallet(LBRYWallet): wallet.synchronize() self.wallet = wallet + blockchain_caught_d = defer.Deferred() + + def check_caught_up(): + local_height = self.network.get_local_height() + remote_height = self.network.get_server_height() + + if remote_height != 0 and remote_height - local_height <= 5: + alert.info('Wallet loaded.') + catch_up_check.stop() + blockchain_caught_d.callback(True) + + catch_up_check = task.LoopingCall(check_caught_up) + d = threads.deferToThread(get_wallet) d.addCallback(self._save_wallet) d.addCallback(lambda _: self.wallet.start_threads(self.network)) + d.addCallback(lambda _: catch_up_check.start(.1)) + d.addCallback(lambda _: blockchain_caught_d) return d def _get_cmd_runner(self): From 42df2fe242b3a9e540bc78074026f619c5f1ebeb Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 14 Mar 2016 12:30:22 -0400 Subject: [PATCH 06/32] update daemon convert to jsonrpc, fix a few issues, remove hacky functions --- lbrynet/conf.py | 12 +- lbrynet/core/LBRYcrdWallet.py | 8 +- lbrynet/lbryfilemanager/LBRYFileManager.py | 19 +- lbrynet/lbrynet_daemon/LBRYDaemon.py | 606 +++++++++----------- lbrynet/lbrynet_daemon/LBRYDaemonControl.py | 51 ++ lbrynet/lbrynet_daemon/LBRYDownloader.py | 39 +- lbrynet/lbrynet_daemon/LBRYPublisher.py | 4 +- setup.py | 16 +- 8 files changed, 398 insertions(+), 357 deletions(-) create mode 100644 lbrynet/lbrynet_daemon/LBRYDaemonControl.py diff --git a/lbrynet/conf.py b/lbrynet/conf.py index c172884e6..8af383387 100644 --- a/lbrynet/conf.py +++ b/lbrynet/conf.py @@ -26,4 +26,14 @@ KNOWN_DHT_NODES = [('104.236.42.182', 4000)] POINTTRADER_SERVER = 'http://ec2-54-187-192-68.us-west-2.compute.amazonaws.com:2424' #POINTTRADER_SERVER = 'http://127.0.0.1:2424' -CRYPTSD_FILE_EXTENSION = ".cryptsd" \ No newline at end of file +CRYPTSD_FILE_EXTENSION = ".cryptsd" + +API_INTERFACE = "localhost" +API_ADDRESS = "lbryapi" +API_PORT = 5279 +ICON_PATH = "app.icns" +APP_NAME = "LBRY" +DEFAULT_WALLET = "lbryum" + +API_CONNECTION_STRING = "http://%s:%i/%s" % (API_INTERFACE, API_PORT, API_ADDRESS) +PROTOCOL_PREFIX = "lbry" \ No newline at end of file diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 46279a2e4..543551c36 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -874,13 +874,15 @@ class LBRYumWallet(LBRYWallet): d = defer.Deferred() def check_stopped(): - if self.network.is_connected(): - return False + if self.network: + if self.network.is_connected(): + return False stop_check.stop() self.network = None d.callback(True) - self.network.stop() + if self.network: + self.network.stop() stop_check = task.LoopingCall(check_stopped) stop_check.start(.1) diff --git a/lbrynet/lbryfilemanager/LBRYFileManager.py b/lbrynet/lbryfilemanager/LBRYFileManager.py index fb14ec199..f741558dc 100644 --- a/lbrynet/lbryfilemanager/LBRYFileManager.py +++ b/lbrynet/lbryfilemanager/LBRYFileManager.py @@ -3,9 +3,9 @@ Keep track of which LBRY Files are downloading and store their LBRY File specifi """ import logging -import datetime import os import sys +from datetime import datetime from twisted.internet.task import LoopingCall from twisted.enterprise import adbapi @@ -28,12 +28,13 @@ class LBRYFileManager(object): Keeps track of currently opened LBRY Files, their options, and their LBRY File specific metadata. """ - def __init__(self, session, stream_info_manager, sd_identifier): + def __init__(self, session, stream_info_manager, sd_identifier, delete_data=False): self.session = session self.stream_info_manager = stream_info_manager self.sd_identifier = sd_identifier self.lbry_files = [] self.sql_db = None + self.delete_data = delete_data self.check_exists_loop = LoopingCall(self.check_files_exist) if sys.platform.startswith("darwin"): self.download_directory = os.path.join(os.path.expanduser("~"), 'Downloads') @@ -42,7 +43,7 @@ class LBRYFileManager(object): log.debug("Download directory for LBRYFileManager: %s", str(self.download_directory)) def setup(self): - self.check_exists_loop.start(1) + self.check_exists_loop.start(10) d = self._open_db() d.addCallback(lambda _: self._add_to_sd_identifier()) @@ -53,7 +54,14 @@ class LBRYFileManager(object): def _disp(deleted_files): if deleted_files[0][0]: for file in bad_files: - print "[" + str(datetime.datetime.now()) + "] Detected " + file.file_name + " was deleted, removing from file manager" + log.info("[" + str(datetime.now()) + "] Detected " + file.file_name + " was deleted, removing from file manager") + + def _delete_stream_data(lbry_file): + s_h = lbry_file.stream_hash + d = self.get_count_for_stream_hash(s_h) + # TODO: could possibly be a timing issue here + d.addCallback(lambda c: self.stream_info_manager.delete_stream(s_h) if c == 0 else True) + return d bad_files = [lbry_file for lbry_file in self.lbry_files if lbry_file.completed == True and @@ -61,6 +69,9 @@ class LBRYFileManager(object): d = defer.DeferredList([self.delete_lbry_file(lbry_file) for lbry_file in bad_files], consumeErrors=True) d.addCallback(lambda files: _disp(files) if len(files) else defer.succeed(None)) + if self.delete_data: + d2 = defer.DeferredList([_delete_stream_data(lbry_file) for lbry_file in bad_files], consumeErrors=True) + def get_lbry_file_status(self, lbry_file): return self._get_lbry_file_status(lbry_file.rowid) diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 410da8a81..67b5c8c9b 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -1,23 +1,21 @@ import locale import os import sys -import json +import simplejson as json import binascii -import webbrowser -import xmlrpclib import subprocess import logging -import argparse -import pwd import requests -from twisted.web import xmlrpc, server -from twisted.internet import defer, threads, reactor, error +from twisted.web import server, resource, static +from twisted.internet import defer, threads, error, reactor +from txjsonrpc.web import jsonrpc from datetime import datetime from decimal import Decimal from StringIO import StringIO from zipfile import ZipFile from urllib import urlopen +from appdirs import user_data_dir from lbrynet.core.PaymentRateManager import PaymentRateManager from lbrynet.core.server.BlobAvailabilityHandler import BlobAvailabilityHandlerFactory @@ -33,6 +31,7 @@ from lbrynet.lbrynet_daemon.LBRYPublisher import Publisher from lbrynet.core.utils import generate_id from lbrynet.lbrynet_console.LBRYSettings import LBRYSettings from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE, DEFAULT_MAX_SEARCH_RESULTS, KNOWN_DHT_NODES, DEFAULT_MAX_KEY_FEE +from lbrynet.conf import API_CONNECTION_STRING, API_PORT, API_ADDRESS from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier, download_sd_blob from lbrynet.core.Session import LBRYSession from lbrynet.core.PTCWallet import PTCWallet @@ -41,28 +40,30 @@ from lbrynet.lbryfilemanager.LBRYFileManager import LBRYFileManager from lbrynet.lbryfile.LBRYFileMetadataManager import DBLBRYFileMetadataManager, TempLBRYFileMetadataManager log = logging.getLogger(__name__) -# logging.basicConfig(level=logging.DEBUG) +BAD_REQUEST = 400 +NOT_FOUND = 404 +OK_CODE = 200 # TODO add login credentials in a conf file -# functions to add: -# TODO send credits to address # TODO alert if your copy of a lbry file is out of date with the name record -BAD_REQUEST = (400, "Bad request") -NOT_FOUND = (404, "Not found") - -OK_CODE = 200 +class Bunch: + def __init__(self, params): + self.__dict__.update(params) -class LBRYDaemon(xmlrpc.XMLRPC): +class LBRYDaemon(jsonrpc.JSONRPC): """ - LBRYnet daemon + LBRYnet daemon, a jsonrpc interface to lbry functions """ + isLeaf = True def setup(self, wallet_type, check_for_updates): def _set_vars(wallet_type, check_for_updates): + reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown) + self.fetcher = None self.current_db_revision = 1 self.run_server = True @@ -71,7 +72,8 @@ class LBRYDaemon(xmlrpc.XMLRPC): if sys.platform != "darwin": self.db_dir = os.path.join(os.path.expanduser("~"), ".lbrynet") else: - self.db_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrynet") + self.db_dir = user_data_dir("LBRY") + # self.db_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrynet") self.blobfile_dir = os.path.join(self.db_dir, "blobfiles") self.peer_port = 3333 self.dht_node_port = 4444 @@ -82,7 +84,8 @@ class LBRYDaemon(xmlrpc.XMLRPC): self.wallet_dir = os.path.join(get_path(FOLDERID.RoamingAppData, UserHandle.current), "lbrycrd") elif sys.platform == "darwin": self.download_directory = os.path.join(os.path.expanduser("~"), 'Downloads') - self.wallet_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrycrd") + # self.wallet_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrycrd") + self.wallet_dir = user_data_dir("LBRY") else: self.wallet_dir = os.path.join(os.path.expanduser("~"), ".lbrycrd") self.download_directory = os.path.join(os.path.expanduser("~"), 'Downloads') @@ -129,15 +132,13 @@ class LBRYDaemon(xmlrpc.XMLRPC): def _disp_startup(): if self.restart_message: - print self.restart_message + log.info(self.restart_message) else: - print "Started LBRYnet daemon" - print "The daemon can be shut down by running 'stop-lbrynet-daemon' in a terminal" - log.info('[' + str(datetime.now()) + '] Started lbrynet-daemon') + log.info("[" + str(datetime.now()) + "] Started lbrynet-daemon") return defer.succeed(None) - log.info('[' + str(datetime.now()) + '] Starting lbrynet-daemon') + log.info("[" + str(datetime.now()) + "] Starting lbrynet-daemon") d = defer.Deferred() d.addCallback(lambda _: _set_vars(wallet_type, check_for_updates)) @@ -160,6 +161,9 @@ class LBRYDaemon(xmlrpc.XMLRPC): return defer.succeed(None) + def _initial_setup(self): + return NotImplemented + def _update(self): def _check_for_updater(): if os.path.isdir("/Applications/LBRY Updater.app"): @@ -323,7 +327,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): return dl def _shutdown(self): - print 'Closing lbrynet session' + log.info("Closing lbrynet session") d = self._stop_server() if self.session is not None: d.addCallback(lambda _: self.session.shut_down()) @@ -339,7 +343,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): return defer.succeed(None) def _setup_data_directory(self): - print "Loading databases..." + log.info("Loading databases...") if self.created_data_dir: db_revision = open(os.path.join(self.db_dir, "db_revision"), mode='w') db_revision.write(str(self.current_db_revision)) @@ -356,7 +360,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): old_revision = int(open(db_revision_file).read().strip()) if old_revision < self.current_db_revision: from lbrynet.db_migrator import dbmigrator - print "Upgrading your databases..." + log.info("Upgrading your databases...") d = threads.deferToThread(dbmigrator.migrate_db, self.db_dir, old_revision, self.current_db_revision) def print_success(old_dirs): @@ -367,7 +371,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): success_string += old_dir if i + 1 < len(old_dir): success_string += ", " - print success_string + log.info(success_string) d.addCallback(print_success) return d @@ -396,7 +400,10 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = self.lbry_file_metadata_manager.setup() def set_lbry_file_manager(): - self.lbry_file_manager = LBRYFileManager(self.session, self.lbry_file_metadata_manager, self.sd_identifier) + self.lbry_file_manager = LBRYFileManager(self.session, + self.lbry_file_metadata_manager, + self.sd_identifier, + delete_data=True) return self.lbry_file_manager.setup() d.addCallback(lambda _: set_lbry_file_manager()) @@ -407,12 +414,11 @@ class LBRYDaemon(xmlrpc.XMLRPC): def get_default_data_rate(): d = self.settings.get_default_data_payment_rate() d.addCallback(lambda rate: {"default_data_payment_rate": rate if rate is not None else - MIN_BLOB_DATA_PAYMENT_RATE}) + MIN_BLOB_DATA_PAYMENT_RATE}) return d def get_wallet(): if self.wallet_type == "lbrycrd": - print "Using lbrycrd wallet" log.info("Using lbrycrd wallet") lbrycrdd_path = None if self.start_lbrycrdd is True: @@ -422,11 +428,9 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = defer.succeed(LBRYcrdWallet(self.db_dir, wallet_dir=self.wallet_dir, wallet_conf=self.lbrycrd_conf, lbrycrdd_path=lbrycrdd_path)) elif self.wallet_type == "lbryum": - print "Using lbryum wallet" log.info("Using lbryum wallet") d = defer.succeed(LBRYumWallet(self.db_dir)) elif self.wallet_type == "ptc": - print "Using PTC wallet" log.info("Using PTC wallet") d = defer.succeed(PTCWallet(self.db_dir)) else: @@ -509,7 +513,6 @@ class LBRYDaemon(xmlrpc.XMLRPC): for line in conf: if len(line.strip()) and line.strip()[0] != "#": self.lbrycrdd_path = line.strip() - print self.lbrycrdd_path d.addCallback(load_lbrycrdd_path) return d @@ -535,13 +538,13 @@ class LBRYDaemon(xmlrpc.XMLRPC): def _download_name(self, name): def _disp_file(file): - print '[' + str(datetime.now()) + ']' + ' Already downloaded: ' + str(file.stream_hash) + log.info("[" + str(datetime.now()) + "] Already downloaded: " + str(file.stream_hash)) d = self._path_from_lbry_file(file) return d def _get_stream(name): def _disp(stream): - print '[' + str(datetime.now()) + ']' + ' Start stream: ' + stream['stream_hash'] + log.info("[" + str(datetime.now()) + "] Start stream: " + stream['stream_hash']) return stream d = self.session.wallet.get_stream_info_for_name(name) @@ -556,12 +559,11 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = self._check_history(name) d.addCallback(lambda lbry_file: _get_stream(name) if not lbry_file else _disp_file(lbry_file)) d.addCallback(lambda _: self._check_history(name)) - d.addCallback(lambda lbry_file: (OK_CODE, {'stream_hash': lbry_file.stream_hash, - 'path': os.path.join(self.download_directory, - lbry_file.file_name)}) - if lbry_file else NOT_FOUND) - d.addErrback(lambda _: NOT_FOUND) - + d.addCallback(lambda lbry_file: ({'stream_hash': lbry_file.stream_hash, + 'path': os.path.join(self.download_directory, + lbry_file.file_name)}) + if lbry_file else defer.fail(NOT_FOUND)) + d.addErrback(lambda err: defer.fail(NOT_FOUND)) return d def _resolve_name(self, name): @@ -595,11 +597,9 @@ class LBRYDaemon(xmlrpc.XMLRPC): stream_hash = info['stream_hash'] path = os.path.join(self.blobfile_dir, stream_hash) if os.path.isfile(path): - print "[" + str(datetime.now()) + "] Search for lbry_file, returning: " + stream_hash log.info("[" + str(datetime.now()) + "] Search for lbry_file, returning: " + stream_hash) return defer.succeed(_get_lbry_file(path)) else: - print "[" + str(datetime.now()) + "] Search for lbry_file didn't return anything" log.info("[" + str(datetime.now()) + "] Search for lbry_file didn't return anything") return defer.succeed(False) @@ -615,7 +615,6 @@ class LBRYDaemon(xmlrpc.XMLRPC): def finish_deletion(lbry_file): d = lbry_file.delete_data() d.addCallback(lambda _: _delete_stream_data(lbry_file)) - d.addCallback(lambda _: _delete_file(lbry_file)) return d def _delete_stream_data(lbry_file): @@ -623,11 +622,10 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = self.lbry_file_manager.get_count_for_stream_hash(s_h) # TODO: could possibly be a timing issue here d.addCallback(lambda c: self.stream_info_manager.delete_stream(s_h) if c == 0 else True) + d.addCallback(lambda _: os.remove(os.path.join(self.download_directory, lbry_file.file_name)) if + os.path.isfile(os.path.join(self.download_directory, lbry_file.file_name)) else defer.succeed(None)) return d - def _delete_file(lbry_file): - os.remove(os.path.join(self.download_directory, lbry_file.file_name)) - d.addCallback(lambda _: finish_deletion(lbry_file)) return d @@ -649,11 +647,9 @@ class LBRYDaemon(xmlrpc.XMLRPC): def _get_est_cost(self, name): def _check_est(d, name): if type(d.result) is float: - print '[' + str(datetime.now()) + '] Cost est for lbry://' + name + ': ' + str(d.result) + 'LBC' - log.info('[' + str(datetime.now()) + '] Cost est for lbry://' + name + ': ' + str(d.result) + 'LBC') + log.info("[" + str(datetime.now()) + "] Cost est for lbry://" + name + ": " + str(d.result) + "LBC") else: - print '[' + str(datetime.now()) + '] Timeout estimating cost for lbry://' + name + ', using key fee' - log.info('[' + str(datetime.now()) + '] Timeout estimating cost for lbry://' + name + ', using key fee') + log.info("[" + str(datetime.now()) + "] Timeout estimating cost for lbry://" + name + ", using key fee") d.cancel() return defer.succeed(None) @@ -674,17 +670,23 @@ class LBRYDaemon(xmlrpc.XMLRPC): return d - def xmlrpc_is_running(self): - if self.startup_message != "" and self.announced_startup == False: - print "Startup message:", self.startup_message - self.announced_startup = True - return self.startup_message - elif self.announced_startup: - return True - else: - return False + def _render_response(self, result, code): + return json.dumps({'result': result, 'code': code}) - def xmlrpc_get_settings(self): + def jsonrpc_is_running(self): + """ + Returns a startup message when the daemon starts, after which it will return True + """ + + if self.startup_message != "" and self.announced_startup == False: + self.announced_startup = True + return self._render_response(self.startup_message, OK_CODE) + elif self.announced_startup: + return self._render_response(True, OK_CODE) + else: + return self._render_response(False, OK_CODE) + + def jsonrpc_get_settings(self): """ Get LBRY payment settings @@ -694,74 +696,82 @@ class LBRYDaemon(xmlrpc.XMLRPC): if not self.session_settings: self.session_settings = {'data_rate': self.data_rate, 'max_key_fee': self.max_key_fee} - print '[' + str(datetime.now()) + '] Get daemon settings' - return self.session_settings + log.info("[" + str(datetime.now()) + "] Get daemon settings") + return self._render_response(self.session_settings, OK_CODE) - def xmlrpc_set_settings(self, settings): + def jsonrpc_set_settings(self, p): """ Set LBRY payment settings - @param settings dict: {'data_rate': float, 'max_key_fee': float} + @param settings: {'settings': {'data_rate': float, 'max_key_fee': float}} """ + params = Bunch(p) - self.session_settings = settings + self.session_settings = params.settings self._update_settings() - print '[' + str(datetime.now()) + '] Set daemon settings' - return 'Set' + log.info("[" + str(datetime.now()) + "] Set daemon settings") + return self._render_response(True, OK_CODE) - def xmlrpc_start_fetcher(self): + def jsonrpc_start_fetcher(self): """ - Start autofetcher + Start automatically downloading new name claims as they happen + + @return: confirmation message """ self.fetcher.start() - print '[' + str(datetime.now()) + '] Start autofetcher' log.info('[' + str(datetime.now()) + '] Start autofetcher') - return 'Started autofetching' + return self._render_response("Started autofetching claims", OK_CODE) - def xmlrpc_stop_fetcher(self): + def jsonrpc_stop_fetcher(self): """ - Stop autofetcher + Stop automatically downloading new name claims as they happen + + @return: confirmation message """ self.fetcher.stop() - print '[' + str(datetime.now()) + '] Stop autofetcher' log.info('[' + str(datetime.now()) + '] Stop autofetcher') - return 'Stopped autofetching' + return self._render_response("Stopped autofetching claims", OK_CODE) - def xmlrpc_fetcher_status(self): + def jsonrpc_fetcher_status(self): """ - Start autofetcher + Get fetcher status + + @return: True/False """ - print '[' + str(datetime.now()) + '] Get fetcher status' - return str(self.fetcher.check_if_running()) + log.info("[" + str(datetime.now()) + "] Get fetcher status") + return self._render_response(self.fetcher.check_if_running(), OK_CODE) - def xmlrpc_get_balance(self): + def jsonrpc_get_balance(self): """ Get LBC balance + + @return: balance """ - print '[' + str(datetime.now()) + '] Get balance' - return str(self.session.wallet.wallet_balance) + log.info("[" + str(datetime.now()) + "] Get balance") + return self._render_response(self.session.wallet.wallet_balance, OK_CODE) - def xmlrpc_stop(self): + def jsonrpc_stop(self): """ Stop lbrynet-daemon + + @return: shutdown message """ def _disp_shutdown(): - log.info('Shutting down lbrynet daemon') - print 'Shutting down lbrynet daemon' + log.info("Shutting down lbrynet daemon") d = self._shutdown() d.addCallback(lambda _: _disp_shutdown()) d.addCallback(lambda _: reactor.callLater(1.0, reactor.stop)) - return defer.succeed('Shutting down') + return self._render_response("Shutting down", OK_CODE) - def xmlrpc_get_lbry_files(self): + def jsonrpc_get_lbry_files(self): """ Get LBRY files @@ -783,123 +793,83 @@ class LBRYDaemon(xmlrpc.XMLRPC): r.append(json.dumps(t)) - print '[' + str(datetime.now()) + '] Get LBRY files' - return r + log.info("[" + str(datetime.now()) + "] Get LBRY files") + return self._render_response(r, OK_CODE) - def xmlrpc_resolve_name(self, name): + def jsonrpc_resolve_name(self, p): """ Resolve stream info from a LBRY uri - @param: name + @param: {'name': name to look up} @return: info for name claim """ + params = Bunch(p) def _disp(info): - print '[' + str(datetime.now()) + ']' + ' Resolved info: ' + str(info['stream_hash']) - return info + log.info("[" + str(datetime.now()) + "] Resolved info: " + info['stream_hash']) + return self._render_response(info, OK_CODE) - d = self._resolve_name(name) - d.addCallbacks(_disp, lambda _: str('UnknownNameError')) + d = self._resolve_name(params.name) + d.addCallbacks(_disp, lambda _: self._render_response('error', NOT_FOUND)) d.callback(None) return d - def xmlrpc_get(self, name): + def jsonrpc_get(self, p): """ Download stream from a LBRY uri @param: name @return: {'stream_hash': hex string, 'path': path of download} """ + params = Bunch(p) - if name: - d = self._download_name(name) + if params.name: + d = self._download_name(params.name) + d.addCallbacks(lambda message: self._render_response(message, OK_CODE), + lambda err: self._render_response('error', NOT_FOUND)) else: - d = defer.succeed(BAD_REQUEST) + d = self._render_response('error', BAD_REQUEST) return d - def xmlrpc_stop_lbry_file(self, stream_hash): + def jsonrpc_stop_lbry_file(self, p): + params = Bunch(p) + try: - lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == stream_hash][0] + lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == params.stream_hash][0] except IndexError: return defer.fail(UnknownNameError) if not lbry_file.stopped: d = self.lbry_file_manager.toggle_lbry_file_running(lbry_file) - d.addCallback(lambda _: 'Stream has been stopped') - d.addErrback(lambda err: str(err)) + d.addCallback(lambda _: self._render_response("Stream has been stopped", OK_CODE)) + d.addErrback(lambda err: self._render_response(err.getTraceback(), )) return d else: - return defer.succeed('Stream was already stopped') + return json.dumps({'result': 'Stream was already stopped'}) + + def jsonrpc_start_lbry_file(self, p): + params = Bunch(p) - def xmlrpc_start_lbry_file(self, stream_hash): try: - lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == stream_hash][0] + lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == params.stream_hash][0] except IndexError: return defer.fail(UnknownNameError) if lbry_file.stopped: d = self.lbry_file_manager.toggle_lbry_file_running(lbry_file) d.callback(None) - return defer.succeed('Stream started') + return json.dumps({'result': 'Stream started'}) else: - return defer.succeed('Stream was already running') + return json.dumps({'result': 'Stream was already running'}) - def xmlrpc_render_html(self, html): - """ - Writes html to lbry.html in the downloads directory, then opens it with the browser - - @param html: - """ - - def _make_file(html, path): - f = open(path, 'w') - f.write(html) - f.close() - return defer.succeed(None) - - def _disp_err(err): - print str(err.getTraceback()) - return err - - path = os.path.join(self.download_directory, 'lbry.html') - - d = defer.Deferred() - d.addCallback(lambda _: _make_file(html, path)) - d.addCallback(lambda _: os.chown(path, pwd.getpwuid(os.getuid()).pw_uid, pwd.getpwuid(os.getuid()).pw_gid)) - d.addCallback(lambda _: webbrowser.open('file://' + path)) - d.addErrback(_disp_err) - d.callback(None) - - return d - - def xmlrpc_render_gui(self): - """ - Opens the lbry web ui in a browser - """ - - def _disp_err(err): - print str(err.getTraceback()) - return err - - d = defer.Deferred() - if sys.platform == 'darwin': - d.addCallback(lambda _: webbrowser.get('safari').open( - "file://" + str(os.path.join(self.download_directory, "lbryio/view/page/gui.html")))) - else: - d.addCallback(lambda _: webbrowser.open( - "file://" + str(os.path.join(self.download_directory, "lbryio/view/page/gui.html")))) - d.addErrback(_disp_err) - d.callback(None) - - return d - - def xmlrpc_search_nametrie(self, search): + def jsonrpc_search_nametrie(self, p): """ Search the nametrie for claims beginning with search - @param search: - @return: + @param {'search': search string} + @return: List of search results """ + params = Bunch(p) def _clean(n): t = [] @@ -910,26 +880,6 @@ class LBRYDaemon(xmlrpc.XMLRPC): t.append([i[1][0][1], i[1][1][1], i[1][2][1]]) return t - def _parse(results): - f = [] - for chain, meta, cost_est in results: - t = {} - if 'name' in chain.keys(): - t['name'] = chain['name'] - if 'thumbnail' in meta.keys(): - t['img'] = meta['thumbnail'] - else: - t['img'] = 'File://' + str( - os.path.join(self.download_directory, "lbryio/web/img/Free-speech-flag.svg")) - if 'name' in meta.keys(): - t['title'] = meta['name'] - if 'description' in meta.keys(): - t['description'] = meta['description'] - t['cost_est'] = cost_est - f.append(t) - - return f - def resolve_claims(claims): ds = [] for claim in claims: @@ -941,148 +891,140 @@ class LBRYDaemon(xmlrpc.XMLRPC): return defer.DeferredList(ds) def _disp(results): - print '[' + str(datetime.now()) + '] Found ' + str(len(results)) + ' results' log.info('[' + str(datetime.now()) + '] Search results: ') for r in results: log.info(str(r)) - return results + return self._render_response(results, OK_CODE) - print '[' + str(datetime.now()) + '] Search nametrie: ' + search - log.info('[' + str(datetime.now()) + '] Search nametrie: ' + search) + log.info('[' + str(datetime.now()) + '] Search nametrie: ' + params.search) d = self.session.wallet.get_nametrie() - d.addCallback(lambda trie: [claim for claim in trie if claim['name'].startswith(search) and 'txid' in claim]) + d.addCallback(lambda trie: [claim for claim in trie if claim['name'].startswith(params.search) and 'txid' in claim]) d.addCallback(lambda claims: claims[:self.max_search_results]) d.addCallback(resolve_claims) d.addCallback(_clean) - d.addCallback(_parse) d.addCallback(_disp) return d - def xmlrpc_delete_lbry_file(self, file_name): + def jsonrpc_delete_lbry_file(self, p): + """ + Delete a lbry file + + @param {'file_name': string} + @return: confirmation message + """ + + params = Bunch(p) + def _disp(file_name): - print '[' + str(datetime.now()) + '] Deleted: ' + file_name - return defer.succeed('Deleted: ' + file_name) + log.info("[" + str(datetime.now()) + "] Deleted: " + file_name) + return self._render_response("Deleted: " + file_name, OK_CODE) - lbry_files = [self._delete_lbry_file(f) for f in self.lbry_file_manager.lbry_files if file_name == f.file_name] + lbry_files = [self._delete_lbry_file(f) for f in self.lbry_file_manager.lbry_files if params.file_name == f.file_name] d = defer.DeferredList(lbry_files) - d.addCallback(lambda _: _disp(file_name)) + d.addCallback(lambda _: _disp(params.file_name)) return d - def xmlrpc_check(self, name): - d = self._check_history(name) - d.addCallback(lambda lbry_file: self._path_from_lbry_file(lbry_file) if lbry_file else 'Not found') - d.addErrback(lambda err: str(err)) + def jsonrpc_publish(self, p): + """ + Make a new name claim - return d + @param: + @return: + """ + params = Bunch(p) - def xmlrpc_publish(self, metadata): - try: - metadata = json.loads(metadata) - except: - return defer.succeed(BAD_REQUEST) + metadata_fields = {"name": str, "file_path": str, "bid": float, "author": str, "title": str, + "description": str, "thumbnail": str, "key_fee": float, "key_fee_address": str, + "content_license": str} + log.info(params) + log.info(params.__dict__) - required = ['name', 'file_path', 'bid'] + for k in metadata_fields.keys(): + if k in params.__dict__.keys(): + assert isinstance(params.__dict__[k], metadata_fields[k]) + metadata_fields[k] = params.__dict__[k] + else: + metadata_fields[k] = None - for r in required: - if not r in metadata.keys(): - return defer.succeed(BAD_REQUEST) - - # if not os.path.isfile(metadata['file_path']): - # return defer.fail() - - if not isinstance(metadata['bid'], float) and metadata['bid'] > 0.0: - return defer.fail() - - name = metadata['name'] - file_path = metadata['file_path'] - bid = metadata['bid'] - - if 'title' in metadata.keys(): - title = metadata['title'] - else: - title = None - - if 'description' in metadata.keys(): - description = metadata['description'] - else: - description = None - - if 'thumbnail' in metadata.keys(): - thumbnail = metadata['thumbnail'] - else: - thumbnail = None - - if 'key_fee' in metadata.keys(): - if not float(metadata['key_fee']) == 0.0: - if not 'key_fee_address' in metadata.keys(): - return defer.fail() - key_fee = metadata['key_fee'] - else: - key_fee = 0.0 - - if 'key_fee_address' in metadata.keys(): - key_fee_address = metadata['key_fee_address'] - else: - key_fee_address = None - - if 'content_license' in metadata.keys(): - content_license = metadata['content_license'] - else: - content_license = None - - log.info('[' + str(datetime.now()) + '] Publish: ', name, file_path, bid, title, description, thumbnail, - key_fee, key_fee_address, content_license) + log.info("[" + str(datetime.now()) + "] Publish: ", metadata_fields) p = Publisher(self.session, self.lbry_file_manager, self.session.wallet) - d = p.start(name, file_path, bid, title, description, thumbnail, key_fee, key_fee_address, content_license) - d.addCallback(lambda msg: (OK_CODE, msg)) + d = p.start(metadata_fields['name'], metadata_fields['file_path'], metadata_fields['bid'], + metadata_fields['title'], metadata_fields['description'], metadata_fields['thumbnail'], + metadata_fields['key_fee'], metadata_fields['key_fee_address'], metadata_fields['content_license']) + d.addCallbacks(lambda msg: self._render_response(msg, OK_CODE), + lambda err: self._render_response(err.getTraceback(), BAD_REQUEST)) return d - def xmlrpc_abandon_name(self, txid): + def jsonrpc_abandon_name(self, p): + """ + Abandon and reclaim credits from a name claim + + @param: {'txid': string} + @return: txid + """ + params = Bunch(p) + def _disp(txid, tx): - print '[' + str(datetime.now()) + '] Spent coins from claim tx ' + txid + ' --> ' + tx - return tx + log.info("[" + str(datetime.now()) + "] Abandoned name claim tx " + txid) + return self._render_response(txid, OK_CODE) d = defer.Deferred() - d.addCallback(lambda _: self.session.wallet.abandon_name(txid)) - d.addCallback(lambda tx: _disp(txid, tx)) - d.addErrback(lambda err: str(err.getTraceback())) + d.addCallback(lambda _: self.session.wallet.abandon_name(params.txid)) + d.addCallback(lambda tx: _disp(params.txid, tx)) + d.addErrback(lambda err: self._render_response(err.getTraceback(), BAD_REQUEST)) d.callback(None) return d - def xmlrpc_get_name_claims(self): + def jsonrpc_get_name_claims(self): + """ + Get name claims + + @return: list of name claims + """ def _clean(claims): for c in claims: for k in c.keys(): if isinstance(c[k], Decimal): c[k] = float(c[k]) - return claims + return self._render_response(claims, OK_CODE) d = self.session.wallet.get_name_claims() d.addCallback(_clean) return d - def xmlrpc_get_time_behind_blockchain(self): + def jsonrpc_get_time_behind_blockchain(self): + """ + Get time behind blockchain + + @return: time behind blockchain + """ d = self.session.wallet.get_most_recent_blocktime() - d.addCallback(get_time_behind_blockchain) + d.addCallbacks(lambda result: self._render_response(result, OK_CODE), + lambda result: self._render_response(result, BAD_REQUEST)) return d - def xmlrpc_get_new_address(self): + def jsonrpc_get_new_address(self): + """ + Generate a new wallet address + + @return: new wallet address + """ def _disp(address): - print "[" + str(datetime.now()) + "] Got new wallet address: " + address - return address + log.info("[" + str(datetime.now()) + "] Got new wallet address: " + address) + return json.dumps(self._render_response(address, OK_CODE)) d = self.session.wallet.get_new_address() d.addCallback(_disp) return d - # def xmlrpc_update_name(self, metadata): + # def jsonrpc_update_name(self, metadata): # def _disp(x): # print x # return x @@ -1102,15 +1044,15 @@ class LBRYDaemon(xmlrpc.XMLRPC): # # return d - def xmlrpc_toggle_fetcher_verbose(self): + def jsonrpc_toggle_fetcher_verbose(self): if self.fetcher.verbose: self.fetcher.verbose = False else: self.fetcher.verbose = True - return self.fetcher.verbose + return self._render_response(self.fetcher.verbose, OK_CODE) - def xmlrpc_check_for_new_version(self): + def jsonrpc_check_for_new_version(self): def _check_for_updates(package): git_version = subprocess.check_output("git ls-remote " + package['git'] + " | grep HEAD | cut -f 1", shell=True) up_to_date = False @@ -1147,64 +1089,90 @@ class LBRYDaemon(xmlrpc.XMLRPC): }, } - return [_check_for_updates(package_infos[p]) for p in package_infos.keys()] + r = [_check_for_updates(package_infos[p]) for p in package_infos.keys()] + log.info("[" + str(datetime.now()) + "] Check for new version: " + json.dumps(r)) + return self._render_response(r, OK_CODE) - def xmlrpc_start_status_bar_app(self): - if sys.platform == 'darwin': - if os.path.isdir("/Applications/LBRY.app"): - # subprocess.Popen("screen -dmS lbry-status bash -c 'lbrynet-daemon-status --startdaemon=False'", shell=True) - subprocess.Popen("screen -dmS lbry-status bash -c 'open /Applications/LBRY.app'") - return "Started" - else: - return "Couldn't find LBRY.app, try running the installer" - else: - return "Status bar not implemented on non OS X" - - def xmlrpc___dir__(self): + def jsonrpc___dir__(self): return ['is_running', 'get_settings', 'set_settings', 'start_fetcher', 'stop_fetcher', 'fetcher_status', 'get_balance', 'stop', 'get_lbry_files', 'resolve_name', 'get', 'search_nametrie', 'delete_lbry_file', 'check', 'publish', 'abandon_name', 'get_name_claims', 'get_time_behind_blockchain', 'get_new_address', 'toggle_fetcher_verbose', 'check_for_new_version'] -def stop(): - daemon = xmlrpclib.ServerProxy("http://localhost:7080/") - try: - status = daemon.is_running() - except: - status = False +class LBRYDaemonCommandHandler(object): + def __init__(self, command): + self._api = jsonrpc.Proxy(API_CONNECTION_STRING) + self.command = command - if status: - daemon.stop() - print "LBRYnet daemon stopped" - else: - print "LBRYnet daemon wasn't running" + def run(self, params=None): + if params: + d = self._api.callRemote(self.command, params) + else: + d = self._api.callRemote(self.command) + return d -def main(): - parser = argparse.ArgumentParser(description="Launch lbrynet-daemon") - parser.add_argument("--wallet", - help="lbrycrd or lbryum, default lbryum", - type=str, - default="lbryum") - parser.add_argument("--update", - help="True or false, default true", - type=str, - default="True") +class LBRYindex(resource.Resource): + isLeaf = False - args = parser.parse_args() - - try: - daemon = xmlrpclib.ServerProxy("http://localhost:7080") - daemon.stop() - except: - pass - - daemon = LBRYDaemon() - daemon.setup(args.wallet, args.update) - reactor.listenTCP(7080, server.Site(daemon), interface='localhost') - reactor.run() + def _delayed_render(self, request, results): + request.write(str(results)) + request.finish() -if __name__ == '__main__': - main() \ No newline at end of file + def render_GET(self, request): + def _disp(r): + log.info(r) + return "" + ''.join(r) + "" + + + d = LBRYDaemonCommandHandler('__dir__').run() + d.addCallback(lambda functions: ["" % (function, function) for function in functions]) + d.addCallback(_disp) + d.addCallbacks(lambda results: self._delayed_render(request, results), + lambda err: self._delayed_render(request, err.getTraceback())) + + return server.NOT_DONE_YET + + +class LBRYFilePage(resource.Resource): + isLeaf = False + + def _delayed_render(self, request, results): + request.write(str(results)) + request.finish() + + h = "" + + d = LBRYDaemonCommandHandler('get_lbry_files').run() + d.addCallback(lambda r: json.loads(r)['result']) + d.addCallback(lambda lbry_files: [h % (json.loads(lbry_file)['file_name'], json.loads(lbry_file)['file_name']) for lbry_file in lbry_files]) + d.addCallback(lambda r: "
%s
%s
" + ''.join(r) + "") + d.addCallbacks(lambda results: self._delayed_render(request, results), + lambda err: self._delayed_render(request, err.getTraceback())) + + return server.NOT_DONE_YET + + +class LBRYDaemonWeb(resource.Resource): + isLeaf = False + + def _delayed_render(self, request, results): + request.write(str(results)) + request.setResponseCode(json.loads(results)['code']) + request.finish() + + def render_GET(self, request): + func = request.args['function'][0] + del request.args['function'] + + p = {} + for k in request.args.keys(): + p[k] = request.args[k][0] + + d = LBRYDaemonCommandHandler(func).run(p) + d.addCallbacks(lambda results: self._delayed_render(request, results), + lambda err: self._delayed_render(request, json.dumps({'message': err.getTraceback(), 'code': BAD_REQUEST}))) + + return server.NOT_DONE_YET \ No newline at end of file diff --git a/lbrynet/lbrynet_daemon/LBRYDaemonControl.py b/lbrynet/lbrynet_daemon/LBRYDaemonControl.py new file mode 100644 index 000000000..4041993eb --- /dev/null +++ b/lbrynet/lbrynet_daemon/LBRYDaemonControl.py @@ -0,0 +1,51 @@ +import argparse +import logging + +from twisted.web import server +from twisted.internet import reactor, defer +from jsonrpc.proxy import JSONRPCProxy + +from lbrynet.lbrynet_daemon.LBRYDaemon import LBRYDaemon, LBRYindex, LBRYDaemonWeb, LBRYFilePage +from lbrynet.conf import API_CONNECTION_STRING, API_INTERFACE, API_ADDRESS, API_PORT, DEFAULT_WALLET + +log = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + + +def stop(): + def _disp_shutdown(): + log.info("Shutting down lbrynet-daemon from command line") + + def _disp_not_running(): + log.info("Attempt to shut down lbrynet-daemon from command line when daemon isn't running") + + d = defer.Deferred(None) + d.addCallback(lambda _: JSONRPCProxy.from_url(API_CONNECTION_STRING).stop()) + d.addCallbacks(lambda _: _disp_shutdown(), lambda _: _disp_not_running()) + d.callback(None) + + +def start(): + parser = argparse.ArgumentParser(description="Launch lbrynet-daemon") + parser.add_argument("--wallet", + help="lbrycrd or lbryum, default lbryum", + type=str, + default=DEFAULT_WALLET) + parser.add_argument("--update", + help="True or false, default true", + type=str, + default="True") + + log.info("Starting lbrynet-daemon from command line") + + args = parser.parse_args() + daemon = LBRYDaemon() + daemon.setup(args.wallet, args.update) + + root = LBRYindex() + root.putChild("", root) + root.putChild("webapi", LBRYDaemonWeb()) + root.putChild(API_ADDRESS, daemon) + root.putChild("myfiles", LBRYFilePage()) + reactor.listenTCP(API_PORT, server.Site(root), interface=API_INTERFACE) + reactor.run() diff --git a/lbrynet/lbrynet_daemon/LBRYDownloader.py b/lbrynet/lbrynet_daemon/LBRYDownloader.py index c5bfea81f..a4cb2a980 100644 --- a/lbrynet/lbrynet_daemon/LBRYDownloader.py +++ b/lbrynet/lbrynet_daemon/LBRYDownloader.py @@ -49,13 +49,13 @@ class GetStream(object): self.stream_hash = self.stream_info['stream_hash'] else: - print 'InvalidStreamInfoError' + log.error("InvalidStreamInfoError in autofetcher: ", stream_info) raise InvalidStreamInfoError(self.stream_info) if self.key_fee > self.max_key_fee: if self.pay_key: - print "Key fee (" + str(self.key_fee) + ") above limit of " + str( - self.max_key_fee) + ", didn't download lbry://" + str(self.resolved_name) + log.info("Key fee (" + str(self.key_fee) + ") above limit of " + str( + self.max_key_fee) + ", didn't download lbry://" + str(self.resolved_name)) return defer.fail(None) else: pass @@ -78,7 +78,7 @@ class GetStream(object): reserved_points = self.wallet.reserve_points(self.key_fee_address, self.key_fee) if reserved_points is None: return defer.fail(InsufficientFundsError()) - print 'Key fee: ' + str(self.key_fee) + ' | ' + str(self.key_fee_address) + log.info("Key fee: " + str(self.key_fee) + " | " + str(self.key_fee_address)) return self.wallet.send_points_to_address(reserved_points, self.key_fee) return defer.succeed(None) @@ -89,7 +89,7 @@ class GetStream(object): downloader.start() - print "Downloading", self.stream_hash, "-->", os.path.join(downloader.download_directory, downloader.file_name) + log.info("Downloading", self.stream_hash, "-->", os.path.join(downloader.download_directory, downloader.file_name)) return d @@ -117,15 +117,16 @@ class FetcherDaemon(object): self.is_running = True self.search = LoopingCall(self._looped_search) self.search.start(1) + log.info("Starting autofetcher") else: - print "Autofetcher is already running" + log.info("Autofetcher is already running") def stop(self): if self.is_running: self.search.stop() self.is_running = False else: - print "Autofetcher isn't running, there's nothing to stop" + log.info("Autofetcher isn't running, there's nothing to stop") def check_if_running(self): if self.is_running: @@ -157,19 +158,15 @@ class FetcherDaemon(object): return d def get_new_streams_in_tx(claims, t, blockhash): - #claims = self.wallet.get_claims_for_tx(t['txid']) - # if self.first_run: - # # claims = self.rpc_conn.getclaimsfortx("96aca2c60efded5806b7336430c5987b9092ffbea9c6ed444e3bf8e008993e11") - # # claims = self.rpc_conn.getclaimsfortx("cc9c7f5225ecb38877e6ca7574d110b23214ac3556b9d65784065ad3a85b4f74") - # self.first_run = False rtn = [] if claims: for claim in claims: if claim not in self.seen: msg = "[" + str(datetime.now()) + "] New claim | lbry://" + str(claim['name']) + \ " | stream hash: " + str(json.loads(claim['value'])['stream_hash']) - print msg - log.debug(msg) + log.info(msg) + if self.verbose: + print msg rtn.append((claim['name'], t)) self.seen.append(claim) else: @@ -179,8 +176,6 @@ class FetcherDaemon(object): d.addCallback(lambda streams: defer.DeferredList( [self.wallet.get_stream_info_from_txid(name, t) for name, t in streams])) - # if len(rtn): - # return defer.DeferredList([self.wallet.get_stream_info_for_name(name, txid=t) for name, t in rtn]) return d def _download_claims(self, claims): @@ -204,12 +199,12 @@ class FetcherDaemon(object): for l in conf: if l.startswith("maxkey="): settings["maxkey"] = float(l[7:].rstrip('\n')) - print "Autofetcher using max key price of", settings["maxkey"], ", to start call start_fetcher()" + conf.close() else: - print "Autofetcher using default max key price of 0.0" - print "To change this create the file:" - print str(self.autofetcher_conf) - print "Example contents of conf file:" - print "maxkey=1.0" + conf = open(self.autofetcher_conf, "w") + conf.write("maxkey=10.0") + conf.close() + settings["maxkey"] = 10.0 + log.info("No autofetcher conf file found, making one with max key fee of 10.0") self.max_key_fee = settings["maxkey"] diff --git a/lbrynet/lbrynet_daemon/LBRYPublisher.py b/lbrynet/lbrynet_daemon/LBRYPublisher.py index 54ade2274..391985522 100644 --- a/lbrynet/lbrynet_daemon/LBRYPublisher.py +++ b/lbrynet/lbrynet_daemon/LBRYPublisher.py @@ -40,7 +40,7 @@ class Publisher(object): def _show_result(): message = "[" + str(datetime.now()) + "] Published " + self.file_name + " --> lbry://" + \ str(self.publish_name) + " with txid: " + str(self.tx_hash) - print message + log.info(message) return defer.succeed(message) self.publish_name = name @@ -122,6 +122,6 @@ class Publisher(object): else: d = defer.succeed(True) error_message = err.getErrorMessage() - print message % (str(self.file_name), str(self.publish_name), error_message) + log.error(error_message) log.error(message, str(self.file_name), str(self.publish_name), err.getTraceback()) return d diff --git a/setup.py b/setup.py index 68d476243..577a83c81 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,11 @@ #!/usr/bin/env python import ez_setup -ez_setup.use_setuptools() -from setuptools import setup, find_packages import sys +import os +from setuptools import setup, find_packages + +ez_setup.use_setuptools() console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch_lbry_console', 'lbrynet-stdin-uploader = lbrynet.lbrynet_console.LBRYStdinUploader:launch_stdin_uploader', @@ -15,8 +17,8 @@ console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch 'lbrynet-gui = lbrynet.lbrynet_gui.gui:start_gui', 'lbrynet-lookup-hosts-for-hash = lbrynet.dht_scripts:get_hosts_for_hash_in_dht', 'lbrynet-announce_hash_to_dht = lbrynet.dht_scripts:announce_hash_to_dht', - 'lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemon:main', - 'stop-lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemon:stop'] + 'lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemonControl:start', + 'stop-lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemonControl:stop'] if sys.platform == 'darwin': console_scripts.append('lbrynet-daemon-status = lbrynet.lbrynet_daemon.LBRYOSXStatusBar:main') @@ -25,7 +27,9 @@ if sys.platform == 'darwin': setup(name='lbrynet', version='0.0.4', packages=find_packages(), - install_requires=['six>=1.9.0', 'pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', 'leveldb', 'lbryum'], + install_requires=['six>=1.9.0', 'pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', + 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', + 'leveldb', 'lbryum'], entry_points={'console_scripts': console_scripts}, data_files=[ ('lbrynet/lbrynet_console/plugins', @@ -47,4 +51,4 @@ setup(name='lbrynet', ) ], dependency_links=['https://github.com/lbryio/lbryum/tarball/master/#egg=lbryum'], - ) \ No newline at end of file + ) From 36e299b4cfd366aa7586dc0bc78ff76194b95e6c Mon Sep 17 00:00:00 2001 From: Jack Date: Thu, 17 Mar 2016 00:44:04 -0400 Subject: [PATCH 07/32] fix files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -don’t automatically remove files that can’t be found from LBRYFileManager -add timeout to GetStream --- lbrynet/core/LBRYcrdWallet.py | 10 ++- lbrynet/lbryfilemanager/LBRYFileManager.py | 50 +++++++------- lbrynet/lbrynet_daemon/LBRYDaemon.py | 80 +++++++++++++++------- lbrynet/lbrynet_daemon/LBRYDownloader.py | 47 +++++++++---- lbrynet/lbrynet_daemon/LBRYPublisher.py | 11 ++- 5 files changed, 127 insertions(+), 71 deletions(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 0d8e48a47..20cd5ffa2 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -297,8 +297,8 @@ class LBRYWallet(object): except (ValueError, TypeError): return Failure(InvalidStreamInfoError(name)) known_fields = ['stream_hash', 'name', 'description', 'key_fee', 'key_fee_address', 'thumbnail', - 'content_license', 'sources', 'fee'] - known_sources = ['lbry_sd_hash'] + 'content_license', 'sources', 'fee', 'author'] + known_sources = ['lbry_sd_hash', 'btih', 'url'] known_fee_types = {'LBC': ['amount', 'address']} for field in known_fields: if field in value_dict: @@ -334,7 +334,7 @@ class LBRYWallet(object): return Failure(UnknownNameError(name)) def claim_name(self, name, sd_hash, amount, description=None, key_fee=None, - key_fee_address=None, thumbnail=None, content_license=None): + key_fee_address=None, thumbnail=None, content_license=None, author=None, sources=None): value = {"sources": {'lbry_sd_hash': sd_hash}} if description is not None: value['description'] = description @@ -344,6 +344,10 @@ class LBRYWallet(object): value['thumbnail'] = thumbnail if content_license is not None: value['content_license'] = content_license + if author is not None: + value['author'] = author + if sources is not None: + value['sources'] = sources d = self._send_name_claim(name, json.dumps(value), amount) diff --git a/lbrynet/lbryfilemanager/LBRYFileManager.py b/lbrynet/lbryfilemanager/LBRYFileManager.py index f741558dc..59f972df3 100644 --- a/lbrynet/lbryfilemanager/LBRYFileManager.py +++ b/lbrynet/lbryfilemanager/LBRYFileManager.py @@ -34,8 +34,8 @@ class LBRYFileManager(object): self.sd_identifier = sd_identifier self.lbry_files = [] self.sql_db = None - self.delete_data = delete_data - self.check_exists_loop = LoopingCall(self.check_files_exist) + # self.delete_data = delete_data + # self.check_exists_loop = LoopingCall(self.check_files_exist) if sys.platform.startswith("darwin"): self.download_directory = os.path.join(os.path.expanduser("~"), 'Downloads') else: @@ -43,34 +43,34 @@ class LBRYFileManager(object): log.debug("Download directory for LBRYFileManager: %s", str(self.download_directory)) def setup(self): - self.check_exists_loop.start(10) + # self.check_exists_loop.start(10) d = self._open_db() d.addCallback(lambda _: self._add_to_sd_identifier()) d.addCallback(lambda _: self._start_lbry_files()) return d - def check_files_exist(self): - def _disp(deleted_files): - if deleted_files[0][0]: - for file in bad_files: - log.info("[" + str(datetime.now()) + "] Detected " + file.file_name + " was deleted, removing from file manager") - - def _delete_stream_data(lbry_file): - s_h = lbry_file.stream_hash - d = self.get_count_for_stream_hash(s_h) - # TODO: could possibly be a timing issue here - d.addCallback(lambda c: self.stream_info_manager.delete_stream(s_h) if c == 0 else True) - return d - - bad_files = [lbry_file for lbry_file in self.lbry_files - if lbry_file.completed == True and - os.path.isfile(os.path.join(self.download_directory, lbry_file.file_name)) == False] - d = defer.DeferredList([self.delete_lbry_file(lbry_file) for lbry_file in bad_files], consumeErrors=True) - d.addCallback(lambda files: _disp(files) if len(files) else defer.succeed(None)) - - if self.delete_data: - d2 = defer.DeferredList([_delete_stream_data(lbry_file) for lbry_file in bad_files], consumeErrors=True) + # def check_files_exist(self): + # def _disp(deleted_files): + # if deleted_files[0][0]: + # for file in bad_files: + # log.info("[" + str(datetime.now()) + "] Detected " + file.file_name + " was deleted, removing from file manager") + # + # def _delete_stream_data(lbry_file): + # s_h = lbry_file.stream_hash + # d = self.get_count_for_stream_hash(s_h) + # # TODO: could possibly be a timing issue here + # d.addCallback(lambda c: self.stream_info_manager.delete_stream(s_h) if c == 0 else True) + # return d + # + # bad_files = [lbry_file for lbry_file in self.lbry_files + # if lbry_file.completed == True and + # os.path.isfile(os.path.join(self.download_directory, lbry_file.file_name)) == False] + # d = defer.DeferredList([self.delete_lbry_file(lbry_file) for lbry_file in bad_files], consumeErrors=True) + # d.addCallback(lambda files: _disp(files) if len(files) else defer.succeed(None)) + # + # if self.delete_data: + # d2 = defer.DeferredList([_delete_stream_data(lbry_file) for lbry_file in bad_files], consumeErrors=True) def get_lbry_file_status(self, lbry_file): return self._get_lbry_file_status(lbry_file.rowid) @@ -180,7 +180,7 @@ class LBRYFileManager(object): return defer.fail(Failure(ValueError("Could not find that LBRY file"))) def stop(self): - self.check_exists_loop.stop() + # self.check_exists_loop.stop() ds = [] diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 67b5c8c9b..a3ba38900 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -6,10 +6,14 @@ import binascii import subprocess import logging import requests +# import rumps +# import httplib2 from twisted.web import server, resource, static from twisted.internet import defer, threads, error, reactor from txjsonrpc.web import jsonrpc +from jsonrpc.proxy import JSONRPCProxy + from datetime import datetime from decimal import Decimal from StringIO import StringIO @@ -537,10 +541,10 @@ class LBRYDaemon(jsonrpc.JSONRPC): return defer.succeed(True) def _download_name(self, name): - def _disp_file(file): - log.info("[" + str(datetime.now()) + "] Already downloaded: " + str(file.stream_hash)) - d = self._path_from_lbry_file(file) - return d + def _disp_file(f): + file_path = os.path.join(self.download_directory, f.file_name) + log.info("[" + str(datetime.now()) + "] Already downloaded: " + str(f.stream_hash) + " --> " + file_path) + return defer.succeed(f) def _get_stream(name): def _disp(stream): @@ -558,12 +562,9 @@ class LBRYDaemon(jsonrpc.JSONRPC): d = self._check_history(name) d.addCallback(lambda lbry_file: _get_stream(name) if not lbry_file else _disp_file(lbry_file)) - d.addCallback(lambda _: self._check_history(name)) - d.addCallback(lambda lbry_file: ({'stream_hash': lbry_file.stream_hash, - 'path': os.path.join(self.download_directory, - lbry_file.file_name)}) - if lbry_file else defer.fail(NOT_FOUND)) + d.addCallback(lambda _: self._path_from_name(name)) d.addErrback(lambda err: defer.fail(NOT_FOUND)) + return d def _resolve_name(self, name): @@ -586,12 +587,19 @@ class LBRYDaemon(jsonrpc.JSONRPC): f = open(path, 'r') l = json.loads(f.read()) f.close() + file_name = l['stream_name'].decode('hex') - lbry_file = [file for file in self.lbry_file_manager.lbry_files if file.stream_name == file_name] - if lbry_file: - return lbry_file[0] + for lbry_file in self.lbry_file_manager.lbry_files: + if lbry_file.stream_name == file_name: + if sys.platform == "darwin": + if os.path.isfile(os.path.join(self.download_directory, lbry_file.stream_name)): + return lbry_file + else: + return False + else: + return lbry_file else: - return None + return False def _check(info): stream_hash = info['stream_hash'] @@ -604,7 +612,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): return defer.succeed(False) d = self._resolve_name(name) - d.addCallbacks(_check, lambda _: False) + d.addCallback(_check) d.callback(None) return d @@ -633,7 +641,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): d = self._check_history(name) d.addCallback(lambda lbry_file: {'stream_hash': lbry_file.stream_hash, 'path': os.path.join(self.download_directory, lbry_file.file_name)} - if lbry_file else defer.fail(UnknownNameError)) + if lbry_file else defer.fail(UnknownNameError)) return d def _path_from_lbry_file(self, lbry_file): @@ -673,6 +681,11 @@ class LBRYDaemon(jsonrpc.JSONRPC): def _render_response(self, result, code): return json.dumps({'result': result, 'code': code}) + # def _log_to_slack(self, msg): + # URL = "https://hooks.slack.com/services/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" + # h = httplib2.Http() + # h.request(URL, 'POST', json.dumps({"text": msg}), headers={'Content-Type': 'application/json'}) + def jsonrpc_is_running(self): """ Returns a startup message when the daemon starts, after which it will return True @@ -722,6 +735,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): self.fetcher.start() log.info('[' + str(datetime.now()) + '] Start autofetcher') + # self._log_to_slack('[' + str(datetime.now()) + '] Start autofetcher') return self._render_response("Started autofetching claims", OK_CODE) def jsonrpc_stop_fetcher(self): @@ -829,6 +843,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): lambda err: self._render_response('error', NOT_FOUND)) else: d = self._render_response('error', BAD_REQUEST) + return d def jsonrpc_stop_lbry_file(self, p): @@ -933,27 +948,40 @@ class LBRYDaemon(jsonrpc.JSONRPC): @param: @return: """ + params = Bunch(p) - metadata_fields = {"name": str, "file_path": str, "bid": float, "author": str, "title": str, - "description": str, "thumbnail": str, "key_fee": float, "key_fee_address": str, - "content_license": str} - log.info(params) - log.info(params.__dict__) + metadata_fields = {"name": unicode, "file_path": unicode, "bid": float, "author": unicode, "title": unicode, + "description": unicode, "thumbnail": unicode, "key_fee": float, "key_fee_address": unicode, + "content_license": unicode, "sources": dict} for k in metadata_fields.keys(): if k in params.__dict__.keys(): - assert isinstance(params.__dict__[k], metadata_fields[k]) - metadata_fields[k] = params.__dict__[k] + if isinstance(params.__dict__[k], metadata_fields[k]): + if type(params.__dict__[k]) == unicode: + metadata_fields[k] = str(params.__dict__[k]) + else: + metadata_fields[k] = params.__dict__[k] + else: + metadata_fields[k] = None else: metadata_fields[k] = None log.info("[" + str(datetime.now()) + "] Publish: ", metadata_fields) p = Publisher(self.session, self.lbry_file_manager, self.session.wallet) - d = p.start(metadata_fields['name'], metadata_fields['file_path'], metadata_fields['bid'], - metadata_fields['title'], metadata_fields['description'], metadata_fields['thumbnail'], - metadata_fields['key_fee'], metadata_fields['key_fee_address'], metadata_fields['content_license']) + d = p.start(name=metadata_fields['name'], + file_path=metadata_fields['file_path'], + bid=metadata_fields['bid'], + title=metadata_fields['title'], + description=metadata_fields['description'], + thumbnail=metadata_fields['thumbnail'], + key_fee=metadata_fields['key_fee'], + key_fee_address=metadata_fields['key_fee_address'], + content_license=metadata_fields['content_license'], + author=metadata_fields['author'], + sources=metadata_fields['sources']) + d.addCallbacks(lambda msg: self._render_response(msg, OK_CODE), lambda err: self._render_response(err.getTraceback(), BAD_REQUEST)) @@ -1175,4 +1203,4 @@ class LBRYDaemonWeb(resource.Resource): d.addCallbacks(lambda results: self._delayed_render(request, results), lambda err: self._delayed_render(request, json.dumps({'message': err.getTraceback(), 'code': BAD_REQUEST}))) - return server.NOT_DONE_YET \ No newline at end of file + return server.NOT_DONE_YET diff --git a/lbrynet/lbrynet_daemon/LBRYDownloader.py b/lbrynet/lbrynet_daemon/LBRYDownloader.py index a4cb2a980..fc1636d46 100644 --- a/lbrynet/lbrynet_daemon/LBRYDownloader.py +++ b/lbrynet/lbrynet_daemon/LBRYDownloader.py @@ -13,7 +13,8 @@ log = logging.getLogger(__name__) class GetStream(object): - def __init__(self, sd_identifier, session, wallet, lbry_file_manager, max_key_fee, pay_key=True, data_rate=0.5): + def __init__(self, sd_identifier, session, wallet, lbry_file_manager, max_key_fee, pay_key=True, data_rate=0.5, + timeout=30): self.wallet = wallet self.resolved_name = None self.description = None @@ -30,8 +31,25 @@ class GetStream(object): self.max_key_fee = max_key_fee self.stream_info = None self.stream_info_manager = None + self.d = defer.Deferred(None) + self.timeout = timeout + self.timeout_counter = 0 + self.download_path = None + self.checker = LoopingCall(self.check_status) + def check_status(self): + self.timeout_counter += 1 + + if self.download_path and os.path.isfile(self.download_path): + self.checker.stop() + return defer.succeed(True) + + elif self.timeout_counter >= self.timeout: + log.info("Timeout downloading " + str(self.stream_info)) + self.checker.stop() + self.d.cancel() + def start(self, stream_info): self.stream_info = stream_info if 'stream_hash' in self.stream_info.keys(): @@ -60,17 +78,18 @@ class GetStream(object): else: pass - d = defer.Deferred(None) - d.addCallback(lambda _: download_sd_blob(self.session, self.stream_hash, self.payment_rate_manager)) - d.addCallback(self.sd_identifier.get_metadata_for_sd_blob) - d.addCallback(lambda metadata: (next(factory for factory in metadata.factories if isinstance(factory, ManagedLBRYFileDownloaderFactory)), metadata)) - d.addCallback(lambda (factory, metadata): factory.make_downloader(metadata, [self.data_rate, True], self.payment_rate_manager)) - d.addErrback(lambda err: err.trap(defer.CancelledError)) - d.addErrback(lambda err: log.error("An exception occurred attempting to load the stream descriptor: %s", err.getTraceback())) - d.addCallback(self._start_download) - d.callback(None) + self.checker.start(1) - return d + self.d.addCallback(lambda _: download_sd_blob(self.session, self.stream_hash, self.payment_rate_manager)) + self.d.addCallback(self.sd_identifier.get_metadata_for_sd_blob) + self.d.addCallback(lambda metadata: (next(factory for factory in metadata.factories if isinstance(factory, ManagedLBRYFileDownloaderFactory)), metadata)) + self.d.addCallback(lambda (factory, metadata): factory.make_downloader(metadata, [self.data_rate, True], self.payment_rate_manager)) + self.d.addErrback(lambda err: err.trap(defer.CancelledError)) + self.d.addErrback(lambda err: log.error("An exception occurred attempting to load the stream descriptor: %s", err.getTraceback())) + self.d.addCallback(self._start_download) + self.d.callback(None) + + return self.d def _start_download(self, downloader): def _pay_key_fee(): @@ -87,9 +106,9 @@ class GetStream(object): else: d = defer.Deferred() - downloader.start() - - log.info("Downloading", self.stream_hash, "-->", os.path.join(downloader.download_directory, downloader.file_name)) + self.download_path = os.path.join(downloader.download_directory, downloader.file_name) + d.addCallback(lambda _: downloader.start()) + d.addCallback(lambda _: log.info("Downloading " + str(self.stream_hash) + " --> " + str(self.download_path))) return d diff --git a/lbrynet/lbrynet_daemon/LBRYPublisher.py b/lbrynet/lbrynet_daemon/LBRYPublisher.py index 391985522..ea7c015a3 100644 --- a/lbrynet/lbrynet_daemon/LBRYPublisher.py +++ b/lbrynet/lbrynet_daemon/LBRYPublisher.py @@ -33,9 +33,11 @@ class Publisher(object): self.sd_hash = None self.tx_hash = None self.content_license = None + self.author = None + self.sources = None def start(self, name, file_path, bid, title=None, description=None, thumbnail=None, - key_fee=None, key_fee_address=None, content_license=None): + key_fee=None, key_fee_address=None, content_license=None, author=None, sources=None): def _show_result(): message = "[" + str(datetime.now()) + "] Published " + self.file_name + " --> lbry://" + \ @@ -52,6 +54,8 @@ class Publisher(object): self.key_fee = key_fee self.key_fee_address = key_fee_address self.content_license = content_license + self.author = author + self.sources = sources d = self._check_file_path(self.file_path) d.addCallback(lambda _: create_lbry_file(self.session, self.lbry_file_manager, @@ -104,10 +108,11 @@ class Publisher(object): return d def _claim_name(self): - d = self.wallet.claim_name(self.publish_name, self.sd_hash, self.bid_amount, + d = self.wallet.claim_name(self.publish_name, {'sd_hash': self.sd_hash}, self.bid_amount, description=self.description, key_fee=self.key_fee, key_fee_address=self.key_fee_address, thumbnail=self.thumbnail, - content_license=self.content_license) + content_license=self.content_license, author=self.author, + sources=self.sources) def set_tx_hash(tx_hash): self.tx_hash = tx_hash From 02bde900d60a789a90a83f1e02b8140fb8ca6283 Mon Sep 17 00:00:00 2001 From: Jack Date: Thu, 17 Mar 2016 10:19:36 -0400 Subject: [PATCH 08/32] update daemon and console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -don’t start console if daemon is running, display a message alerting user -move os x data directory to match app -add timeout parameter to get function --- lbrynet/conf.py | 4 +- lbrynet/lbrynet_console/LBRYConsole.py | 55 ++++++++++++++---------- lbrynet/lbrynet_daemon/LBRYDaemon.py | 11 +++-- lbrynet/lbrynet_daemon/LBRYDownloader.py | 8 +++- 4 files changed, 49 insertions(+), 29 deletions(-) diff --git a/lbrynet/conf.py b/lbrynet/conf.py index 8af383387..227589def 100644 --- a/lbrynet/conf.py +++ b/lbrynet/conf.py @@ -36,4 +36,6 @@ APP_NAME = "LBRY" DEFAULT_WALLET = "lbryum" API_CONNECTION_STRING = "http://%s:%i/%s" % (API_INTERFACE, API_PORT, API_ADDRESS) -PROTOCOL_PREFIX = "lbry" \ No newline at end of file +PROTOCOL_PREFIX = "lbry" + +DEFAULT_TIMEOUT = 30 \ No newline at end of file diff --git a/lbrynet/lbrynet_console/LBRYConsole.py b/lbrynet/lbrynet_console/LBRYConsole.py index d3fa39b2b..43325bc73 100644 --- a/lbrynet/lbrynet_console/LBRYConsole.py +++ b/lbrynet/lbrynet_console/LBRYConsole.py @@ -1,16 +1,21 @@ import logging -from lbrynet.core.Session import LBRYSession import os.path import argparse import requests import locale import sys + +if sys.platform == "darwin": + from appdirs import user_data_dir from yapsy.PluginManager import PluginManager from twisted.internet import defer, threads, stdio, task, error +from jsonrpc.proxy import JSONRPCProxy + +from lbrynet.core.Session import LBRYSession from lbrynet.lbrynet_console.ConsoleControl import ConsoleControl from lbrynet.lbrynet_console.LBRYSettings import LBRYSettings from lbrynet.lbryfilemanager.LBRYFileManager import LBRYFileManager -from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE # , MIN_BLOB_INFO_PAYMENT_RATE +from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE, API_CONNECTION_STRING # , MIN_BLOB_INFO_PAYMENT_RATE from lbrynet.core.utils import generate_id from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier from lbrynet.core.PaymentRateManager import PaymentRateManager @@ -461,7 +466,6 @@ class LBRYConsole(): def launch_lbry_console(): - from twisted.internet import reactor parser = argparse.ArgumentParser(description="Launch a lbrynet console") @@ -529,7 +533,7 @@ def launch_lbry_console(): created_data_dir = False if not args.data_dir: if sys.platform == "darwin": - data_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrynet") + data_dir = user_data_dir("LBRY") else: data_dir = os.path.join(os.path.expanduser("~"), ".lbrynet") else: @@ -538,28 +542,35 @@ def launch_lbry_console(): os.mkdir(data_dir) created_data_dir = True + daemon = JSONRPCProxy.from_url(API_CONNECTION_STRING) + try: + daemon.is_running() + log.info("Attempt to start lbrynet-console while lbrynet-daemon is running") + print "lbrynet-daemon is running, you must turn it off before using lbrynet-console" + print "If you're running the app, quit before starting lbrynet-console" + print "If you're running lbrynet-daemon in a terminal, run 'stop-lbrynet-daemon' to turn it off" - log_format = "(%(asctime)s)[%(filename)s:%(lineno)s] %(funcName)s(): %(message)s" - formatter = logging.Formatter(log_format) + except: + log_format = "(%(asctime)s)[%(filename)s:%(lineno)s] %(funcName)s(): %(message)s" + formatter = logging.Formatter(log_format) - logger = logging.getLogger() - logger.setLevel(logging.DEBUG) - file_handler = logging.FileHandler(os.path.join(data_dir, "console.log")) - file_handler.setFormatter(formatter) - file_handler.addFilter(logging.Filter("lbrynet")) - logger.addHandler(file_handler) + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + file_handler = logging.FileHandler(os.path.join(data_dir, "console.log")) + file_handler.setFormatter(formatter) + file_handler.addFilter(logging.Filter("lbrynet")) + logger.addHandler(file_handler) - console = LBRYConsole(peer_port, dht_node_port, bootstrap_nodes, fake_wallet=args.fake_wallet, - lbrycrd_conf=args.lbrycrd_wallet_conf, lbrycrd_dir=args.lbrycrd_wallet_dir, - use_upnp=not args.disable_upnp, data_dir=data_dir, - created_data_dir=created_data_dir, lbrycrdd_path=args.lbrycrdd_path) - d = task.deferLater(reactor, 0, console.start) + console = LBRYConsole(peer_port, dht_node_port, bootstrap_nodes, fake_wallet=args.fake_wallet, + lbrycrd_conf=args.lbrycrd_wallet_conf, lbrycrd_dir=args.lbrycrd_wallet_dir, + use_upnp=not args.disable_upnp, data_dir=data_dir, + created_data_dir=created_data_dir, lbrycrdd_path=args.lbrycrdd_path) - d.addErrback(lambda _: reactor.stop()) - - reactor.addSystemEventTrigger('before', 'shutdown', console.shut_down) - reactor.run() + d = task.deferLater(reactor, 0, console.start) + d.addErrback(lambda _: reactor.stop()) + reactor.addSystemEventTrigger('before', 'shutdown', console.shut_down) + reactor.run() if __name__ == "__main__": - launch_lbry_console() \ No newline at end of file + launch_lbry_console() diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index a3ba38900..e3b9a437b 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -35,7 +35,7 @@ from lbrynet.lbrynet_daemon.LBRYPublisher import Publisher from lbrynet.core.utils import generate_id from lbrynet.lbrynet_console.LBRYSettings import LBRYSettings from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE, DEFAULT_MAX_SEARCH_RESULTS, KNOWN_DHT_NODES, DEFAULT_MAX_KEY_FEE -from lbrynet.conf import API_CONNECTION_STRING, API_PORT, API_ADDRESS +from lbrynet.conf import API_CONNECTION_STRING, API_PORT, API_ADDRESS, DEFAULT_TIMEOUT from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier, download_sd_blob from lbrynet.core.Session import LBRYSession from lbrynet.core.PTCWallet import PTCWallet @@ -540,7 +540,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): self.sd_identifier.add_stream_downloader_factory(LBRYFileStreamType, downloader_factory) return defer.succeed(True) - def _download_name(self, name): + def _download_name(self, name, timeout=DEFAULT_TIMEOUT): def _disp_file(f): file_path = os.path.join(self.download_directory, f.file_name) log.info("[" + str(datetime.now()) + "] Already downloaded: " + str(f.stream_hash) + " --> " + file_path) @@ -553,7 +553,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): d = self.session.wallet.get_stream_info_for_name(name) stream = GetStream(self.sd_identifier, self.session, self.session.wallet, self.lbry_file_manager, - max_key_fee=self.max_key_fee, data_rate=self.data_rate) + max_key_fee=self.max_key_fee, data_rate=self.data_rate, timeout=timeout) d.addCallback(_disp) d.addCallback(lambda stream_info: stream.start(stream_info)) d.addCallback(lambda _: self._path_from_name(name)) @@ -837,8 +837,11 @@ class LBRYDaemon(jsonrpc.JSONRPC): """ params = Bunch(p) + if 'timeout' not in p.keys(): + params.timeout = DEFAULT_TIMEOUT + if params.name: - d = self._download_name(params.name) + d = self._download_name(params.name, timeout=params.timeout) d.addCallbacks(lambda message: self._render_response(message, OK_CODE), lambda err: self._render_response('error', NOT_FOUND)) else: diff --git a/lbrynet/lbrynet_daemon/LBRYDownloader.py b/lbrynet/lbrynet_daemon/LBRYDownloader.py index fc1636d46..4552cd4af 100644 --- a/lbrynet/lbrynet_daemon/LBRYDownloader.py +++ b/lbrynet/lbrynet_daemon/LBRYDownloader.py @@ -1,20 +1,23 @@ import json import logging import os + from datetime import datetime from twisted.internet import defer from twisted.internet.task import LoopingCall + from lbrynet.core.Error import InvalidStreamInfoError, InsufficientFundsError from lbrynet.core.PaymentRateManager import PaymentRateManager from lbrynet.core.StreamDescriptor import download_sd_blob from lbrynet.lbryfilemanager.LBRYFileDownloader import ManagedLBRYFileDownloaderFactory +from lbrynet.conf import DEFAULT_TIMEOUT log = logging.getLogger(__name__) class GetStream(object): def __init__(self, sd_identifier, session, wallet, lbry_file_manager, max_key_fee, pay_key=True, data_rate=0.5, - timeout=30): + timeout=DEFAULT_TIMEOUT): self.wallet = wallet self.resolved_name = None self.description = None @@ -106,8 +109,9 @@ class GetStream(object): else: d = defer.Deferred() + downloader.start() + self.download_path = os.path.join(downloader.download_directory, downloader.file_name) - d.addCallback(lambda _: downloader.start()) d.addCallback(lambda _: log.info("Downloading " + str(self.stream_hash) + " --> " + str(self.download_path))) return d From 0200ed13416fe330e52959e95f9ed37242251350 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Thu, 17 Mar 2016 20:19:13 -0400 Subject: [PATCH 09/32] refresh wallet balance every 3 seconds instead of 60 --- lbrynet/core/LBRYcrdWallet.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 88a9686ef..4b0002181 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -67,6 +67,9 @@ class LBRYWallet(object): self.stopped = True self.manage_running = False + self._manage_count = 0 + self._balance_refresh_time = 3 + self._batch_count = 60 def start(self): @@ -93,16 +96,20 @@ class LBRYWallet(object): self.next_manage_call.cancel() self.next_manage_call = None - d = self.manage() + d = self.manage(do_full=True) d.addErrback(self.log_stop_error) d.addCallback(lambda _: self._stop()) d.addErrback(self.log_stop_error) return d - def manage(self): + def manage(self, do_full=False): log.info("Doing manage") self.next_manage_call = None have_set_manage_running = [False] + self._manage_count += 1 + if self._manage_count % self._batch_count == 0: + self._manage_count = 0 + do_full = True def check_if_manage_running(): @@ -113,6 +120,8 @@ class LBRYWallet(object): self.manage_running = True have_set_manage_running[0] = True d.callback(True) + elif do_full is False: + d.callback(False) else: task.deferLater(reactor, 1, fire_if_not_running) @@ -121,20 +130,26 @@ class LBRYWallet(object): d = check_if_manage_running() - d.addCallback(lambda _: self._check_expected_balances()) + def do_manage(): + if do_full: + d = self._check_expected_balances() + d.addCallback(lambda _: self._send_payments()) + else: + d = defer.succeed(True) - d.addCallback(lambda _: self._send_payments()) + d.addCallback(lambda _: self.get_balance()) - d.addCallback(lambda _: self.get_balance()) + def set_wallet_balance(balance): + self.wallet_balance = balance - def set_wallet_balance(balance): - self.wallet_balance = balance + d.addCallback(set_wallet_balance) + return d - d.addCallback(set_wallet_balance) + d.addCallback(lambda should_run: do_manage() if should_run else None) def set_next_manage_call(): if not self.stopped: - self.next_manage_call = reactor.callLater(60, self.manage) + self.next_manage_call = reactor.callLater(self._balance_refresh_time, self.manage) d.addCallback(lambda _: set_next_manage_call()) From 4449bf3c75a5186ffe43ce02fc8abd21f128d9b5 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Thu, 17 Mar 2016 21:55:06 -0400 Subject: [PATCH 10/32] change manage timer back to 60 seconds --- 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 4b0002181..89fd3c98a 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -69,7 +69,7 @@ class LBRYWallet(object): self.manage_running = False self._manage_count = 0 self._balance_refresh_time = 3 - self._batch_count = 60 + self._batch_count = 20 def start(self): From a68d8917703d7fb9cc351b02dae45a3067fe0c8a Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Sat, 19 Mar 2016 21:24:44 -0400 Subject: [PATCH 11/32] enable checking first run status multiple times --- lbrynet/core/LBRYcrdWallet.py | 24 +++++++++++++++++++++--- lbrynet/lbrynet_console/LBRYConsole.py | 2 +- lbrynet/lbrynet_daemon/LBRYDaemon.py | 2 +- lbrynet/lbrynet_gui/LBRYGui.py | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 89fd3c98a..be3f96b69 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -50,6 +50,10 @@ class LBRYWallet(object): """This class implements the LBRYWallet interface for the LBRYcrd payment system""" implements(ILBRYWallet) + _FIRST_RUN_UNKNOWN = 0 + _FIRST_RUN_YES = 1 + _FIRST_RUN_NO = 2 + def __init__(self, db_dir): self.db_dir = db_dir @@ -70,6 +74,7 @@ class LBRYWallet(object): self._manage_count = 0 self._balance_refresh_time = 3 self._batch_count = 20 + self._first_run = self._FIRST_RUN_UNKNOWN def start(self): @@ -419,6 +424,19 @@ class LBRYWallet(object): def get_available_balance(self): return float(self.wallet_balance - self.total_reserved_points) + def is_first_run(self): + if self._first_run == self._FIRST_RUN_UNKNOWN: + d = self._check_first_run() + + def set_first_run(is_first): + self._first_run = self._FIRST_RUN_YES if is_first else self._FIRST_RUN_NO + + d.addCallback(set_first_run) + else: + d = defer.succeed(None) + d.addCallback(lambda _: self._first_run == self._FIRST_RUN_YES) + return d + def _get_status_of_claim(self, txid, name, sd_hash): d = self.get_claims_from_tx(txid) @@ -534,7 +552,7 @@ class LBRYWallet(object): def get_name_claims(self): return defer.fail(NotImplementedError()) - def check_first_run(self): + def _check_first_run(self): return defer.fail(NotImplementedError()) def _get_raw_tx(self, txid): @@ -614,7 +632,7 @@ class LBRYcrdWallet(LBRYWallet): settings["rpc_port"] = int(l[8:].rstrip('\n')) return settings - def check_first_run(self): + def _check_first_run(self): d = self.get_balance() d.addCallback(lambda bal: threads.deferToThread(self._get_num_addresses_rpc) if bal == 0 else 2) d.addCallback(lambda num_addresses: True if num_addresses <= 1 else False) @@ -996,7 +1014,7 @@ class LBRYumWallet(LBRYWallet): func = getattr(self.cmd_runner, cmd.name) return threads.deferToThread(func) - def check_first_run(self): + def _check_first_run(self): return defer.succeed(self.first_run) def _get_raw_tx(self, txid): diff --git a/lbrynet/lbrynet_console/LBRYConsole.py b/lbrynet/lbrynet_console/LBRYConsole.py index d3fa39b2b..18bd6a8fc 100644 --- a/lbrynet/lbrynet_console/LBRYConsole.py +++ b/lbrynet/lbrynet_console/LBRYConsole.py @@ -253,7 +253,7 @@ class LBRYConsole(): return dl def check_first_run(self): - d = self.session.wallet.check_first_run() + d = self.session.wallet.is_first_run() d.addCallback(lambda is_first_run: self._do_first_run() if is_first_run else 0.0) return d diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 410da8a81..85c441826 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -460,7 +460,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): return dl def _check_first_run(self): - d = self.session.wallet.check_first_run() + d = self.session.wallet.is_first_run() d.addCallback(lambda is_first_run: self._do_first_run() if is_first_run else 0.0) return d diff --git a/lbrynet/lbrynet_gui/LBRYGui.py b/lbrynet/lbrynet_gui/LBRYGui.py index dcc20f649..3c83308a8 100644 --- a/lbrynet/lbrynet_gui/LBRYGui.py +++ b/lbrynet/lbrynet_gui/LBRYGui.py @@ -362,7 +362,7 @@ class LBRYDownloader(object): self.sd_identifier.add_stream_downloader_factory(LBRYFileStreamType, file_opener_factory) def check_first_run(self): - d = self.session.wallet.check_first_run() + d = self.session.wallet.is_first_run() d.addCallback(lambda is_first_run: self._do_first_run() if is_first_run else 0.0) return d From d36036a9fea7c02ddebb931d28207bf02518739a Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Sat, 19 Mar 2016 21:50:38 -0400 Subject: [PATCH 12/32] Tell user to be patient if it's the first run and user has no funds --- lbrynet/lbrynet_console/ControlHandlers.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lbrynet/lbrynet_console/ControlHandlers.py b/lbrynet/lbrynet_console/ControlHandlers.py index 78e53b0dd..dd01f41b2 100644 --- a/lbrynet/lbrynet_console/ControlHandlers.py +++ b/lbrynet/lbrynet_console/ControlHandlers.py @@ -783,6 +783,9 @@ class AddStream(CommandHandler): d.addCallback(get_time_behind_blockchain) d.addCallback(self._show_time_behind_blockchain_download) d.addErrback(self._log_recent_blockchain_time_error_download) + d.addCallback(lambda _: self.wallet.is_first_run()) + d.addCallback(self._show_first_run_insufficient_funds) + d.addErrback(self._log_first_run_check_error) else: log.error("An unexpected error has caused the download to stop: %s" % err.getTraceback()) log_file = get_log_file() @@ -803,6 +806,16 @@ class AddStream(CommandHandler): def _log_recent_blockchain_time_error_download(self, err): log.error("An error occurred trying to look up the most recent blocktime: %s", err.getTraceback()) + def _show_first_run_insufficient_funds(self, is_first_run): + if is_first_run: + self.console.sendLine("\nThis appears to be the first time you have run LBRY. It can take\n" + "a few minutes for your testing LBC to show up. If you haven't\n" + "received them after a few minutes, please let us know.\n\n" + "Thank you for your patience.\n\n") + + def _log_first_run_check_error(self, err): + log.error("An error occurred checking if this was the first run: %s", err.getTraceback()) + class AddStreamFromSD(AddStream): #prompt_description = "Add a stream from a stream descriptor file" From a0b75d7ada0ae756425a8fa0ccad9ae8422bd921 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Sat, 19 Mar 2016 22:30:55 -0400 Subject: [PATCH 13/32] Tell user to be patient if it's the first run and user has no funds, in two more places --- lbrynet/lbrynet_console/ControlHandlers.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lbrynet/lbrynet_console/ControlHandlers.py b/lbrynet/lbrynet_console/ControlHandlers.py index dd01f41b2..cbe5dd270 100644 --- a/lbrynet/lbrynet_console/ControlHandlers.py +++ b/lbrynet/lbrynet_console/ControlHandlers.py @@ -862,6 +862,9 @@ class AddStreamFromHash(AddStream): d.addCallback(get_time_behind_blockchain) d.addCallback(self._show_time_behind_blockchain_download) d.addErrback(self._log_recent_blockchain_time_error_download) + d.addCallback(lambda _: self.wallet.is_first_run()) + d.addCallback(self._show_first_run_insufficient_funds) + d.addErrback(self._log_first_run_check_error) d.addCallback(lambda _: self.console.sendLine("\n")) d.chainDeferred(self.finished_deferred) return @@ -1870,6 +1873,16 @@ class Publish(CommandHandler): def _log_best_blocktime_error(self, err): log.error("An error occurred checking the best time of the blockchain: %s", err.getTraceback()) + def _show_first_run_insufficient_funds(self, is_first_run): + if is_first_run: + self.console.sendLine("\nThis appears to be the first time you have run LBRY. It can take\n" + "a few minutes for your testing LBC to show up. If you haven't\n" + "received them after a few minutes, please let us know.\n\n" + "Thank you for your patience.\n\n") + + def _log_first_run_check_error(self, err): + log.error("An error occurred checking if this was the first run: %s", err.getTraceback()) + def _show_publish_error(self, err): message = "An error occurred publishing %s to %s. Error: %s." if err.check(InsufficientFundsError): @@ -1877,6 +1890,9 @@ class Publish(CommandHandler): d.addCallback(get_time_behind_blockchain) d.addCallback(self._show_time_behind_blockchain) d.addErrback(self._log_best_blocktime_error) + d.addCallback(lambda _: self.wallet.is_first_run()) + d.addCallback(self._show_first_run_insufficient_funds) + d.addErrback(self._log_first_run_check_error) error_message = "Insufficient funds" else: d = defer.succeed(True) From 246647641a43b1811672257a94eca2b1c74b7b43 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Sat, 19 Mar 2016 22:39:47 -0400 Subject: [PATCH 14/32] remove some log statements that are useless, instead log whenever balance changes --- lbrynet/core/LBRYcrdWallet.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index be3f96b69..3c0c5f03f 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -108,7 +108,6 @@ class LBRYWallet(object): return d def manage(self, do_full=False): - log.info("Doing manage") self.next_manage_call = None have_set_manage_running = [False] self._manage_count += 1 @@ -145,6 +144,8 @@ class LBRYWallet(object): d.addCallback(lambda _: self.get_balance()) def set_wallet_balance(balance): + if self.wallet_balance != balance: + log.info("Got a new balance: %s", str(balance)) self.wallet_balance = balance d.addCallback(set_wallet_balance) @@ -272,8 +273,6 @@ class LBRYWallet(object): return d def _send_payments(self): - log.info("Trying to send payments, if there are any to be sent") - payments_to_send = {} for address, points in self.queued_payments.items(): log.info("Should be sending %s points to %s", str(points), str(address)) From 5072f503c467fbaf1bb4610025b430bd514eb6e4 Mon Sep 17 00:00:00 2001 From: Jack Date: Sun, 20 Mar 2016 22:53:01 -0400 Subject: [PATCH 15/32] fix cross scripting problem add access-control-allow-origin: http://localhost:5279 --- lbrynet/lbrynet_daemon/LBRYDaemon.py | 32 +++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index e3b9a437b..1d647a917 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -11,6 +11,7 @@ import requests from twisted.web import server, resource, static from twisted.internet import defer, threads, error, reactor +from txjsonrpc import jsonrpclib from txjsonrpc.web import jsonrpc from jsonrpc.proxy import JSONRPCProxy @@ -64,6 +65,35 @@ class LBRYDaemon(jsonrpc.JSONRPC): """ isLeaf = True + def render(self, request): + request.content.seek(0, 0) + # Unmarshal the JSON-RPC data. + content = request.content.read() + parsed = jsonrpclib.loads(content) + functionPath = parsed.get("method") + args = parsed.get('params') + id = parsed.get('id') + version = parsed.get('jsonrpc') + if version: + version = int(float(version)) + elif id and not version: + version = jsonrpclib.VERSION_1 + else: + version = jsonrpclib.VERSION_PRE1 + # XXX this all needs to be re-worked to support logic for multiple + # versions... + try: + function = self._getFunction(functionPath) + except jsonrpclib.Fault, f: + self._cbRender(f, request, id, version) + else: + request.setHeader('Access-Control-Allow-Origin', ('http://localhost' + ':' + str(API_PORT))) + request.setHeader("content-type", "text/json") + d = defer.maybeDeferred(function, *args) + d.addErrback(self._ebRender, id) + d.addCallback(self._cbRender, request, id, version) + return server.NOT_DONE_YET + def setup(self, wallet_type, check_for_updates): def _set_vars(wallet_type, check_for_updates): reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown) @@ -1206,4 +1236,4 @@ class LBRYDaemonWeb(resource.Resource): d.addCallbacks(lambda results: self._delayed_render(request, results), lambda err: self._delayed_render(request, json.dumps({'message': err.getTraceback(), 'code': BAD_REQUEST}))) - return server.NOT_DONE_YET + return server.NOT_DONE_YET \ No newline at end of file From 34eaa822a01f1b28f1893b30451fb9489a87e0d8 Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 21 Mar 2016 10:12:01 -0400 Subject: [PATCH 16/32] handle null parameter --- lbrynet/lbrynet_daemon/LBRYDaemon.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 1d647a917..5838b4945 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -89,7 +89,10 @@ class LBRYDaemon(jsonrpc.JSONRPC): else: request.setHeader('Access-Control-Allow-Origin', ('http://localhost' + ':' + str(API_PORT))) request.setHeader("content-type", "text/json") - d = defer.maybeDeferred(function, *args) + if args == [{}]: + d = defer.maybeDeferred(function) + else: + d = defer.maybeDeferred(function, *args) d.addErrback(self._ebRender, id) d.addCallback(self._cbRender, request, id, version) return server.NOT_DONE_YET @@ -917,6 +920,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): @param {'search': search string} @return: List of search results """ + params = Bunch(p) def _clean(n): From 55f25c261380bbd1adec2929d15196c0aaeb8ccf Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 21 Mar 2016 12:06:19 -0400 Subject: [PATCH 17/32] consolidate search output consolidate search output into a list of dicts --- lbrynet/lbrynet_daemon/LBRYDaemon.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 5838b4945..363ce87d1 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -943,10 +943,19 @@ class LBRYDaemon(jsonrpc.JSONRPC): return defer.DeferredList(ds) def _disp(results): - log.info('[' + str(datetime.now()) + '] Search results: ') + log.info('[' + str(datetime.now()) + '] Found ' + str(len(results)) + ' search results') + consolidated_results = [] for r in results: - log.info(str(r)) - return self._render_response(results, OK_CODE) + t = {} + t.update(r[0]) + if 'name' in r[1].keys(): + r[1]['stream_name'] = r[1]['name'] + del r[1]['name'] + t.update(r[1]) + t['cost_est'] = r[2] + consolidated_results.append(t) + # log.info(str(t)) + return self._render_response(consolidated_results, OK_CODE) log.info('[' + str(datetime.now()) + '] Search nametrie: ' + params.search) From df5b889f7d26ecfaf0db1b5bdb8d07470c647746 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Mon, 21 Mar 2016 21:33:55 -0400 Subject: [PATCH 18/32] add a version to lbrynet --- lbrynet/__init__.py | 1 + setup.py | 32 +++++++++++++++++--------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lbrynet/__init__.py b/lbrynet/__init__.py index c53c52efe..38cda8bd9 100644 --- a/lbrynet/__init__.py +++ b/lbrynet/__init__.py @@ -1,4 +1,5 @@ import logging +from version import __version__ logging.getLogger(__name__).addHandler(logging.NullHandler()) \ No newline at end of file diff --git a/setup.py b/setup.py index 68d476243..8dde41775 100644 --- a/setup.py +++ b/setup.py @@ -4,6 +4,13 @@ import ez_setup ez_setup.use_setuptools() from setuptools import setup, find_packages import sys +import os + +base_dir = os.path.abspath(os.path.dirname(__file__)) + + +from lbrynet import __version__ + console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch_lbry_console', 'lbrynet-stdin-uploader = lbrynet.lbrynet_console.LBRYStdinUploader:launch_stdin_uploader', @@ -18,33 +25,28 @@ console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch 'lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemon:main', 'stop-lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemon:stop'] + if sys.platform == 'darwin': console_scripts.append('lbrynet-daemon-status = lbrynet.lbrynet_daemon.LBRYOSXStatusBar:main') +gui_data_files = ['close2.gif', 'lbry-dark-242x80.gif', 'lbry-dark-icon.xbm', 'lbry-dark-icon.ico', + 'drop_down.gif', 'show_options.gif', 'hide_options.gif', 'lbry.conf'] +gui_data_paths = [os.path.join(base_dir, 'lbrynet', 'lbrynet_gui', f) for f in gui_data_files] + setup(name='lbrynet', - version='0.0.4', - packages=find_packages(), + version='.'.join([str(x) for x in __version__]), + packages=find_packages(base_dir), install_requires=['six>=1.9.0', 'pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', 'leveldb', 'lbryum'], entry_points={'console_scripts': console_scripts}, data_files=[ ('lbrynet/lbrynet_console/plugins', [ - 'lbrynet/lbrynet_console/plugins/blindrepeater.yapsy-plugin', + os.path.join(base_dir, 'lbrynet', 'lbrynet_console', 'plugins', + 'blindrepeater.yapsy-plugin') ] ), - ('lbrynet/lbrynet_gui', - [ - 'lbrynet/lbrynet_gui/close2.gif', - 'lbrynet/lbrynet_gui/lbry-dark-242x80.gif', - 'lbrynet/lbrynet_gui/lbry-dark-icon.xbm', - 'lbrynet/lbrynet_gui/lbry-dark-icon.ico', - 'lbrynet/lbrynet_gui/drop_down.gif', - 'lbrynet/lbrynet_gui/show_options.gif', - 'lbrynet/lbrynet_gui/hide_options.gif', - 'lbrynet/lbrynet_gui/lbry.conf', - ] - ) + ('lbrynet/lbrynet_gui', gui_data_paths) ], dependency_links=['https://github.com/lbryio/lbryum/tarball/master/#egg=lbryum'], ) \ No newline at end of file From e4a30c052eba060b01e0ade14dfdbfeabfeffede Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Mon, 21 Mar 2016 21:37:15 -0400 Subject: [PATCH 19/32] put the actual version in __init__.py --- lbrynet/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lbrynet/__init__.py b/lbrynet/__init__.py index 38cda8bd9..f780625b8 100644 --- a/lbrynet/__init__.py +++ b/lbrynet/__init__.py @@ -1,5 +1,7 @@ import logging -from version import __version__ -logging.getLogger(__name__).addHandler(logging.NullHandler()) \ No newline at end of file +logging.getLogger(__name__).addHandler(logging.NullHandler()) + + +__version__ = (0, 2, 0) \ No newline at end of file From ba991b47ea18e30ad62cec1578071703953750e5 Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 22 Mar 2016 00:03:17 -0400 Subject: [PATCH 20/32] add /view to dynamically generate a video containing page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -uses UI stored in Resources folder of app -going to /view?name= will download the corresponding stream and display the file in the browser -adds default daemon settings, currently they don’t do anything, to be added to -adds missing packages to setup.py --- lbrynet/lbrynet_daemon/LBRYDaemon.py | 106 ++++++++++++++------ lbrynet/lbrynet_daemon/LBRYDaemonControl.py | 14 ++- setup.py | 2 +- 3 files changed, 87 insertions(+), 35 deletions(-) diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 363ce87d1..5dce85822 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -126,7 +126,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): else: self.wallet_dir = os.path.join(os.path.expanduser("~"), ".lbrycrd") self.download_directory = os.path.join(os.path.expanduser("~"), 'Downloads') - + self.daemon_conf = os.path.join(self.wallet_dir, 'daemon_settings.conf') self.wallet_conf = os.path.join(self.wallet_dir, "lbrycrd.conf") self.wallet_user = None self.wallet_password = None @@ -164,6 +164,14 @@ class LBRYDaemon(jsonrpc.JSONRPC): self.announced_startup = False self.search_timeout = 3.0 self.query_handlers = {} + self.default_settings = { + 'run_on_startup': False, + 'data_rate': MIN_BLOB_DATA_PAYMENT_RATE, + 'max_key_fee': 10.0, + 'default_download_directory': self.download_directory, + 'max_upload': 0.0, + 'max_download': 0.0 + } return defer.succeed(None) @@ -178,7 +186,8 @@ class LBRYDaemon(jsonrpc.JSONRPC): log.info("[" + str(datetime.now()) + "] Starting lbrynet-daemon") d = defer.Deferred() - d.addCallback(lambda _: _set_vars(wallet_type, check_for_updates)) + d.addCallback(lambda _:_set_vars(wallet_type, check_for_updates)) + d.addCallback(lambda _: self._setup_daemon_settings()) d.addCallback(lambda _: threads.deferToThread(self._setup_data_directory)) d.addCallback(lambda _: self._check_db_migration()) d.addCallback(lambda _: self._get_settings()) @@ -201,6 +210,10 @@ class LBRYDaemon(jsonrpc.JSONRPC): def _initial_setup(self): return NotImplemented + def _setup_daemon_settings(self): + self.session_settings = self.default_settings + return defer.succeed(None) + def _update(self): def _check_for_updater(): if os.path.isdir("/Applications/LBRY Updater.app"): @@ -370,9 +383,28 @@ class LBRYDaemon(jsonrpc.JSONRPC): d.addCallback(lambda _: self.session.shut_down()) return d - def _update_settings(self): - self.data_rate = self.session_settings['data_rate'] - self.max_key_fee = self.session_settings['max_key_fee'] + def _update_settings(self, settings): + if not isinstance(settings['run_on_startup'], bool): + return defer.fail() + elif not isinstance(settings['data_rate'], float): + return defer.fail() + elif not isinstance(settings['max_key_fee'], float): + return defer.fail() + elif not isinstance(settings['default_download_directory'], unicode): + return defer.fail() + elif not isinstance(settings['max_upload'], float): + return defer.fail() + elif not isinstance(settings['max_download'], float): + return defer.fail() + + self.session_settings['run_on_startup'] = settings['run_on_startup'] + self.session_settings['data_rate'] = settings['data_rate'] + self.session_settings['max_key_fee'] = settings['max_key_fee'] + self.session_settings['default_download_directory'] = settings['default_download_directory'] + self.session_settings['max_upload'] = settings['max_upload'] + self.session_settings['max_download'] = settings['max_download'] + + return defer.succeed(True) def _setup_fetcher(self): self.fetcher = FetcherDaemon(self.session, self.lbry_file_manager, self.lbry_file_metadata_manager, @@ -739,9 +771,6 @@ class LBRYDaemon(jsonrpc.JSONRPC): @return {'data_rate': float, 'max_key_fee': float} """ - if not self.session_settings: - self.session_settings = {'data_rate': self.data_rate, 'max_key_fee': self.max_key_fee} - log.info("[" + str(datetime.now()) + "] Get daemon settings") return self._render_response(self.session_settings, OK_CODE) @@ -751,10 +780,8 @@ class LBRYDaemon(jsonrpc.JSONRPC): @param settings: {'settings': {'data_rate': float, 'max_key_fee': float}} """ - params = Bunch(p) - self.session_settings = params.settings - self._update_settings() + d = self._update_settings(p) log.info("[" + str(datetime.now()) + "] Set daemon settings") return self._render_response(True, OK_CODE) @@ -1194,39 +1221,60 @@ class LBRYindex(resource.Resource): request.write(str(results)) request.finish() + def getChild(self, name, request): + if name == '': + return self + return resource.Resource.getChild(self, name, request) def render_GET(self, request): def _disp(r): log.info(r) return "
" + ''.join(r) + "" - - d = LBRYDaemonCommandHandler('__dir__').run() - d.addCallback(lambda functions: ["" % (function, function) for function in functions]) - d.addCallback(_disp) - d.addCallbacks(lambda results: self._delayed_render(request, results), - lambda err: self._delayed_render(request, err.getTraceback())) - - return server.NOT_DONE_YET + return static.File("./dist/index.html").render_GET(request) -class LBRYFilePage(resource.Resource): +class LBRYFileRender(resource.Resource): isLeaf = False + def _render_path(self, path): + return r'
' + def _delayed_render(self, request, results): request.write(str(results)) request.finish() - h = "" + def render_GET(self, request): + if 'name' in request.args.keys(): + api = jsonrpc.Proxy(API_CONNECTION_STRING) + d = api.callRemote("get", {'name': request.args['name'][0]}) + d.addCallback(lambda response: self._delayed_render(request, self._render_path(json.loads(response)['result']['path'])) + if json.loads(response)['code'] == 200 + else self._delayed_render(request, "Error")) - d = LBRYDaemonCommandHandler('get_lbry_files').run() - d.addCallback(lambda r: json.loads(r)['result']) - d.addCallback(lambda lbry_files: [h % (json.loads(lbry_file)['file_name'], json.loads(lbry_file)['file_name']) for lbry_file in lbry_files]) - d.addCallback(lambda r: "
%s
%s
" + ''.join(r) + "") - d.addCallbacks(lambda results: self._delayed_render(request, results), - lambda err: self._delayed_render(request, err.getTraceback())) + return server.NOT_DONE_YET + else: + self._delayed_render(request, "Error") + return server.NOT_DONE_YET - return server.NOT_DONE_YET + +# class LBRYFilePage(resource.Resource): +# isLeaf = False +# +# def _delayed_render(self, request, results): +# request.write(str(results)) +# request.finish() +# +# h = "" +# +# d = LBRYDaemonCommandHandler('get_lbry_files').run() +# d.addCallback(lambda r: json.loads(r)['result']) +# d.addCallback(lambda lbry_files: [h % (json.loads(lbry_file)['file_name'], json.loads(lbry_file)['file_name']) for lbry_file in lbry_files]) +# d.addCallback(lambda r: "
%s
" + ''.join(r) + "") +# d.addCallbacks(lambda results: self._delayed_render(request, results), +# lambda err: self._delayed_render(request, err.getTraceback())) +# +# return server.NOT_DONE_YET class LBRYDaemonWeb(resource.Resource): @@ -1249,4 +1297,4 @@ class LBRYDaemonWeb(resource.Resource): d.addCallbacks(lambda results: self._delayed_render(request, results), lambda err: self._delayed_render(request, json.dumps({'message': err.getTraceback(), 'code': BAD_REQUEST}))) - return server.NOT_DONE_YET \ No newline at end of file + return server.NOT_DONE_YET diff --git a/lbrynet/lbrynet_daemon/LBRYDaemonControl.py b/lbrynet/lbrynet_daemon/LBRYDaemonControl.py index 4041993eb..89b678f68 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemonControl.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemonControl.py @@ -1,11 +1,11 @@ import argparse import logging -from twisted.web import server +from twisted.web import server, static from twisted.internet import reactor, defer from jsonrpc.proxy import JSONRPCProxy -from lbrynet.lbrynet_daemon.LBRYDaemon import LBRYDaemon, LBRYindex, LBRYDaemonWeb, LBRYFilePage +from lbrynet.lbrynet_daemon.LBRYDaemon import LBRYDaemon, LBRYindex, LBRYDaemonWeb, LBRYFileRender from lbrynet.conf import API_CONNECTION_STRING, API_INTERFACE, API_ADDRESS, API_PORT, DEFAULT_WALLET log = logging.getLogger(__name__) @@ -43,9 +43,13 @@ def start(): daemon.setup(args.wallet, args.update) root = LBRYindex() - root.putChild("", root) - root.putChild("webapi", LBRYDaemonWeb()) + root.putChild("css", static.File("./css")) + root.putChild("font", static.File("./font")) + root.putChild("img", static.File("./img")) + root.putChild("js", static.File("./js")) root.putChild(API_ADDRESS, daemon) - root.putChild("myfiles", LBRYFilePage()) + root.putChild("webapi", LBRYDaemonWeb()) + root.putChild("view", LBRYFileRender()) reactor.listenTCP(API_PORT, server.Site(root), interface=API_INTERFACE) + reactor.run() diff --git a/setup.py b/setup.py index 577a83c81..b032122fb 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ setup(name='lbrynet', packages=find_packages(), install_requires=['six>=1.9.0', 'pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', - 'leveldb', 'lbryum'], + 'leveldb', 'lbryum', 'jsonrpc', 'simplejson', 'appdirs'], entry_points={'console_scripts': console_scripts}, data_files=[ ('lbrynet/lbrynet_console/plugins', From 2486ae6d3f690b1164f031483e0ab381496e352c Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 22 Mar 2016 09:40:18 -0400 Subject: [PATCH 21/32] get rid of unused updater function updater function was hacky and not the most reliable, to be replaced by app version checking --- lbrynet/lbrynet_daemon/LBRYDaemon.py | 101 +---------- .../lbrynet_daemon/scripts/restart_daemon.sh | 4 - lbrynet/lbrynet_daemon/scripts/update_lbry.sh | 50 ------ .../lbrynet_daemon/scripts/update_lbrynet.sh | 163 ------------------ 4 files changed, 3 insertions(+), 315 deletions(-) delete mode 100644 lbrynet/lbrynet_daemon/scripts/restart_daemon.sh delete mode 100755 lbrynet/lbrynet_daemon/scripts/update_lbry.sh delete mode 100755 lbrynet/lbrynet_daemon/scripts/update_lbrynet.sh diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 5dce85822..922f3be27 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -159,7 +159,6 @@ class LBRYDaemon(jsonrpc.JSONRPC): self.data_rate = MIN_BLOB_DATA_PAYMENT_RATE self.max_key_fee = DEFAULT_MAX_KEY_FEE self.max_search_results = DEFAULT_MAX_SEARCH_RESULTS - self.restart_message = "" self.startup_message = "" self.announced_startup = False self.search_timeout = 3.0 @@ -176,10 +175,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): return defer.succeed(None) def _disp_startup(): - if self.restart_message: - log.info(self.restart_message) - else: - log.info("[" + str(datetime.now()) + "] Started lbrynet-daemon") + log.info("[" + str(datetime.now()) + "] Started lbrynet-daemon") return defer.succeed(None) @@ -199,8 +195,6 @@ class LBRYDaemon(jsonrpc.JSONRPC): d.addCallback(lambda _: self._setup_lbry_file_opener()) d.addCallback(lambda _: self._setup_query_handlers()) d.addCallback(lambda _: self._setup_server()) - # d.addCallback(lambda _: self._update() if self.check_for_updates == "True" and sys.platform == "darwin" - # else defer.succeed(None)) d.addCallback(lambda _: self._setup_fetcher()) d.addCallback(lambda _: _disp_startup()) d.callback(None) @@ -208,102 +202,12 @@ class LBRYDaemon(jsonrpc.JSONRPC): return defer.succeed(None) def _initial_setup(self): - return NotImplemented + return defer.fail(NotImplementedError()) def _setup_daemon_settings(self): self.session_settings = self.default_settings return defer.succeed(None) - def _update(self): - def _check_for_updater(): - if os.path.isdir("/Applications/LBRY Updater.app"): - print "Found LBRY updater" - return defer.succeed(None) - - print "LBRY updater not found, downloading and installing..." - url = urlopen("https://rawgit.com/jackrobison/lbrynet-app/master/LBRY%20Updater.app.zip") - zipped_app = ZipFile(StringIO(url.read())) - zipped_app.extractall("/Applications") - return defer.succeed(None) - - def _update_lbrynet(): - git_version = subprocess.check_output( - "git ls-remote https://github.com/lbryio/lbry.git | grep HEAD | cut -f 1", - shell=True) - if os.path.isfile(os.path.join(self.db_dir, "lbrynet_version.txt")): - f = open(os.path.join(self.db_dir, "lbrynet_version.txt"), 'r') - current_version = f.read() - f.close() - if git_version == current_version: - print "LBRYnet installation version " + current_version[:-1] + " is up to date" - return defer.succeed(None) - print "Update LBRYnet version " + current_version[:-1] + " --> " + git_version[:-1] - self.restart_message = "Updates available" - else: - print "Update LBRYnet to version " + git_version[:-1] - self.restart_message = "Updates available" - - return defer.succeed(None) - - def _update_lbrycrdd(): - git_version = subprocess.check_output( - "git ls-remote https://github.com/jackrobison/lbrynet-app.git | grep HEAD | cut -f 1", - shell=True) - if os.path.isfile(os.path.join(self.wallet_dir, "lbry_app_version.txt")): - f = open(os.path.join(self.wallet_dir, "lbry_app_version.txt"), 'r') - current_version = f.read() - f.close() - if git_version == current_version: - print "LBRY installation version " + current_version[:-1] + " is up to date" - return defer.succeed(None) - print "Update LBRY version " + current_version[:-1] + " --> " + git_version[:-1] - self.restart_message = "Updates available" - else: - print "Update LBRY to version " + git_version[:-1] - self.restart_message = "Updates available" - - return defer.succeed(None) - - def _update_lbryum(): - git_version = subprocess.check_output( - "git ls-remote https://github.com/lbryio/lbryum.git | grep HEAD | cut -f 1", - shell=True) - if os.path.isfile(os.path.join(self.db_dir, "lbryum_version.txt")): - f = open(os.path.join(self.db_dir, "lbryum_version.txt"), 'r') - current_version = f.read() - f.close() - if git_version == current_version: - print "LBRYum installation version " + current_version[:-1] + " is up to date" - return defer.succeed(None) - print "Update LBRYum version " + current_version[:-1] + " --> " + git_version[:-1] - self.restart_message = "Updates available" - else: - print "Update LBRYum to version " + git_version[:-1] - self.restart_message = "Updates available" - - return defer.succeed(None) - - d = _check_for_updater() - d.addCallback(lambda _: _update_lbrynet()) - d.addCallback(lambda _: _update_lbrycrdd() if self.wallet_type == 'lbrycrd' else _update_lbryum()) - d.addCallback(lambda _: os.system("open /Applications/LBRY\ Updater.app &>/dev/null") if self.restart_message - else defer.succeed(None)) - d.addCallbacks(lambda _: self._restart() if self.restart_message else defer.succeed(None)) - - return defer.succeed(None) - - def _restart(self): - def _disp_shutdown(): - print 'Restarting lbrynet daemon' - return defer.succeed(None) - - # LBRY Updater.app will restart the daemon - d = self._shutdown() - d.addCallback(lambda _: _disp_shutdown()) - d.addCallback(lambda _: reactor.callLater(1.0, reactor.stop)) - - return d - def _start_server(self): if self.peer_port is not None: @@ -1106,6 +1010,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): @return: time behind blockchain """ d = self.session.wallet.get_most_recent_blocktime() + d.addCallback(get_time_behind_blockchain) d.addCallbacks(lambda result: self._render_response(result, OK_CODE), lambda result: self._render_response(result, BAD_REQUEST)) diff --git a/lbrynet/lbrynet_daemon/scripts/restart_daemon.sh b/lbrynet/lbrynet_daemon/scripts/restart_daemon.sh deleted file mode 100644 index 7353c0a20..000000000 --- a/lbrynet/lbrynet_daemon/scripts/restart_daemon.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -echo "Restarting lbrynet-daemon" -lbrynet-daemon \ No newline at end of file diff --git a/lbrynet/lbrynet_daemon/scripts/update_lbry.sh b/lbrynet/lbrynet_daemon/scripts/update_lbry.sh deleted file mode 100755 index 09177e79c..000000000 --- a/lbrynet/lbrynet_daemon/scripts/update_lbry.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh - -lbrycrd_directory="/Users/${SUDO_USER}/Library/Application Support/lbrycrd" - -current_version=$(git ls-remote https://github.com/jackrobison/lbrynet-app.git | grep HEAD | cut -f 1) - -if [ -d "$lbrycrd_directory" ]; then - if [ -f "${lbrycrd_directory}/lbry_app_version.txt" ]; then - if grep -Fxq "$current_version" "${lbrycrd_directory}/lbry_app_version.txt"; then - echo "LBRY version $current_version is up to date" - exit - fi - fi -fi - -if ! brew list berkeley-db4 &>/dev/null; then - echo "Installing berkeley-db4" - sudo -u ${SUDO_USER} brew install https://rawgit.com/jackrobison/homebrew/master/Library/Formula/berkeley-db4.rb &>/dev/null - sudo -u ${SUDO_USER} brew link --force berkeley-db4 &>/dev/null -else - echo "berkeley-db4 already installed" -fi - -tmp=$(mktemp -d) -cd $tmp - -echo "Downloading LBRY update" -git clone --depth 1 https://github.com/jackrobison/lbrynet-app.git &>/dev/null -cd lbrynet-app -unzip LBRY.app.zip &>/dev/null -unzip LBRYURIHandler.app.zip &>/dev/null -unzip LBRY\ Updater.app.zip &>/dev/null - -echo "Installing update" - -mkdir -p "$lbrycrd_directory" -echo $current_version > "${lbrycrd_directory}/lbry_app_version.txt" - -rm -rf /Applications/LBRY.app &>/dev/null -rm -rf /Applications/LBRYURIHandler.app &>/dev/null -rm -rf /Applications/LBRY\ Updater.app &>/dev/null - -mv -f LBRY.app /Applications -mv -f LBRYURIHandler.app /Applications -mv -f LBRY\ Updater.app /Applications - -echo "Cleaning up" - -cd ../../ -rm -rf $tmp \ No newline at end of file diff --git a/lbrynet/lbrynet_daemon/scripts/update_lbrynet.sh b/lbrynet/lbrynet_daemon/scripts/update_lbrynet.sh deleted file mode 100755 index fbb7d2b17..000000000 --- a/lbrynet/lbrynet_daemon/scripts/update_lbrynet.sh +++ /dev/null @@ -1,163 +0,0 @@ -#!/bin/sh - -if ! which brew &>/dev/null; then - echo "Installing brew..." - sudo -u ${SUDO_USER} ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null &>/dev/null -else - echo "Updating brew..." - sudo -u ${SUDO_USER} brew update &>/dev/null -fi - -if ! brew list mpfr &>/dev/null; then - echo "Installing mpfr..." - sudo -u ${SUDO_USER} brew install mpfr &>/dev/null -else - echo "mpfr already installed..." -fi - -if ! brew list libmpc &>/dev/null; then - echo "Installing libmpc..." - sudo -u ${SUDO_USER} brew install libmpc &>/dev/null -else - echo "libmpc already installed..." -fi - -if ! brew list openssl &>/dev/null; then - echo "Installing openssl..." - sudo -u ${SUDO_USER} brew install openssl &>/dev/null - sudo -u ${SUDO_USER} brew link --force openssl &>/dev/null -else - echo "openssl already installed..." -fi - -if ! which pip &>/dev/null; then - echo "Installing pip..." - sudo easy_install pip &>/dev/null -else - echo "pip already installed" -fi - -if ! python -c 'import gmpy' &>/dev/null; then - echo "Installing gmpy..." - sudo pip install gmpy &>/dev/null -else - echo "gmpy already installed..." -fi - -if ! python -c 'import service_identity' &>/dev/null; then - echo "Installing service_identity..." - sudo pip install service_identity &>/dev/null -else - echo "gmpy already installed..." -fi - -if ! python -c 'import rumps' &>/dev/null; then - echo "Installing rumps..." - sudo pip install rumps &>/dev/null -else - echo "rumps already installed..." -fi - -if ! python -c "import six; exit(0) if six.__version__ == '1.9.0' else exit(1)" &>/dev/null; then - echo "Installing six 1.9.0 for python..." - curl -O https://pypi.python.org/packages/source/s/six/six-1.9.0.tar.gz &>/dev/null - tar xf six-1.9.0.tar.gz &>/dev/null - cd six-1.9.0 - sudo python setup.py install &>/dev/null - cd .. - rm -rf six-1.9.0 - rm six-1.9.0.tar.gz -fi - -lbrynet_directory="/Users/${SUDO_USER}/Library/Application Support/lbrynet" -lbryum_current_version=$(git ls-remote https://github.com/lbryio/lbryum.git | grep HEAD | cut -f 1) - -if [ -d "$lbrynet_directory" ]; then - if [ -f "${lbrynet_directory}/lbryum_version.txt" ]; then - if grep -Fxq "$lbryum_current_version" "${lbrynet_directory}/lbryum_version.txt"; then - echo "LBRYum version $lbryum_current_version is up to date" - else - tmp=$(mktemp -d) - cd $tmp - - echo "Downloading LBRYum update..." - - git clone --depth 1 https://github.com/lbryio/lbryum.git &>/dev/null - cd lbryum - - echo "Installing update..." - sudo python setup.py install &>/dev/null - mkdir -p "$lbrynet_directory" - echo $lbryum_current_version > "${lbrynet_directory}/lbryum_version.txt" - - echo "Cleaning up..." - - cd ../../ - rm -rf $tmp - fi - else - tmp=$(mktemp -d) - cd $tmp - - echo "Downloading LBRYum..." - - git clone --depth 1 https://github.com/lbryio/lbryum.git &>/dev/null - cd lbryum - - echo "Installing..." - sudo python setup.py install &>/dev/null - mkdir -p "$lbrynet_directory" - echo $lbryum_current_version > "${lbrynet_directory}/lbryum_version.txt" - - echo "Cleaning up..." - - cd ../../ - rm -rf $tmp - fi -fi - -lbrynet_current_version=$(git ls-remote https://github.com/lbryio/lbry.git | grep HEAD | cut -f 1) - -if [ -d "$lbrynet_directory" ]; then - if [ -f "${lbrynet_directory}/lbrynet_version.txt" ]; then - if grep -Fxq "$lbrynet_current_version" "${lbrynet_directory}/lbrynet_version.txt"; then - echo "LBRYnet version $lbrynet_current_version is up to date" - else - tmp=$(mktemp -d) - cd $tmp - - echo "Downloading LBRYnet update" - - git clone --depth 1 https://github.com/lbryio/lbry.git &>/dev/null - cd lbry - - echo "Installing update..." - sudo python setup.py install &>/dev/null - mkdir -p "$lbrynet_directory" - echo $lbrynet_current_version > "${lbrynet_directory}/lbrynet_version.txt" - - echo "Cleaning up..." - - cd ../../ - rm -rf $tmp - fi - else - tmp=$(mktemp -d) - cd $tmp - - echo "Downloading LBRYnet..." - - git clone --depth 1 https://github.com/lbryio/lbry.git &>/dev/null - cd lbry - - echo "Installing..." - sudo python setup.py install &>/dev/null - mkdir -p "$lbrynet_directory" - echo $lbrynet_current_version > "${lbrynet_directory}/lbrynet_version.txt" - - echo "Cleaning up..." - - cd ../../ - rm -rf $tmp - fi -fi \ No newline at end of file From a55e3d8578c76b929417c16118a0a1d22d939e6e Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 22 Mar 2016 10:37:13 -0400 Subject: [PATCH 22/32] use UI downloaded to temp folder at startup --- lbrynet/lbrynet_daemon/LBRYDaemon.py | 8 +++++-- lbrynet/lbrynet_daemon/LBRYDaemonControl.py | 25 ++++++++++++++++----- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 922f3be27..84ca4478b 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -1120,6 +1120,10 @@ class LBRYDaemonCommandHandler(object): class LBRYindex(resource.Resource): + def __init__(self, ui_dir): + resource.Resource.__init__(self) + self.ui_dir = ui_dir + isLeaf = False def _delayed_render(self, request, results): @@ -1136,7 +1140,7 @@ class LBRYindex(resource.Resource): log.info(r) return "
" + ''.join(r) + "" - return static.File("./dist/index.html").render_GET(request) + return static.File(os.path.join(self.ui_dir, "index.html")).render_GET(request) class LBRYFileRender(resource.Resource): @@ -1202,4 +1206,4 @@ class LBRYDaemonWeb(resource.Resource): d.addCallbacks(lambda results: self._delayed_render(request, results), lambda err: self._delayed_render(request, json.dumps({'message': err.getTraceback(), 'code': BAD_REQUEST}))) - return server.NOT_DONE_YET + return server.NOT_DONE_YET \ No newline at end of file diff --git a/lbrynet/lbrynet_daemon/LBRYDaemonControl.py b/lbrynet/lbrynet_daemon/LBRYDaemonControl.py index 89b678f68..ce6540d0c 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemonControl.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemonControl.py @@ -1,5 +1,12 @@ import argparse import logging +import tempfile +import os +import shutil + +from StringIO import StringIO +from zipfile import ZipFile +from urllib import urlopen from twisted.web import server, static from twisted.internet import reactor, defer @@ -38,18 +45,26 @@ def start(): log.info("Starting lbrynet-daemon from command line") + tmpdir = tempfile.mkdtemp() + url = urlopen("https://rawgit.com/lbryio/lbry-web-ui/master/dist.zip") + z = ZipFile(StringIO(url.read())) + z.extractall(tmpdir) + + args = parser.parse_args() daemon = LBRYDaemon() daemon.setup(args.wallet, args.update) - root = LBRYindex() - root.putChild("css", static.File("./css")) - root.putChild("font", static.File("./font")) - root.putChild("img", static.File("./img")) - root.putChild("js", static.File("./js")) + root = LBRYindex(tmpdir) + root.putChild("css", static.File(os.path.join(tmpdir, "css"))) + root.putChild("font", static.File(os.path.join(tmpdir, "font"))) + root.putChild("img", static.File(os.path.join(tmpdir, "img"))) + root.putChild("js", static.File(os.path.join(tmpdir, "js"))) root.putChild(API_ADDRESS, daemon) root.putChild("webapi", LBRYDaemonWeb()) root.putChild("view", LBRYFileRender()) reactor.listenTCP(API_PORT, server.Site(root), interface=API_INTERFACE) reactor.run() + + shutil.rmtree(tmpdir) \ No newline at end of file From 13acbfb64f6eee683d1df4de332418e52fbc096f Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 22 Mar 2016 11:51:27 -0400 Subject: [PATCH 23/32] update uri handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -use new jsonrpc daemon, start app if it isn’t running on first lbry:// request --- lbrynet/conf.py | 2 + lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py | 83 ++++++++++--------- lbrynet/lbrynet_daemon/LBRYDaemon.py | 4 +- setup_uri_handler.py | 2 + 4 files changed, 52 insertions(+), 39 deletions(-) diff --git a/lbrynet/conf.py b/lbrynet/conf.py index 227589def..f3903ae6a 100644 --- a/lbrynet/conf.py +++ b/lbrynet/conf.py @@ -36,6 +36,8 @@ APP_NAME = "LBRY" DEFAULT_WALLET = "lbryum" API_CONNECTION_STRING = "http://%s:%i/%s" % (API_INTERFACE, API_PORT, API_ADDRESS) +UI_ADDRESS = "http://" + API_INTERFACE + ":" + str(API_PORT) + PROTOCOL_PREFIX = "lbry" DEFAULT_TIMEOUT = 30 \ No newline at end of file diff --git a/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py b/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py index 1cc1bf3f8..1bc8c3399 100644 --- a/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py +++ b/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py @@ -1,54 +1,61 @@ import os import json import webbrowser -import xmlrpclib, sys +import sys +from time import sleep -def render_video(path): - r = r'
' - return r +from jsonrpc.proxy import JSONRPCProxy +from lbrynet.conf import API_CONNECTION_STRING, UI_ADDRESS -def main(args): - if len(args) == 0: - args.append('lbry://wonderfullife') +class LBRYURIHandler(object): + def __init__(self): + self.started_daemon = False + self.start_timeout = 0 + self.daemon = JSONRPCProxy.from_url(API_CONNECTION_STRING) - daemon = xmlrpclib.ServerProxy('http://localhost:7080/') + def check_status(self): + try: + self.daemon.is_running() - try: - daemon.is_running() - - if len(args) > 1: - exit(1) - - if args[0][7:] == 'lbry': - daemon.render_gui() - - elif args[0][7:] == 'settings': - r = daemon.get_settings() - html = "" + json.dumps(r) + "" - daemon.render_html(html) - - else: - r = daemon.get(args[0][7:]) - if r[0] == 200: - path = r[1]['path'] - if path[0] != '/': - path = '/' + path - - filename = os.path.basename(path) - extension = os.path.splitext(filename)[1] - - if extension in ['mp4', 'flv', 'mov']: - html = render_video(path) - daemon.render_html(html) + except: + if self.started_daemon: + if self.start_timeout < 30: + sleep(1) + self.start_timeout += 1 + self.check_status() else: - webbrowser.get('safari').open('file://' + str(path)) + exit(1) + else: + os.system("open /Applications/LBRY.app") + self.started_daemon = True + self.start_timeout += 1 + self.check_status() + def handle(self, lbry_name): + self.check_status() + + if lbry_name == "lbry": + webbrowser.get('safari').open(UI_ADDRESS) + else: + r = json.loads(self.daemon.get({'name': lbry_name})) + if r['code'] == 200: + path = r['result']['path'].encode('utf-8') + extension = os.path.splitext(path)[1] + if extension in ['mp4', 'flv', 'mov', 'ogv']: + webbrowser.get('safari').open(UI_ADDRESS + "/view?name=" + lbry_name) + else: + webbrowser.get('safari').open('file://' + path) else: webbrowser.get('safari').open('http://lbry.io/get') - except: - webbrowser.get('safari').open('http://lbry.io/get') + +def main(args): + if len(args) != 1: + args = ['lbry://lbry'] + + name = args[0][7:] + LBRYURIHandler().handle(lbry_name=name) if __name__ == "__main__": diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 84ca4478b..b3e37a1f7 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -1147,7 +1147,9 @@ class LBRYFileRender(resource.Resource): isLeaf = False def _render_path(self, path): - return r'
' + extension = os.path.splitext(path)[1] + if extension in ['mp4', 'flv', 'mov', 'ogv']: + return r'
' def _delayed_render(self, request, results): request.write(str(results)) diff --git a/setup_uri_handler.py b/setup_uri_handler.py index 37a38826e..02f437e64 100644 --- a/setup_uri_handler.py +++ b/setup_uri_handler.py @@ -4,7 +4,9 @@ import os APP = [os.path.join('lbrynet', 'lbrynet_daemon', 'Apps', 'LBRYURIHandler.py')] DATA_FILES = [] OPTIONS = {'argv_emulation': True, + 'packages': ['lbrynet', 'jsonrpc'], 'plist': { + 'LSUIElement': True, 'CFBundleURLTypes': [ { 'CFBundleURLTypes': 'LBRYURIHandler', From 141162e5aee02da87d7b2e25dbf8c8e51830c9a6 Mon Sep 17 00:00:00 2001 From: Alex Grintsvayg Date: Tue, 22 Mar 2016 22:15:07 -0400 Subject: [PATCH 24/32] fixes so we can build an sdist --- MANIFEST.in | 2 ++ setup.py | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..97304ecca --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include lbrynet/lbrynet_console/plugins/blindrepeater.yapsy-plugin +recursive-include lbrynet/lbrynet_gui *.gif *.ico *.xbm *.conf diff --git a/setup.py b/setup.py index 8dde41775..ed9b2a866 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -import ez_setup -ez_setup.use_setuptools() from setuptools import setup, find_packages import sys import os @@ -49,4 +47,4 @@ setup(name='lbrynet', ('lbrynet/lbrynet_gui', gui_data_paths) ], dependency_links=['https://github.com/lbryio/lbryum/tarball/master/#egg=lbryum'], - ) \ No newline at end of file + ) From e85683e40f0ab46fc2afe47ab7e5d4c109acc81a Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Tue, 22 Mar 2016 22:42:45 -0400 Subject: [PATCH 25/32] show more informative messages when blockchain is catching up --- lbrynet/core/LBRYcrdWallet.py | 38 ++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 3c0c5f03f..9015da57f 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -893,6 +893,9 @@ class LBRYumWallet(LBRYWallet): self.cmd_runner = None self.first_run = False self.printed_retrieving_headers = False + self._start_check = None + self._catch_up_check = None + self._caught_up_counter = 0 def _start(self): @@ -912,21 +915,30 @@ class LBRYumWallet(LBRYWallet): alert.info("Running the wallet for the first time...this may take a moment.") self.printed_retrieving_headers = True return False - start_check.stop() + self._start_check.stop() + self._start_check = None if self.network.is_connected(): network_start_d.callback(True) else: network_start_d.errback(ValueError("Failed to connect to network.")) - start_check = task.LoopingCall(check_started) + self._start_check = task.LoopingCall(check_started) - d.addCallback(lambda _: start_check.start(.1)) + d.addCallback(lambda _: self._start_check.start(.1)) d.addCallback(lambda _: network_start_d) d.addCallback(lambda _: self._load_wallet()) d.addCallback(lambda _: self._get_cmd_runner()) return d def _stop(self): + if self._start_check is not None: + self._start_check.stop() + self._start_check = None + + if self._catch_up_check is not None: + self._catch_up_check.stop() + self._catch_up_check = None + d = defer.Deferred() def check_stopped(): @@ -964,16 +976,28 @@ class LBRYumWallet(LBRYWallet): remote_height = self.network.get_server_height() if remote_height != 0 and remote_height - local_height <= 5: - alert.info('Wallet loaded.') - catch_up_check.stop() + msg = "" + if self._caught_up_counter != 0: + msg += "All caught up. " + msg += "Wallet loaded." + alert.info(msg) + self._catch_up_check.stop() + self._catch_up_check = None blockchain_caught_d.callback(True) + elif remote_height != 0: + if self._caught_up_counter == 0: + alert.info('Catching up to the blockchain...showing blocks left...') + if self._caught_up_counter % 30 == 0: + alert.info('%d...', (remote_height - local_height)) + self._caught_up_counter += 1 - catch_up_check = task.LoopingCall(check_caught_up) + + self._catch_up_check = task.LoopingCall(check_caught_up) d = threads.deferToThread(get_wallet) d.addCallback(self._save_wallet) d.addCallback(lambda _: self.wallet.start_threads(self.network)) - d.addCallback(lambda _: catch_up_check.start(.1)) + d.addCallback(lambda _: self._catch_up_check.start(.1)) d.addCallback(lambda _: blockchain_caught_d) return d From 94398071eb389b150e6c2e372c0370865cd94425 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 23 Mar 2016 19:49:14 -0400 Subject: [PATCH 26/32] have uri handler check if app is running MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -checks if LBRY.app is running, starts it if it isn’t -delete unused function in LBRYDaemon --- lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py | 50 +++++++++++++------ lbrynet/lbrynet_daemon/LBRYDaemon.py | 4 -- setup_uri_handler.py | 2 +- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py b/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py index 1bc8c3399..ba62a78a4 100644 --- a/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py +++ b/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py @@ -3,9 +3,12 @@ import json import webbrowser import sys from time import sleep +import subprocess from jsonrpc.proxy import JSONRPCProxy -from lbrynet.conf import API_CONNECTION_STRING, UI_ADDRESS + +API_CONNECTION_STRING = "http://localhost:5279/lbryapi" +UI_ADDRESS = "http://localhost:5279" class LBRYURIHandler(object): @@ -15,27 +18,42 @@ class LBRYURIHandler(object): self.daemon = JSONRPCProxy.from_url(API_CONNECTION_STRING) def check_status(self): + status = None try: - self.daemon.is_running() - - except: - if self.started_daemon: - if self.start_timeout < 30: - sleep(1) - self.start_timeout += 1 - self.check_status() - else: - exit(1) - else: - os.system("open /Applications/LBRY.app") - self.started_daemon = True + status = json.loads(self.daemon.is_running())['result'] + if self.start_timeout < 30 and not status: + sleep(1) self.start_timeout += 1 self.check_status() + elif status: + return True + else: + exit(1) + except: + if self.start_timeout < 30: + sleep(1) + self.start_timeout += 1 + self.check_status() + else: + exit(1) def handle(self, lbry_name): - self.check_status() + lbry_process = [d for d in subprocess.Popen(['ps','aux'], stdout=subprocess.PIPE).stdout.readlines() + if 'LBRY.app' in d] + try: + status = json.loads(self.daemon.is_running())['result'] + except: + pass - if lbry_name == "lbry": + if lbry_process: + self.check_status() + started = False + else: + os.system("open /Applications/LBRY.app") + self.check_status() + started = True + + if lbry_name == "lbry" or lbry_name == "" and not started: webbrowser.get('safari').open(UI_ADDRESS) else: r = json.loads(self.daemon.get({'name': lbry_name})) diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index b3e37a1f7..3391e0dcb 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -1136,10 +1136,6 @@ class LBRYindex(resource.Resource): return resource.Resource.getChild(self, name, request) def render_GET(self, request): - def _disp(r): - log.info(r) - return "
" + ''.join(r) + "" - return static.File(os.path.join(self.ui_dir, "index.html")).render_GET(request) diff --git a/setup_uri_handler.py b/setup_uri_handler.py index 02f437e64..1a3c68700 100644 --- a/setup_uri_handler.py +++ b/setup_uri_handler.py @@ -4,7 +4,7 @@ import os APP = [os.path.join('lbrynet', 'lbrynet_daemon', 'Apps', 'LBRYURIHandler.py')] DATA_FILES = [] OPTIONS = {'argv_emulation': True, - 'packages': ['lbrynet', 'jsonrpc'], + 'packages': ['jsonrpc'], 'plist': { 'LSUIElement': True, 'CFBundleURLTypes': [ From 1ccd2a3cc9107d1cd17df66dc31019f3610ed5fd Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Wed, 23 Mar 2016 22:02:02 -0400 Subject: [PATCH 27/32] do version better --- lbrynet/__init__.py | 3 ++- setup.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lbrynet/__init__.py b/lbrynet/__init__.py index f780625b8..eb4d8454c 100644 --- a/lbrynet/__init__.py +++ b/lbrynet/__init__.py @@ -4,4 +4,5 @@ import logging logging.getLogger(__name__).addHandler(logging.NullHandler()) -__version__ = (0, 2, 0) \ No newline at end of file +version = (0, 2, 0) +__version__ = ".".join([str(x) for x in version]) diff --git a/setup.py b/setup.py index ed9b2a866..4b8047d00 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ gui_data_files = ['close2.gif', 'lbry-dark-242x80.gif', 'lbry-dark-icon.xbm', 'l gui_data_paths = [os.path.join(base_dir, 'lbrynet', 'lbrynet_gui', f) for f in gui_data_files] setup(name='lbrynet', - version='.'.join([str(x) for x in __version__]), + version=__version__, packages=find_packages(base_dir), install_requires=['six>=1.9.0', 'pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', 'leveldb', 'lbryum'], entry_points={'console_scripts': console_scripts}, From 543b327d09696b808c694ff6d5884fa415f183c3 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 23 Mar 2016 22:06:04 -0400 Subject: [PATCH 28/32] use only six 1.9 on os x --- setup.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index b032122fb..36000670b 100644 --- a/setup.py +++ b/setup.py @@ -23,13 +23,19 @@ console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch if sys.platform == 'darwin': console_scripts.append('lbrynet-daemon-status = lbrynet.lbrynet_daemon.LBRYOSXStatusBar:main') +requires = ['pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', + 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', + 'leveldb', 'lbryum', 'jsonrpc', 'simplejson', 'appdirs'] + +if sys.platform == 'darwin': + requires.append('six==1.9.0') +else: + requires.append('six>=1.9.0') setup(name='lbrynet', version='0.0.4', packages=find_packages(), - install_requires=['six>=1.9.0', 'pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', - 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', - 'leveldb', 'lbryum', 'jsonrpc', 'simplejson', 'appdirs'], + install_requires=requires, entry_points={'console_scripts': console_scripts}, data_files=[ ('lbrynet/lbrynet_console/plugins', From c714a3f91c58680147e664622c0f89e1039c2aad Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 23 Mar 2016 22:27:48 -0400 Subject: [PATCH 29/32] merge updates --- lbrynet/core/LBRYcrdWallet.py | 18 +- lbrynet/lbrynet_console/LBRYConsole.py | 55 +- lbrynet/lbrynet_daemon/LBRYDaemon.py | 855 ++++++++++++------------- setup.py | 34 +- 4 files changed, 490 insertions(+), 472 deletions(-) diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 3c0c5f03f..5ead82cb2 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -316,8 +316,8 @@ class LBRYWallet(object): except (ValueError, TypeError): return Failure(InvalidStreamInfoError(name)) known_fields = ['stream_hash', 'name', 'description', 'key_fee', 'key_fee_address', 'thumbnail', - 'content_license', 'sources', 'fee'] - known_sources = ['lbry_sd_hash'] + 'content_license', 'sources', 'fee', 'author'] + known_sources = ['lbry_sd_hash', 'btih', 'url'] known_fee_types = {'LBC': ['amount', 'address']} for field in known_fields: if field in value_dict: @@ -353,7 +353,7 @@ class LBRYWallet(object): return Failure(UnknownNameError(name)) def claim_name(self, name, sd_hash, amount, description=None, key_fee=None, - key_fee_address=None, thumbnail=None, content_license=None): + key_fee_address=None, thumbnail=None, content_license=None, author=None, sources=None): value = {"sources": {'lbry_sd_hash': sd_hash}} if description is not None: value['description'] = description @@ -363,6 +363,10 @@ class LBRYWallet(object): value['thumbnail'] = thumbnail if content_license is not None: value['content_license'] = content_license + if author is not None: + value['author'] = author + if sources is not None: + value['sources'] = sources d = self._send_name_claim(name, json.dumps(value), amount) @@ -930,13 +934,15 @@ class LBRYumWallet(LBRYWallet): d = defer.Deferred() def check_stopped(): - if self.network.is_connected(): - return False + if self.network: + if self.network.is_connected(): + return False stop_check.stop() self.network = None d.callback(True) - self.network.stop() + if self.network: + self.network.stop() stop_check = task.LoopingCall(check_stopped) stop_check.start(.1) diff --git a/lbrynet/lbrynet_console/LBRYConsole.py b/lbrynet/lbrynet_console/LBRYConsole.py index 18bd6a8fc..6cde77c3f 100644 --- a/lbrynet/lbrynet_console/LBRYConsole.py +++ b/lbrynet/lbrynet_console/LBRYConsole.py @@ -1,16 +1,21 @@ import logging -from lbrynet.core.Session import LBRYSession import os.path import argparse import requests import locale import sys + +if sys.platform == "darwin": + from appdirs import user_data_dir from yapsy.PluginManager import PluginManager from twisted.internet import defer, threads, stdio, task, error +from jsonrpc.proxy import JSONRPCProxy + +from lbrynet.core.Session import LBRYSession from lbrynet.lbrynet_console.ConsoleControl import ConsoleControl from lbrynet.lbrynet_console.LBRYSettings import LBRYSettings from lbrynet.lbryfilemanager.LBRYFileManager import LBRYFileManager -from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE # , MIN_BLOB_INFO_PAYMENT_RATE +from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE, API_CONNECTION_STRING # , MIN_BLOB_INFO_PAYMENT_RATE from lbrynet.core.utils import generate_id from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier from lbrynet.core.PaymentRateManager import PaymentRateManager @@ -461,7 +466,6 @@ class LBRYConsole(): def launch_lbry_console(): - from twisted.internet import reactor parser = argparse.ArgumentParser(description="Launch a lbrynet console") @@ -529,7 +533,7 @@ def launch_lbry_console(): created_data_dir = False if not args.data_dir: if sys.platform == "darwin": - data_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrynet") + data_dir = user_data_dir("LBRY") else: data_dir = os.path.join(os.path.expanduser("~"), ".lbrynet") else: @@ -538,28 +542,35 @@ def launch_lbry_console(): os.mkdir(data_dir) created_data_dir = True + daemon = JSONRPCProxy.from_url(API_CONNECTION_STRING) + try: + daemon.is_running() + log.info("Attempt to start lbrynet-console while lbrynet-daemon is running") + print "lbrynet-daemon is running, you must turn it off before using lbrynet-console" + print "If you're running the app, quit before starting lbrynet-console" + print "If you're running lbrynet-daemon in a terminal, run 'stop-lbrynet-daemon' to turn it off" - log_format = "(%(asctime)s)[%(filename)s:%(lineno)s] %(funcName)s(): %(message)s" - formatter = logging.Formatter(log_format) + except: + log_format = "(%(asctime)s)[%(filename)s:%(lineno)s] %(funcName)s(): %(message)s" + formatter = logging.Formatter(log_format) - logger = logging.getLogger() - logger.setLevel(logging.DEBUG) - file_handler = logging.FileHandler(os.path.join(data_dir, "console.log")) - file_handler.setFormatter(formatter) - file_handler.addFilter(logging.Filter("lbrynet")) - logger.addHandler(file_handler) + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + file_handler = logging.FileHandler(os.path.join(data_dir, "console.log")) + file_handler.setFormatter(formatter) + file_handler.addFilter(logging.Filter("lbrynet")) + logger.addHandler(file_handler) - console = LBRYConsole(peer_port, dht_node_port, bootstrap_nodes, fake_wallet=args.fake_wallet, - lbrycrd_conf=args.lbrycrd_wallet_conf, lbrycrd_dir=args.lbrycrd_wallet_dir, - use_upnp=not args.disable_upnp, data_dir=data_dir, - created_data_dir=created_data_dir, lbrycrdd_path=args.lbrycrdd_path) - d = task.deferLater(reactor, 0, console.start) + console = LBRYConsole(peer_port, dht_node_port, bootstrap_nodes, fake_wallet=args.fake_wallet, + lbrycrd_conf=args.lbrycrd_wallet_conf, lbrycrd_dir=args.lbrycrd_wallet_dir, + use_upnp=not args.disable_upnp, data_dir=data_dir, + created_data_dir=created_data_dir, lbrycrdd_path=args.lbrycrdd_path) - d.addErrback(lambda _: reactor.stop()) - - reactor.addSystemEventTrigger('before', 'shutdown', console.shut_down) - reactor.run() + d = task.deferLater(reactor, 0, console.start) + d.addErrback(lambda _: reactor.stop()) + reactor.addSystemEventTrigger('before', 'shutdown', console.shut_down) + reactor.run() if __name__ == "__main__": - launch_lbry_console() \ No newline at end of file + launch_lbry_console() diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 85c441826..d3b616b75 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -1,23 +1,26 @@ import locale import os import sys -import json +import simplejson as json import binascii -import webbrowser -import xmlrpclib import subprocess import logging -import argparse -import pwd import requests +# import rumps +# import httplib2 + +from twisted.web import server, resource, static +from twisted.internet import defer, threads, error, reactor +from txjsonrpc import jsonrpclib +from txjsonrpc.web import jsonrpc +from jsonrpc.proxy import JSONRPCProxy -from twisted.web import xmlrpc, server -from twisted.internet import defer, threads, reactor, error from datetime import datetime from decimal import Decimal from StringIO import StringIO from zipfile import ZipFile from urllib import urlopen +from appdirs import user_data_dir from lbrynet.core.PaymentRateManager import PaymentRateManager from lbrynet.core.server.BlobAvailabilityHandler import BlobAvailabilityHandlerFactory @@ -33,6 +36,7 @@ from lbrynet.lbrynet_daemon.LBRYPublisher import Publisher from lbrynet.core.utils import generate_id from lbrynet.lbrynet_console.LBRYSettings import LBRYSettings from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE, DEFAULT_MAX_SEARCH_RESULTS, KNOWN_DHT_NODES, DEFAULT_MAX_KEY_FEE +from lbrynet.conf import API_CONNECTION_STRING, API_PORT, API_ADDRESS, DEFAULT_TIMEOUT from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier, download_sd_blob from lbrynet.core.Session import LBRYSession from lbrynet.core.PTCWallet import PTCWallet @@ -41,28 +45,62 @@ from lbrynet.lbryfilemanager.LBRYFileManager import LBRYFileManager from lbrynet.lbryfile.LBRYFileMetadataManager import DBLBRYFileMetadataManager, TempLBRYFileMetadataManager log = logging.getLogger(__name__) -# logging.basicConfig(level=logging.DEBUG) +BAD_REQUEST = 400 +NOT_FOUND = 404 +OK_CODE = 200 # TODO add login credentials in a conf file -# functions to add: -# TODO send credits to address # TODO alert if your copy of a lbry file is out of date with the name record -BAD_REQUEST = (400, "Bad request") -NOT_FOUND = (404, "Not found") - -OK_CODE = 200 +class Bunch: + def __init__(self, params): + self.__dict__.update(params) -class LBRYDaemon(xmlrpc.XMLRPC): +class LBRYDaemon(jsonrpc.JSONRPC): """ - LBRYnet daemon + LBRYnet daemon, a jsonrpc interface to lbry functions """ + isLeaf = True + + def render(self, request): + request.content.seek(0, 0) + # Unmarshal the JSON-RPC data. + content = request.content.read() + parsed = jsonrpclib.loads(content) + functionPath = parsed.get("method") + args = parsed.get('params') + id = parsed.get('id') + version = parsed.get('jsonrpc') + if version: + version = int(float(version)) + elif id and not version: + version = jsonrpclib.VERSION_1 + else: + version = jsonrpclib.VERSION_PRE1 + # XXX this all needs to be re-worked to support logic for multiple + # versions... + try: + function = self._getFunction(functionPath) + except jsonrpclib.Fault, f: + self._cbRender(f, request, id, version) + else: + request.setHeader('Access-Control-Allow-Origin', ('http://localhost' + ':' + str(API_PORT))) + request.setHeader("content-type", "text/json") + if args == [{}]: + d = defer.maybeDeferred(function) + else: + d = defer.maybeDeferred(function, *args) + d.addErrback(self._ebRender, id) + d.addCallback(self._cbRender, request, id, version) + return server.NOT_DONE_YET def setup(self, wallet_type, check_for_updates): def _set_vars(wallet_type, check_for_updates): + reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown) + self.fetcher = None self.current_db_revision = 1 self.run_server = True @@ -71,7 +109,8 @@ class LBRYDaemon(xmlrpc.XMLRPC): if sys.platform != "darwin": self.db_dir = os.path.join(os.path.expanduser("~"), ".lbrynet") else: - self.db_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrynet") + self.db_dir = user_data_dir("LBRY") + # self.db_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrynet") self.blobfile_dir = os.path.join(self.db_dir, "blobfiles") self.peer_port = 3333 self.dht_node_port = 4444 @@ -82,11 +121,12 @@ class LBRYDaemon(xmlrpc.XMLRPC): self.wallet_dir = os.path.join(get_path(FOLDERID.RoamingAppData, UserHandle.current), "lbrycrd") elif sys.platform == "darwin": self.download_directory = os.path.join(os.path.expanduser("~"), 'Downloads') - self.wallet_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrycrd") + # self.wallet_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrycrd") + self.wallet_dir = user_data_dir("LBRY") else: self.wallet_dir = os.path.join(os.path.expanduser("~"), ".lbrycrd") self.download_directory = os.path.join(os.path.expanduser("~"), 'Downloads') - + self.daemon_conf = os.path.join(self.wallet_dir, 'daemon_settings.conf') self.wallet_conf = os.path.join(self.wallet_dir, "lbrycrd.conf") self.wallet_user = None self.wallet_password = None @@ -119,28 +159,31 @@ class LBRYDaemon(xmlrpc.XMLRPC): self.data_rate = MIN_BLOB_DATA_PAYMENT_RATE self.max_key_fee = DEFAULT_MAX_KEY_FEE self.max_search_results = DEFAULT_MAX_SEARCH_RESULTS - self.restart_message = "" self.startup_message = "" self.announced_startup = False self.search_timeout = 3.0 self.query_handlers = {} + self.default_settings = { + 'run_on_startup': False, + 'data_rate': MIN_BLOB_DATA_PAYMENT_RATE, + 'max_key_fee': 10.0, + 'default_download_directory': self.download_directory, + 'max_upload': 0.0, + 'max_download': 0.0 + } return defer.succeed(None) def _disp_startup(): - if self.restart_message: - print self.restart_message - else: - print "Started LBRYnet daemon" - print "The daemon can be shut down by running 'stop-lbrynet-daemon' in a terminal" - log.info('[' + str(datetime.now()) + '] Started lbrynet-daemon') + log.info("[" + str(datetime.now()) + "] Started lbrynet-daemon") return defer.succeed(None) - log.info('[' + str(datetime.now()) + '] Starting lbrynet-daemon') + log.info("[" + str(datetime.now()) + "] Starting lbrynet-daemon") d = defer.Deferred() - d.addCallback(lambda _: _set_vars(wallet_type, check_for_updates)) + d.addCallback(lambda _:_set_vars(wallet_type, check_for_updates)) + d.addCallback(lambda _: self._setup_daemon_settings()) d.addCallback(lambda _: threads.deferToThread(self._setup_data_directory)) d.addCallback(lambda _: self._check_db_migration()) d.addCallback(lambda _: self._get_settings()) @@ -152,104 +195,19 @@ class LBRYDaemon(xmlrpc.XMLRPC): d.addCallback(lambda _: self._setup_lbry_file_opener()) d.addCallback(lambda _: self._setup_query_handlers()) d.addCallback(lambda _: self._setup_server()) - # d.addCallback(lambda _: self._update() if self.check_for_updates == "True" and sys.platform == "darwin" - # else defer.succeed(None)) d.addCallback(lambda _: self._setup_fetcher()) d.addCallback(lambda _: _disp_startup()) d.callback(None) return defer.succeed(None) - def _update(self): - def _check_for_updater(): - if os.path.isdir("/Applications/LBRY Updater.app"): - print "Found LBRY updater" - return defer.succeed(None) - - print "LBRY updater not found, downloading and installing..." - url = urlopen("https://rawgit.com/jackrobison/lbrynet-app/master/LBRY%20Updater.app.zip") - zipped_app = ZipFile(StringIO(url.read())) - zipped_app.extractall("/Applications") - return defer.succeed(None) - - def _update_lbrynet(): - git_version = subprocess.check_output( - "git ls-remote https://github.com/lbryio/lbry.git | grep HEAD | cut -f 1", - shell=True) - if os.path.isfile(os.path.join(self.db_dir, "lbrynet_version.txt")): - f = open(os.path.join(self.db_dir, "lbrynet_version.txt"), 'r') - current_version = f.read() - f.close() - if git_version == current_version: - print "LBRYnet installation version " + current_version[:-1] + " is up to date" - return defer.succeed(None) - print "Update LBRYnet version " + current_version[:-1] + " --> " + git_version[:-1] - self.restart_message = "Updates available" - else: - print "Update LBRYnet to version " + git_version[:-1] - self.restart_message = "Updates available" - - return defer.succeed(None) - - def _update_lbrycrdd(): - git_version = subprocess.check_output( - "git ls-remote https://github.com/jackrobison/lbrynet-app.git | grep HEAD | cut -f 1", - shell=True) - if os.path.isfile(os.path.join(self.wallet_dir, "lbry_app_version.txt")): - f = open(os.path.join(self.wallet_dir, "lbry_app_version.txt"), 'r') - current_version = f.read() - f.close() - if git_version == current_version: - print "LBRY installation version " + current_version[:-1] + " is up to date" - return defer.succeed(None) - print "Update LBRY version " + current_version[:-1] + " --> " + git_version[:-1] - self.restart_message = "Updates available" - else: - print "Update LBRY to version " + git_version[:-1] - self.restart_message = "Updates available" - - return defer.succeed(None) - - def _update_lbryum(): - git_version = subprocess.check_output( - "git ls-remote https://github.com/lbryio/lbryum.git | grep HEAD | cut -f 1", - shell=True) - if os.path.isfile(os.path.join(self.db_dir, "lbryum_version.txt")): - f = open(os.path.join(self.db_dir, "lbryum_version.txt"), 'r') - current_version = f.read() - f.close() - if git_version == current_version: - print "LBRYum installation version " + current_version[:-1] + " is up to date" - return defer.succeed(None) - print "Update LBRYum version " + current_version[:-1] + " --> " + git_version[:-1] - self.restart_message = "Updates available" - else: - print "Update LBRYum to version " + git_version[:-1] - self.restart_message = "Updates available" - - return defer.succeed(None) - - d = _check_for_updater() - d.addCallback(lambda _: _update_lbrynet()) - d.addCallback(lambda _: _update_lbrycrdd() if self.wallet_type == 'lbrycrd' else _update_lbryum()) - d.addCallback(lambda _: os.system("open /Applications/LBRY\ Updater.app &>/dev/null") if self.restart_message - else defer.succeed(None)) - d.addCallbacks(lambda _: self._restart() if self.restart_message else defer.succeed(None)) + def _initial_setup(self): + return defer.fail(NotImplementedError()) + def _setup_daemon_settings(self): + self.session_settings = self.default_settings return defer.succeed(None) - def _restart(self): - def _disp_shutdown(): - print 'Restarting lbrynet daemon' - return defer.succeed(None) - - # LBRY Updater.app will restart the daemon - d = self._shutdown() - d.addCallback(lambda _: _disp_shutdown()) - d.addCallback(lambda _: reactor.callLater(1.0, reactor.stop)) - - return d - def _start_server(self): if self.peer_port is not None: @@ -323,15 +281,34 @@ class LBRYDaemon(xmlrpc.XMLRPC): return dl def _shutdown(self): - print 'Closing lbrynet session' + log.info("Closing lbrynet session") d = self._stop_server() if self.session is not None: d.addCallback(lambda _: self.session.shut_down()) return d - def _update_settings(self): - self.data_rate = self.session_settings['data_rate'] - self.max_key_fee = self.session_settings['max_key_fee'] + def _update_settings(self, settings): + if not isinstance(settings['run_on_startup'], bool): + return defer.fail() + elif not isinstance(settings['data_rate'], float): + return defer.fail() + elif not isinstance(settings['max_key_fee'], float): + return defer.fail() + elif not isinstance(settings['default_download_directory'], unicode): + return defer.fail() + elif not isinstance(settings['max_upload'], float): + return defer.fail() + elif not isinstance(settings['max_download'], float): + return defer.fail() + + self.session_settings['run_on_startup'] = settings['run_on_startup'] + self.session_settings['data_rate'] = settings['data_rate'] + self.session_settings['max_key_fee'] = settings['max_key_fee'] + self.session_settings['default_download_directory'] = settings['default_download_directory'] + self.session_settings['max_upload'] = settings['max_upload'] + self.session_settings['max_download'] = settings['max_download'] + + return defer.succeed(True) def _setup_fetcher(self): self.fetcher = FetcherDaemon(self.session, self.lbry_file_manager, self.lbry_file_metadata_manager, @@ -339,7 +316,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): return defer.succeed(None) def _setup_data_directory(self): - print "Loading databases..." + log.info("Loading databases...") if self.created_data_dir: db_revision = open(os.path.join(self.db_dir, "db_revision"), mode='w') db_revision.write(str(self.current_db_revision)) @@ -356,7 +333,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): old_revision = int(open(db_revision_file).read().strip()) if old_revision < self.current_db_revision: from lbrynet.db_migrator import dbmigrator - print "Upgrading your databases..." + log.info("Upgrading your databases...") d = threads.deferToThread(dbmigrator.migrate_db, self.db_dir, old_revision, self.current_db_revision) def print_success(old_dirs): @@ -367,7 +344,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): success_string += old_dir if i + 1 < len(old_dir): success_string += ", " - print success_string + log.info(success_string) d.addCallback(print_success) return d @@ -396,7 +373,10 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = self.lbry_file_metadata_manager.setup() def set_lbry_file_manager(): - self.lbry_file_manager = LBRYFileManager(self.session, self.lbry_file_metadata_manager, self.sd_identifier) + self.lbry_file_manager = LBRYFileManager(self.session, + self.lbry_file_metadata_manager, + self.sd_identifier, + delete_data=True) return self.lbry_file_manager.setup() d.addCallback(lambda _: set_lbry_file_manager()) @@ -407,12 +387,11 @@ class LBRYDaemon(xmlrpc.XMLRPC): def get_default_data_rate(): d = self.settings.get_default_data_payment_rate() d.addCallback(lambda rate: {"default_data_payment_rate": rate if rate is not None else - MIN_BLOB_DATA_PAYMENT_RATE}) + MIN_BLOB_DATA_PAYMENT_RATE}) return d def get_wallet(): if self.wallet_type == "lbrycrd": - print "Using lbrycrd wallet" log.info("Using lbrycrd wallet") lbrycrdd_path = None if self.start_lbrycrdd is True: @@ -422,11 +401,9 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = defer.succeed(LBRYcrdWallet(self.db_dir, wallet_dir=self.wallet_dir, wallet_conf=self.lbrycrd_conf, lbrycrdd_path=lbrycrdd_path)) elif self.wallet_type == "lbryum": - print "Using lbryum wallet" log.info("Using lbryum wallet") d = defer.succeed(LBRYumWallet(self.db_dir)) elif self.wallet_type == "ptc": - print "Using PTC wallet" log.info("Using PTC wallet") d = defer.succeed(PTCWallet(self.db_dir)) else: @@ -509,7 +486,6 @@ class LBRYDaemon(xmlrpc.XMLRPC): for line in conf: if len(line.strip()) and line.strip()[0] != "#": self.lbrycrdd_path = line.strip() - print self.lbrycrdd_path d.addCallback(load_lbrycrdd_path) return d @@ -533,20 +509,20 @@ class LBRYDaemon(xmlrpc.XMLRPC): self.sd_identifier.add_stream_downloader_factory(LBRYFileStreamType, downloader_factory) return defer.succeed(True) - def _download_name(self, name): - def _disp_file(file): - print '[' + str(datetime.now()) + ']' + ' Already downloaded: ' + str(file.stream_hash) - d = self._path_from_lbry_file(file) - return d + def _download_name(self, name, timeout=DEFAULT_TIMEOUT): + def _disp_file(f): + file_path = os.path.join(self.download_directory, f.file_name) + log.info("[" + str(datetime.now()) + "] Already downloaded: " + str(f.stream_hash) + " --> " + file_path) + return defer.succeed(f) def _get_stream(name): def _disp(stream): - print '[' + str(datetime.now()) + ']' + ' Start stream: ' + stream['stream_hash'] + log.info("[" + str(datetime.now()) + "] Start stream: " + stream['stream_hash']) return stream d = self.session.wallet.get_stream_info_for_name(name) stream = GetStream(self.sd_identifier, self.session, self.session.wallet, self.lbry_file_manager, - max_key_fee=self.max_key_fee, data_rate=self.data_rate) + max_key_fee=self.max_key_fee, data_rate=self.data_rate, timeout=timeout) d.addCallback(_disp) d.addCallback(lambda stream_info: stream.start(stream_info)) d.addCallback(lambda _: self._path_from_name(name)) @@ -555,12 +531,8 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = self._check_history(name) d.addCallback(lambda lbry_file: _get_stream(name) if not lbry_file else _disp_file(lbry_file)) - d.addCallback(lambda _: self._check_history(name)) - d.addCallback(lambda lbry_file: (OK_CODE, {'stream_hash': lbry_file.stream_hash, - 'path': os.path.join(self.download_directory, - lbry_file.file_name)}) - if lbry_file else NOT_FOUND) - d.addErrback(lambda _: NOT_FOUND) + d.addCallback(lambda _: self._path_from_name(name)) + d.addErrback(lambda err: defer.fail(NOT_FOUND)) return d @@ -584,27 +556,32 @@ class LBRYDaemon(xmlrpc.XMLRPC): f = open(path, 'r') l = json.loads(f.read()) f.close() + file_name = l['stream_name'].decode('hex') - lbry_file = [file for file in self.lbry_file_manager.lbry_files if file.stream_name == file_name] - if lbry_file: - return lbry_file[0] + for lbry_file in self.lbry_file_manager.lbry_files: + if lbry_file.stream_name == file_name: + if sys.platform == "darwin": + if os.path.isfile(os.path.join(self.download_directory, lbry_file.stream_name)): + return lbry_file + else: + return False + else: + return lbry_file else: - return None + return False def _check(info): stream_hash = info['stream_hash'] path = os.path.join(self.blobfile_dir, stream_hash) if os.path.isfile(path): - print "[" + str(datetime.now()) + "] Search for lbry_file, returning: " + stream_hash log.info("[" + str(datetime.now()) + "] Search for lbry_file, returning: " + stream_hash) return defer.succeed(_get_lbry_file(path)) else: - print "[" + str(datetime.now()) + "] Search for lbry_file didn't return anything" log.info("[" + str(datetime.now()) + "] Search for lbry_file didn't return anything") return defer.succeed(False) d = self._resolve_name(name) - d.addCallbacks(_check, lambda _: False) + d.addCallback(_check) d.callback(None) return d @@ -615,7 +592,6 @@ class LBRYDaemon(xmlrpc.XMLRPC): def finish_deletion(lbry_file): d = lbry_file.delete_data() d.addCallback(lambda _: _delete_stream_data(lbry_file)) - d.addCallback(lambda _: _delete_file(lbry_file)) return d def _delete_stream_data(lbry_file): @@ -623,11 +599,10 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = self.lbry_file_manager.get_count_for_stream_hash(s_h) # TODO: could possibly be a timing issue here d.addCallback(lambda c: self.stream_info_manager.delete_stream(s_h) if c == 0 else True) + d.addCallback(lambda _: os.remove(os.path.join(self.download_directory, lbry_file.file_name)) if + os.path.isfile(os.path.join(self.download_directory, lbry_file.file_name)) else defer.succeed(None)) return d - def _delete_file(lbry_file): - os.remove(os.path.join(self.download_directory, lbry_file.file_name)) - d.addCallback(lambda _: finish_deletion(lbry_file)) return d @@ -635,7 +610,7 @@ class LBRYDaemon(xmlrpc.XMLRPC): d = self._check_history(name) d.addCallback(lambda lbry_file: {'stream_hash': lbry_file.stream_hash, 'path': os.path.join(self.download_directory, lbry_file.file_name)} - if lbry_file else defer.fail(UnknownNameError)) + if lbry_file else defer.fail(UnknownNameError)) return d def _path_from_lbry_file(self, lbry_file): @@ -649,11 +624,9 @@ class LBRYDaemon(xmlrpc.XMLRPC): def _get_est_cost(self, name): def _check_est(d, name): if type(d.result) is float: - print '[' + str(datetime.now()) + '] Cost est for lbry://' + name + ': ' + str(d.result) + 'LBC' - log.info('[' + str(datetime.now()) + '] Cost est for lbry://' + name + ': ' + str(d.result) + 'LBC') + log.info("[" + str(datetime.now()) + "] Cost est for lbry://" + name + ": " + str(d.result) + "LBC") else: - print '[' + str(datetime.now()) + '] Timeout estimating cost for lbry://' + name + ', using key fee' - log.info('[' + str(datetime.now()) + '] Timeout estimating cost for lbry://' + name + ', using key fee') + log.info("[" + str(datetime.now()) + "] Timeout estimating cost for lbry://" + name + ", using key fee") d.cancel() return defer.succeed(None) @@ -674,94 +647,109 @@ class LBRYDaemon(xmlrpc.XMLRPC): return d - def xmlrpc_is_running(self): - if self.startup_message != "" and self.announced_startup == False: - print "Startup message:", self.startup_message - self.announced_startup = True - return self.startup_message - elif self.announced_startup: - return True - else: - return False + def _render_response(self, result, code): + return json.dumps({'result': result, 'code': code}) - def xmlrpc_get_settings(self): + # def _log_to_slack(self, msg): + # URL = "https://hooks.slack.com/services/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" + # h = httplib2.Http() + # h.request(URL, 'POST', json.dumps({"text": msg}), headers={'Content-Type': 'application/json'}) + + def jsonrpc_is_running(self): + """ + Returns a startup message when the daemon starts, after which it will return True + """ + + if self.startup_message != "" and self.announced_startup == False: + self.announced_startup = True + return self._render_response(self.startup_message, OK_CODE) + elif self.announced_startup: + return self._render_response(True, OK_CODE) + else: + return self._render_response(False, OK_CODE) + + def jsonrpc_get_settings(self): """ Get LBRY payment settings @return {'data_rate': float, 'max_key_fee': float} """ - if not self.session_settings: - self.session_settings = {'data_rate': self.data_rate, 'max_key_fee': self.max_key_fee} + log.info("[" + str(datetime.now()) + "] Get daemon settings") + return self._render_response(self.session_settings, OK_CODE) - print '[' + str(datetime.now()) + '] Get daemon settings' - return self.session_settings - - def xmlrpc_set_settings(self, settings): + def jsonrpc_set_settings(self, p): """ Set LBRY payment settings - @param settings dict: {'data_rate': float, 'max_key_fee': float} + @param settings: {'settings': {'data_rate': float, 'max_key_fee': float}} """ - self.session_settings = settings - self._update_settings() + d = self._update_settings(p) - print '[' + str(datetime.now()) + '] Set daemon settings' - return 'Set' + log.info("[" + str(datetime.now()) + "] Set daemon settings") + return self._render_response(True, OK_CODE) - def xmlrpc_start_fetcher(self): + def jsonrpc_start_fetcher(self): """ - Start autofetcher + Start automatically downloading new name claims as they happen + + @return: confirmation message """ self.fetcher.start() - print '[' + str(datetime.now()) + '] Start autofetcher' log.info('[' + str(datetime.now()) + '] Start autofetcher') - return 'Started autofetching' + # self._log_to_slack('[' + str(datetime.now()) + '] Start autofetcher') + return self._render_response("Started autofetching claims", OK_CODE) - def xmlrpc_stop_fetcher(self): + def jsonrpc_stop_fetcher(self): """ - Stop autofetcher + Stop automatically downloading new name claims as they happen + + @return: confirmation message """ self.fetcher.stop() - print '[' + str(datetime.now()) + '] Stop autofetcher' log.info('[' + str(datetime.now()) + '] Stop autofetcher') - return 'Stopped autofetching' + return self._render_response("Stopped autofetching claims", OK_CODE) - def xmlrpc_fetcher_status(self): + def jsonrpc_fetcher_status(self): """ - Start autofetcher + Get fetcher status + + @return: True/False """ - print '[' + str(datetime.now()) + '] Get fetcher status' - return str(self.fetcher.check_if_running()) + log.info("[" + str(datetime.now()) + "] Get fetcher status") + return self._render_response(self.fetcher.check_if_running(), OK_CODE) - def xmlrpc_get_balance(self): + def jsonrpc_get_balance(self): """ Get LBC balance + + @return: balance """ - print '[' + str(datetime.now()) + '] Get balance' - return str(self.session.wallet.wallet_balance) + log.info("[" + str(datetime.now()) + "] Get balance") + return self._render_response(self.session.wallet.wallet_balance, OK_CODE) - def xmlrpc_stop(self): + def jsonrpc_stop(self): """ Stop lbrynet-daemon + + @return: shutdown message """ def _disp_shutdown(): - log.info('Shutting down lbrynet daemon') - print 'Shutting down lbrynet daemon' + log.info("Shutting down lbrynet daemon") d = self._shutdown() d.addCallback(lambda _: _disp_shutdown()) d.addCallback(lambda _: reactor.callLater(1.0, reactor.stop)) - return defer.succeed('Shutting down') + return self._render_response("Shutting down", OK_CODE) - def xmlrpc_get_lbry_files(self): + def jsonrpc_get_lbry_files(self): """ Get LBRY files @@ -783,124 +771,89 @@ class LBRYDaemon(xmlrpc.XMLRPC): r.append(json.dumps(t)) - print '[' + str(datetime.now()) + '] Get LBRY files' - return r + log.info("[" + str(datetime.now()) + "] Get LBRY files") + return self._render_response(r, OK_CODE) - def xmlrpc_resolve_name(self, name): + def jsonrpc_resolve_name(self, p): """ Resolve stream info from a LBRY uri - @param: name + @param: {'name': name to look up} @return: info for name claim """ + params = Bunch(p) def _disp(info): - print '[' + str(datetime.now()) + ']' + ' Resolved info: ' + str(info['stream_hash']) - return info + log.info("[" + str(datetime.now()) + "] Resolved info: " + info['stream_hash']) + return self._render_response(info, OK_CODE) - d = self._resolve_name(name) - d.addCallbacks(_disp, lambda _: str('UnknownNameError')) + d = self._resolve_name(params.name) + d.addCallbacks(_disp, lambda _: self._render_response('error', NOT_FOUND)) d.callback(None) return d - def xmlrpc_get(self, name): + def jsonrpc_get(self, p): """ Download stream from a LBRY uri @param: name @return: {'stream_hash': hex string, 'path': path of download} """ + params = Bunch(p) - if name: - d = self._download_name(name) + if 'timeout' not in p.keys(): + params.timeout = DEFAULT_TIMEOUT + + if params.name: + d = self._download_name(params.name, timeout=params.timeout) + d.addCallbacks(lambda message: self._render_response(message, OK_CODE), + lambda err: self._render_response('error', NOT_FOUND)) else: - d = defer.succeed(BAD_REQUEST) + d = self._render_response('error', BAD_REQUEST) + return d - def xmlrpc_stop_lbry_file(self, stream_hash): + def jsonrpc_stop_lbry_file(self, p): + params = Bunch(p) + try: - lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == stream_hash][0] + lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == params.stream_hash][0] except IndexError: return defer.fail(UnknownNameError) if not lbry_file.stopped: d = self.lbry_file_manager.toggle_lbry_file_running(lbry_file) - d.addCallback(lambda _: 'Stream has been stopped') - d.addErrback(lambda err: str(err)) + d.addCallback(lambda _: self._render_response("Stream has been stopped", OK_CODE)) + d.addErrback(lambda err: self._render_response(err.getTraceback(), )) return d else: - return defer.succeed('Stream was already stopped') + return json.dumps({'result': 'Stream was already stopped'}) + + def jsonrpc_start_lbry_file(self, p): + params = Bunch(p) - def xmlrpc_start_lbry_file(self, stream_hash): try: - lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == stream_hash][0] + lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == params.stream_hash][0] except IndexError: return defer.fail(UnknownNameError) if lbry_file.stopped: d = self.lbry_file_manager.toggle_lbry_file_running(lbry_file) d.callback(None) - return defer.succeed('Stream started') + return json.dumps({'result': 'Stream started'}) else: - return defer.succeed('Stream was already running') + return json.dumps({'result': 'Stream was already running'}) - def xmlrpc_render_html(self, html): - """ - Writes html to lbry.html in the downloads directory, then opens it with the browser - - @param html: - """ - - def _make_file(html, path): - f = open(path, 'w') - f.write(html) - f.close() - return defer.succeed(None) - - def _disp_err(err): - print str(err.getTraceback()) - return err - - path = os.path.join(self.download_directory, 'lbry.html') - - d = defer.Deferred() - d.addCallback(lambda _: _make_file(html, path)) - d.addCallback(lambda _: os.chown(path, pwd.getpwuid(os.getuid()).pw_uid, pwd.getpwuid(os.getuid()).pw_gid)) - d.addCallback(lambda _: webbrowser.open('file://' + path)) - d.addErrback(_disp_err) - d.callback(None) - - return d - - def xmlrpc_render_gui(self): - """ - Opens the lbry web ui in a browser - """ - - def _disp_err(err): - print str(err.getTraceback()) - return err - - d = defer.Deferred() - if sys.platform == 'darwin': - d.addCallback(lambda _: webbrowser.get('safari').open( - "file://" + str(os.path.join(self.download_directory, "lbryio/view/page/gui.html")))) - else: - d.addCallback(lambda _: webbrowser.open( - "file://" + str(os.path.join(self.download_directory, "lbryio/view/page/gui.html")))) - d.addErrback(_disp_err) - d.callback(None) - - return d - - def xmlrpc_search_nametrie(self, search): + def jsonrpc_search_nametrie(self, p): """ Search the nametrie for claims beginning with search - @param search: - @return: + @param {'search': search string} + @return: List of search results """ + params = Bunch(p) + def _clean(n): t = [] for i in n: @@ -910,26 +863,6 @@ class LBRYDaemon(xmlrpc.XMLRPC): t.append([i[1][0][1], i[1][1][1], i[1][2][1]]) return t - def _parse(results): - f = [] - for chain, meta, cost_est in results: - t = {} - if 'name' in chain.keys(): - t['name'] = chain['name'] - if 'thumbnail' in meta.keys(): - t['img'] = meta['thumbnail'] - else: - t['img'] = 'File://' + str( - os.path.join(self.download_directory, "lbryio/web/img/Free-speech-flag.svg")) - if 'name' in meta.keys(): - t['title'] = meta['name'] - if 'description' in meta.keys(): - t['description'] = meta['description'] - t['cost_est'] = cost_est - f.append(t) - - return f - def resolve_claims(claims): ds = [] for claim in claims: @@ -941,148 +874,163 @@ class LBRYDaemon(xmlrpc.XMLRPC): return defer.DeferredList(ds) def _disp(results): - print '[' + str(datetime.now()) + '] Found ' + str(len(results)) + ' results' - log.info('[' + str(datetime.now()) + '] Search results: ') + log.info('[' + str(datetime.now()) + '] Found ' + str(len(results)) + ' search results') + consolidated_results = [] for r in results: - log.info(str(r)) - return results + t = {} + t.update(r[0]) + if 'name' in r[1].keys(): + r[1]['stream_name'] = r[1]['name'] + del r[1]['name'] + t.update(r[1]) + t['cost_est'] = r[2] + consolidated_results.append(t) + # log.info(str(t)) + return self._render_response(consolidated_results, OK_CODE) - print '[' + str(datetime.now()) + '] Search nametrie: ' + search - log.info('[' + str(datetime.now()) + '] Search nametrie: ' + search) + log.info('[' + str(datetime.now()) + '] Search nametrie: ' + params.search) d = self.session.wallet.get_nametrie() - d.addCallback(lambda trie: [claim for claim in trie if claim['name'].startswith(search) and 'txid' in claim]) + d.addCallback(lambda trie: [claim for claim in trie if claim['name'].startswith(params.search) and 'txid' in claim]) d.addCallback(lambda claims: claims[:self.max_search_results]) d.addCallback(resolve_claims) d.addCallback(_clean) - d.addCallback(_parse) d.addCallback(_disp) return d - def xmlrpc_delete_lbry_file(self, file_name): + def jsonrpc_delete_lbry_file(self, p): + """ + Delete a lbry file + + @param {'file_name': string} + @return: confirmation message + """ + + params = Bunch(p) + def _disp(file_name): - print '[' + str(datetime.now()) + '] Deleted: ' + file_name - return defer.succeed('Deleted: ' + file_name) + log.info("[" + str(datetime.now()) + "] Deleted: " + file_name) + return self._render_response("Deleted: " + file_name, OK_CODE) - lbry_files = [self._delete_lbry_file(f) for f in self.lbry_file_manager.lbry_files if file_name == f.file_name] + lbry_files = [self._delete_lbry_file(f) for f in self.lbry_file_manager.lbry_files if params.file_name == f.file_name] d = defer.DeferredList(lbry_files) - d.addCallback(lambda _: _disp(file_name)) + d.addCallback(lambda _: _disp(params.file_name)) return d - def xmlrpc_check(self, name): - d = self._check_history(name) - d.addCallback(lambda lbry_file: self._path_from_lbry_file(lbry_file) if lbry_file else 'Not found') - d.addErrback(lambda err: str(err)) + def jsonrpc_publish(self, p): + """ + Make a new name claim - return d + @param: + @return: + """ - def xmlrpc_publish(self, metadata): - try: - metadata = json.loads(metadata) - except: - return defer.succeed(BAD_REQUEST) + params = Bunch(p) - required = ['name', 'file_path', 'bid'] + metadata_fields = {"name": unicode, "file_path": unicode, "bid": float, "author": unicode, "title": unicode, + "description": unicode, "thumbnail": unicode, "key_fee": float, "key_fee_address": unicode, + "content_license": unicode, "sources": dict} - for r in required: - if not r in metadata.keys(): - return defer.succeed(BAD_REQUEST) + for k in metadata_fields.keys(): + if k in params.__dict__.keys(): + if isinstance(params.__dict__[k], metadata_fields[k]): + if type(params.__dict__[k]) == unicode: + metadata_fields[k] = str(params.__dict__[k]) + else: + metadata_fields[k] = params.__dict__[k] + else: + metadata_fields[k] = None + else: + metadata_fields[k] = None - # if not os.path.isfile(metadata['file_path']): - # return defer.fail() - - if not isinstance(metadata['bid'], float) and metadata['bid'] > 0.0: - return defer.fail() - - name = metadata['name'] - file_path = metadata['file_path'] - bid = metadata['bid'] - - if 'title' in metadata.keys(): - title = metadata['title'] - else: - title = None - - if 'description' in metadata.keys(): - description = metadata['description'] - else: - description = None - - if 'thumbnail' in metadata.keys(): - thumbnail = metadata['thumbnail'] - else: - thumbnail = None - - if 'key_fee' in metadata.keys(): - if not float(metadata['key_fee']) == 0.0: - if not 'key_fee_address' in metadata.keys(): - return defer.fail() - key_fee = metadata['key_fee'] - else: - key_fee = 0.0 - - if 'key_fee_address' in metadata.keys(): - key_fee_address = metadata['key_fee_address'] - else: - key_fee_address = None - - if 'content_license' in metadata.keys(): - content_license = metadata['content_license'] - else: - content_license = None - - log.info('[' + str(datetime.now()) + '] Publish: ', name, file_path, bid, title, description, thumbnail, - key_fee, key_fee_address, content_license) + log.info("[" + str(datetime.now()) + "] Publish: ", metadata_fields) p = Publisher(self.session, self.lbry_file_manager, self.session.wallet) - d = p.start(name, file_path, bid, title, description, thumbnail, key_fee, key_fee_address, content_license) - d.addCallback(lambda msg: (OK_CODE, msg)) + d = p.start(name=metadata_fields['name'], + file_path=metadata_fields['file_path'], + bid=metadata_fields['bid'], + title=metadata_fields['title'], + description=metadata_fields['description'], + thumbnail=metadata_fields['thumbnail'], + key_fee=metadata_fields['key_fee'], + key_fee_address=metadata_fields['key_fee_address'], + content_license=metadata_fields['content_license'], + author=metadata_fields['author'], + sources=metadata_fields['sources']) + + d.addCallbacks(lambda msg: self._render_response(msg, OK_CODE), + lambda err: self._render_response(err.getTraceback(), BAD_REQUEST)) return d - def xmlrpc_abandon_name(self, txid): + def jsonrpc_abandon_name(self, p): + """ + Abandon and reclaim credits from a name claim + + @param: {'txid': string} + @return: txid + """ + params = Bunch(p) + def _disp(txid, tx): - print '[' + str(datetime.now()) + '] Spent coins from claim tx ' + txid + ' --> ' + tx - return tx + log.info("[" + str(datetime.now()) + "] Abandoned name claim tx " + txid) + return self._render_response(txid, OK_CODE) d = defer.Deferred() - d.addCallback(lambda _: self.session.wallet.abandon_name(txid)) - d.addCallback(lambda tx: _disp(txid, tx)) - d.addErrback(lambda err: str(err.getTraceback())) + d.addCallback(lambda _: self.session.wallet.abandon_name(params.txid)) + d.addCallback(lambda tx: _disp(params.txid, tx)) + d.addErrback(lambda err: self._render_response(err.getTraceback(), BAD_REQUEST)) d.callback(None) return d - def xmlrpc_get_name_claims(self): + def jsonrpc_get_name_claims(self): + """ + Get name claims + + @return: list of name claims + """ def _clean(claims): for c in claims: for k in c.keys(): if isinstance(c[k], Decimal): c[k] = float(c[k]) - return claims + return self._render_response(claims, OK_CODE) d = self.session.wallet.get_name_claims() d.addCallback(_clean) return d - def xmlrpc_get_time_behind_blockchain(self): + def jsonrpc_get_time_behind_blockchain(self): + """ + Get time behind blockchain + + @return: time behind blockchain + """ d = self.session.wallet.get_most_recent_blocktime() d.addCallback(get_time_behind_blockchain) + d.addCallbacks(lambda result: self._render_response(result, OK_CODE), + lambda result: self._render_response(result, BAD_REQUEST)) return d - def xmlrpc_get_new_address(self): + def jsonrpc_get_new_address(self): + """ + Generate a new wallet address + + @return: new wallet address + """ def _disp(address): - print "[" + str(datetime.now()) + "] Got new wallet address: " + address - return address + log.info("[" + str(datetime.now()) + "] Got new wallet address: " + address) + return json.dumps(self._render_response(address, OK_CODE)) d = self.session.wallet.get_new_address() d.addCallback(_disp) return d - # def xmlrpc_update_name(self, metadata): + # def jsonrpc_update_name(self, metadata): # def _disp(x): # print x # return x @@ -1102,15 +1050,15 @@ class LBRYDaemon(xmlrpc.XMLRPC): # # return d - def xmlrpc_toggle_fetcher_verbose(self): + def jsonrpc_toggle_fetcher_verbose(self): if self.fetcher.verbose: self.fetcher.verbose = False else: self.fetcher.verbose = True - return self.fetcher.verbose + return self._render_response(self.fetcher.verbose, OK_CODE) - def xmlrpc_check_for_new_version(self): + def jsonrpc_check_for_new_version(self): def _check_for_updates(package): git_version = subprocess.check_output("git ls-remote " + package['git'] + " | grep HEAD | cut -f 1", shell=True) up_to_date = False @@ -1147,64 +1095,113 @@ class LBRYDaemon(xmlrpc.XMLRPC): }, } - return [_check_for_updates(package_infos[p]) for p in package_infos.keys()] + r = [_check_for_updates(package_infos[p]) for p in package_infos.keys()] + log.info("[" + str(datetime.now()) + "] Check for new version: " + json.dumps(r)) + return self._render_response(r, OK_CODE) - def xmlrpc_start_status_bar_app(self): - if sys.platform == 'darwin': - if os.path.isdir("/Applications/LBRY.app"): - # subprocess.Popen("screen -dmS lbry-status bash -c 'lbrynet-daemon-status --startdaemon=False'", shell=True) - subprocess.Popen("screen -dmS lbry-status bash -c 'open /Applications/LBRY.app'") - return "Started" - else: - return "Couldn't find LBRY.app, try running the installer" - else: - return "Status bar not implemented on non OS X" - - def xmlrpc___dir__(self): + def jsonrpc___dir__(self): return ['is_running', 'get_settings', 'set_settings', 'start_fetcher', 'stop_fetcher', 'fetcher_status', 'get_balance', 'stop', 'get_lbry_files', 'resolve_name', 'get', 'search_nametrie', 'delete_lbry_file', 'check', 'publish', 'abandon_name', 'get_name_claims', 'get_time_behind_blockchain', 'get_new_address', 'toggle_fetcher_verbose', 'check_for_new_version'] -def stop(): - daemon = xmlrpclib.ServerProxy("http://localhost:7080/") - try: - status = daemon.is_running() - except: - status = False +class LBRYDaemonCommandHandler(object): + def __init__(self, command): + self._api = jsonrpc.Proxy(API_CONNECTION_STRING) + self.command = command - if status: - daemon.stop() - print "LBRYnet daemon stopped" - else: - print "LBRYnet daemon wasn't running" + def run(self, params=None): + if params: + d = self._api.callRemote(self.command, params) + else: + d = self._api.callRemote(self.command) + return d -def main(): - parser = argparse.ArgumentParser(description="Launch lbrynet-daemon") - parser.add_argument("--wallet", - help="lbrycrd or lbryum, default lbryum", - type=str, - default="lbryum") - parser.add_argument("--update", - help="True or false, default true", - type=str, - default="True") +class LBRYindex(resource.Resource): + def __init__(self, ui_dir): + resource.Resource.__init__(self) + self.ui_dir = ui_dir - args = parser.parse_args() + isLeaf = False - try: - daemon = xmlrpclib.ServerProxy("http://localhost:7080") - daemon.stop() - except: - pass + def _delayed_render(self, request, results): + request.write(str(results)) + request.finish() - daemon = LBRYDaemon() - daemon.setup(args.wallet, args.update) - reactor.listenTCP(7080, server.Site(daemon), interface='localhost') - reactor.run() + def getChild(self, name, request): + if name == '': + return self + return resource.Resource.getChild(self, name, request) + + def render_GET(self, request): + return static.File(os.path.join(self.ui_dir, "index.html")).render_GET(request) -if __name__ == '__main__': - main() \ No newline at end of file +class LBRYFileRender(resource.Resource): + isLeaf = False + + def _render_path(self, path): + extension = os.path.splitext(path)[1] + if extension in ['mp4', 'flv', 'mov', 'ogv']: + return r'
' + + def _delayed_render(self, request, results): + request.write(str(results)) + request.finish() + + def render_GET(self, request): + if 'name' in request.args.keys(): + api = jsonrpc.Proxy(API_CONNECTION_STRING) + d = api.callRemote("get", {'name': request.args['name'][0]}) + d.addCallback(lambda response: self._delayed_render(request, self._render_path(json.loads(response)['result']['path'])) + if json.loads(response)['code'] == 200 + else self._delayed_render(request, "Error")) + + return server.NOT_DONE_YET + else: + self._delayed_render(request, "Error") + return server.NOT_DONE_YET + + +# class LBRYFilePage(resource.Resource): +# isLeaf = False +# +# def _delayed_render(self, request, results): +# request.write(str(results)) +# request.finish() +# +# h = "
" +# +# d = LBRYDaemonCommandHandler('get_lbry_files').run() +# d.addCallback(lambda r: json.loads(r)['result']) +# d.addCallback(lambda lbry_files: [h % (json.loads(lbry_file)['file_name'], json.loads(lbry_file)['file_name']) for lbry_file in lbry_files]) +# d.addCallback(lambda r: "
%s
" + ''.join(r) + "") +# d.addCallbacks(lambda results: self._delayed_render(request, results), +# lambda err: self._delayed_render(request, err.getTraceback())) +# +# return server.NOT_DONE_YET + + +class LBRYDaemonWeb(resource.Resource): + isLeaf = False + + def _delayed_render(self, request, results): + request.write(str(results)) + request.setResponseCode(json.loads(results)['code']) + request.finish() + + def render_GET(self, request): + func = request.args['function'][0] + del request.args['function'] + + p = {} + for k in request.args.keys(): + p[k] = request.args[k][0] + + d = LBRYDaemonCommandHandler(func).run(p) + d.addCallbacks(lambda results: self._delayed_render(request, results), + lambda err: self._delayed_render(request, json.dumps({'message': err.getTraceback(), 'code': BAD_REQUEST}))) + + return server.NOT_DONE_YET \ No newline at end of file diff --git a/setup.py b/setup.py index ed9b2a866..22d73b43e 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,15 @@ #!/usr/bin/env python -from setuptools import setup, find_packages -import sys -import os - -base_dir = os.path.abspath(os.path.dirname(__file__)) - - from lbrynet import __version__ +import ez_setup +import sys +import os +from setuptools import setup, find_packages + +base_dir = os.path.abspath(os.path.dirname(__file__)) + +ez_setup.use_setuptools() console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch_lbry_console', 'lbrynet-stdin-uploader = lbrynet.lbrynet_console.LBRYStdinUploader:launch_stdin_uploader', @@ -20,22 +21,25 @@ console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch 'lbrynet-gui = lbrynet.lbrynet_gui.gui:start_gui', 'lbrynet-lookup-hosts-for-hash = lbrynet.dht_scripts:get_hosts_for_hash_in_dht', 'lbrynet-announce_hash_to_dht = lbrynet.dht_scripts:announce_hash_to_dht', - 'lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemon:main', - 'stop-lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemon:stop'] + 'lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemonControl:start', + 'stop-lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemonControl:stop'] +requires = ['pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', + 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', + 'leveldb', 'lbryum', 'jsonrpc', 'simplejson', 'appdirs'] if sys.platform == 'darwin': - console_scripts.append('lbrynet-daemon-status = lbrynet.lbrynet_daemon.LBRYOSXStatusBar:main') - + requires.append('six==1.9.0') +else: + requires.append('six>=1.9.0') gui_data_files = ['close2.gif', 'lbry-dark-242x80.gif', 'lbry-dark-icon.xbm', 'lbry-dark-icon.ico', 'drop_down.gif', 'show_options.gif', 'hide_options.gif', 'lbry.conf'] gui_data_paths = [os.path.join(base_dir, 'lbrynet', 'lbrynet_gui', f) for f in gui_data_files] -setup(name='lbrynet', - version='.'.join([str(x) for x in __version__]), +setup(name='lbrynet', version='.'.join([str(x) for x in __version__]), packages=find_packages(base_dir), - install_requires=['six>=1.9.0', 'pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', 'leveldb', 'lbryum'], + install_requires=requires, entry_points={'console_scripts': console_scripts}, data_files=[ ('lbrynet/lbrynet_console/plugins', @@ -47,4 +51,4 @@ setup(name='lbrynet', ('lbrynet/lbrynet_gui', gui_data_paths) ], dependency_links=['https://github.com/lbryio/lbryum/tarball/master/#egg=lbryum'], - ) + ) \ No newline at end of file From e0b00c09ce02266c70f7132e1c170bc12c7b8d03 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 23 Mar 2016 22:36:14 -0400 Subject: [PATCH 30/32] fix conflicts --- setup.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/setup.py b/setup.py index 0d34ca21e..d0c995765 100644 --- a/setup.py +++ b/setup.py @@ -7,11 +7,8 @@ import sys import os from setuptools import setup, find_packages -<<<<<<< HEAD -======= base_dir = os.path.abspath(os.path.dirname(__file__)) ->>>>>>> development ez_setup.use_setuptools() console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch_lbry_console', @@ -26,20 +23,7 @@ console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch 'lbrynet-announce_hash_to_dht = lbrynet.dht_scripts:announce_hash_to_dht', 'lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemonControl:start', 'stop-lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemonControl:stop'] -<<<<<<< HEAD -======= -requires = ['pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', - 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', - 'leveldb', 'lbryum', 'jsonrpc', 'simplejson', 'appdirs'] ->>>>>>> development - -if sys.platform == 'darwin': - requires.append('six==1.9.0') -else: - requires.append('six>=1.9.0') - -<<<<<<< HEAD requires = ['pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure', 'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0', 'leveldb', 'lbryum', 'jsonrpc', 'simplejson', 'appdirs'] @@ -49,17 +33,12 @@ if sys.platform == 'darwin': else: requires.append('six>=1.9.0') -setup(name='lbrynet', - version='0.0.4', - packages=find_packages(), -======= gui_data_files = ['close2.gif', 'lbry-dark-242x80.gif', 'lbry-dark-icon.xbm', 'lbry-dark-icon.ico', 'drop_down.gif', 'show_options.gif', 'hide_options.gif', 'lbry.conf'] gui_data_paths = [os.path.join(base_dir, 'lbrynet', 'lbrynet_gui', f) for f in gui_data_files] setup(name='lbrynet', version='.'.join([str(x) for x in __version__]), packages=find_packages(base_dir), ->>>>>>> development install_requires=requires, entry_points={'console_scripts': console_scripts}, data_files=[ From 32bb9fd4ec05d4efbc896c6e4d74648d7025a113 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Thu, 24 Mar 2016 20:00:56 -0400 Subject: [PATCH 31/32] reorder setuptools --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d0c995765..31cbc6f32 100644 --- a/setup.py +++ b/setup.py @@ -3,13 +3,13 @@ from lbrynet import __version__ import ez_setup +ez_setup.use_setuptools() import sys import os from setuptools import setup, find_packages base_dir = os.path.abspath(os.path.dirname(__file__)) -ez_setup.use_setuptools() console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch_lbry_console', 'lbrynet-stdin-uploader = lbrynet.lbrynet_console.LBRYStdinUploader:launch_stdin_uploader', From b3cf5e86982df373b2d1ad5575f3a54242fd2894 Mon Sep 17 00:00:00 2001 From: Jack Date: Thu, 24 Mar 2016 20:46:24 -0400 Subject: [PATCH 32/32] add bundle identifier to uri handler --- lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py | 18 +++++++++++++----- setup_uri_handler.py | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py b/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py index ba62a78a4..9bab2e2d8 100644 --- a/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py +++ b/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py @@ -1,16 +1,24 @@ import os import json import webbrowser -import sys -from time import sleep import subprocess +import sys +from time import sleep from jsonrpc.proxy import JSONRPCProxy API_CONNECTION_STRING = "http://localhost:5279/lbryapi" UI_ADDRESS = "http://localhost:5279" +class Timeout(Exception): + def __init__(self, value): + self.parameter = value + + def __str__(self): + return repr(self.parameter) + + class LBRYURIHandler(object): def __init__(self): self.started_daemon = False @@ -28,18 +36,18 @@ class LBRYURIHandler(object): elif status: return True else: - exit(1) + raise Timeout("LBRY daemon is running, but connection timed out") except: if self.start_timeout < 30: sleep(1) self.start_timeout += 1 self.check_status() else: - exit(1) + raise Timeout("Timed out trying to start LBRY daemon") def handle(self, lbry_name): lbry_process = [d for d in subprocess.Popen(['ps','aux'], stdout=subprocess.PIPE).stdout.readlines() - if 'LBRY.app' in d] + if 'LBRY.app' in d and 'LBRYURIHandler' not in d] try: status = json.loads(self.daemon.is_running())['result'] except: diff --git a/setup_uri_handler.py b/setup_uri_handler.py index 1a3c68700..e9ba6749c 100644 --- a/setup_uri_handler.py +++ b/setup_uri_handler.py @@ -7,6 +7,7 @@ OPTIONS = {'argv_emulation': True, 'packages': ['jsonrpc'], 'plist': { 'LSUIElement': True, + 'CFBundleIdentifier': 'io.lbry.LBRYURIHandler', 'CFBundleURLTypes': [ { 'CFBundleURLTypes': 'LBRYURIHandler',