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/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/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/__init__.py b/lbrynet/__init__.py index c53c52efe..eb4d8454c 100644 --- a/lbrynet/__init__.py +++ b/lbrynet/__init__.py @@ -1,4 +1,8 @@ import logging -logging.getLogger(__name__).addHandler(logging.NullHandler()) \ No newline at end of file +logging.getLogger(__name__).addHandler(logging.NullHandler()) + + +version = (0, 2, 0) +__version__ = ".".join([str(x) for x in version]) diff --git a/lbrynet/conf.py b/lbrynet/conf.py index c172884e6..f3903ae6a 100644 --- a/lbrynet/conf.py +++ b/lbrynet/conf.py @@ -26,4 +26,18 @@ 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) +UI_ADDRESS = "http://" + API_INTERFACE + ":" + str(API_PORT) + +PROTOCOL_PREFIX = "lbry" + +DEFAULT_TIMEOUT = 30 \ No newline at end of file diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 09bc1e7bc..cce937c21 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 @@ -67,6 +71,10 @@ class LBRYWallet(object): self.stopped = True self.manage_running = False + self._manage_count = 0 + self._balance_refresh_time = 3 + self._batch_count = 20 + self._first_run = self._FIRST_RUN_UNKNOWN def start(self): @@ -93,16 +101,19 @@ 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): - log.info("Doing manage") + def manage(self, do_full=False): 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 +124,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 +134,28 @@ 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): + if self.wallet_balance != balance: + log.info("Got a new balance: %s", str(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()) @@ -252,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)) @@ -297,10 +316,32 @@ 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', '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: - 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] + 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: d = self._save_name_metadata(name, r_dict['stream_hash'], str(result['txid'])) else: @@ -312,18 +353,20 @@ 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, author=None, sources=None): + 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: 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) @@ -384,6 +427,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) @@ -397,7 +453,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']: @@ -494,7 +555,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): @@ -574,7 +635,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) @@ -836,6 +897,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): @@ -844,7 +908,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() @@ -855,32 +919,42 @@ 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(): - alert.info("Wallet started.") 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(): - 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) @@ -901,9 +975,36 @@ 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: + 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 + + + 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 _: self._catch_up_check.start(.1)) + d.addCallback(lambda _: blockchain_caught_d) return d def _get_cmd_runner(self): @@ -942,7 +1043,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/lbryfilemanager/LBRYFileManager.py b/lbrynet/lbryfilemanager/LBRYFileManager.py index ed4c75a79..59f972df3 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 os import sys +from datetime import datetime + +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 @@ -26,12 +28,14 @@ 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') else: @@ -39,11 +43,35 @@ class LBRYFileManager(object): log.debug("Download directory for LBRYFileManager: %s", str(self.download_directory)) def setup(self): + # 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 get_lbry_file_status(self, lbry_file): return self._get_lbry_file_status(lbry_file.rowid) @@ -152,6 +180,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_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 54e072ec9..cbe5dd270 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: @@ -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() @@ -797,12 +800,22 @@ 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): 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" @@ -849,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 @@ -913,7 +929,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,13 +1866,23 @@ 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)) 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): @@ -1864,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) diff --git a/lbrynet/lbrynet_console/LBRYConsole.py b/lbrynet/lbrynet_console/LBRYConsole.py index c822661e2..fee6c2faa 100644 --- a/lbrynet/lbrynet_console/LBRYConsole.py +++ b/lbrynet/lbrynet_console/LBRYConsole.py @@ -1,5 +1,4 @@ import logging -from lbrynet.core.Session import LBRYSession import os.path import argparse import requests @@ -7,16 +6,17 @@ import locale import sys import webbrowser -from xmlrpclib import ServerProxy +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 twisted.python.failure import Failure +from jsonrpc.proxy import JSONRPCProxy -# from lbrynet.core.client.AutoDownloader import AutoFetcher +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 @@ -259,7 +259,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 @@ -467,96 +467,93 @@ class LBRYConsole(): def launch_lbry_console(): + from twisted.internet import reactor + + parser = argparse.ArgumentParser(description="Launch a lbrynet console") + parser.add_argument("--no_listen_peer", + help="Don't listen for incoming data connections.", + action="store_true") + parser.add_argument("--peer_port", + help="The port on which the console will listen for incoming data connections.", + type=int, default=3333) + parser.add_argument("--no_listen_dht", + help="Don't listen for incoming DHT connections.", + action="store_true") + parser.add_argument("--dht_node_port", + help="The port on which the console will listen for DHT connections.", + type=int, default=4444) + parser.add_argument("--fake_wallet", + help="Testing purposes only. Use a non-blockchain wallet.", + action="store_true") + parser.add_argument("--no_dht_bootstrap", + help="Don't try to connect to the DHT", + action="store_true") + parser.add_argument("--dht_bootstrap_host", + help="The hostname of a known DHT node, to be used to bootstrap into the DHT. " + "Must be used with --dht_bootstrap_port", + type=str, default='104.236.42.182') + parser.add_argument("--dht_bootstrap_port", + help="The port of a known DHT node, to be used to bootstrap into the DHT. Must " + "be used with --dht_bootstrap_host", + type=int, default=4000) + parser.add_argument("--disable_upnp", + help="Don't try to use UPnP to enable incoming connections through the firewall", + action="store_true") + parser.add_argument("--data_dir", + help=("The full path to the directory in which lbrynet data and metadata will be stored. " + "Default: ~/.lbrynet on linux, ~/Library/Application Support/lbrynet on OS X"), + type=str) + parser.add_argument("--lbrycrdd_path", + help="The path to lbrycrdd, which will be launched if it isn't running. If" + "this option is chosen, lbrycrdd will be used as the interface to the" + "blockchain. By default, a lightweight interface is used.") + parser.add_argument("--lbrycrd_wallet_dir", + help="The directory in which lbrycrd data will stored. Used if lbrycrdd is " + "launched by this application.") + parser.add_argument("--lbrycrd_wallet_conf", + help="The configuration file for the LBRYcrd wallet. Default: ~/.lbrycrd/lbrycrd.conf", + type=str) + + args = parser.parse_args() + + if args.no_dht_bootstrap: + bootstrap_nodes = [] + else: + bootstrap_nodes = [(args.dht_bootstrap_host, args.dht_bootstrap_port)] + + if args.no_listen_peer: + peer_port = None + else: + peer_port = args.peer_port + + if args.no_listen_dht: + dht_node_port = None + else: + dht_node_port = args.dht_node_port + + created_data_dir = False + if not args.data_dir: + if sys.platform == "darwin": + data_dir = user_data_dir("LBRY") + else: + data_dir = os.path.join(os.path.expanduser("~"), ".lbrynet") + else: + data_dir = args.data_dir + if not os.path.exists(data_dir): + os.mkdir(data_dir) + created_data_dir = True + + daemon = JSONRPCProxy.from_url(API_CONNECTION_STRING) try: - daemon = ServerProxy("http://localhost:7080") 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" - print "lbrynet-daemon is already running" - print "To use lbrynet-console first close the LBRY status bar app, " \ - "or run stop-lbrynet-daemon if you started it via command line" - print "" - print "Launching browser interface" - - webbrowser.open("lbry://lbry") + webbrowser.open("http://localhost:5279") except: - from twisted.internet import reactor - - parser = argparse.ArgumentParser(description="Launch a lbrynet console") - parser.add_argument("--no_listen_peer", - help="Don't listen for incoming data connections.", - action="store_true") - parser.add_argument("--peer_port", - help="The port on which the console will listen for incoming data connections.", - type=int, default=3333) - parser.add_argument("--no_listen_dht", - help="Don't listen for incoming DHT connections.", - action="store_true") - parser.add_argument("--dht_node_port", - help="The port on which the console will listen for DHT connections.", - type=int, default=4444) - parser.add_argument("--fake_wallet", - help="Testing purposes only. Use a non-blockchain wallet.", - action="store_true") - parser.add_argument("--no_dht_bootstrap", - help="Don't try to connect to the DHT", - action="store_true") - parser.add_argument("--dht_bootstrap_host", - help="The hostname of a known DHT node, to be used to bootstrap into the DHT. " - "Must be used with --dht_bootstrap_port", - type=str, default='104.236.42.182') - parser.add_argument("--dht_bootstrap_port", - help="The port of a known DHT node, to be used to bootstrap into the DHT. Must " - "be used with --dht_bootstrap_host", - type=int, default=4000) - parser.add_argument("--disable_upnp", - help="Don't try to use UPnP to enable incoming connections through the firewall", - action="store_true") - parser.add_argument("--data_dir", - help=("The full path to the directory in which lbrynet data and metadata will be stored. " - "Default: ~/.lbrynet on linux, ~/Library/Application Support/lbrynet on OS X"), - type=str) - parser.add_argument("--lbrycrdd_path", - help="The path to lbrycrdd, which will be launched if it isn't running. If" - "this option is chosen, lbrycrdd will be used as the interface to the" - "blockchain. By default, a lightweight interface is used.") - parser.add_argument("--lbrycrd_wallet_dir", - help="The directory in which lbrycrd data will stored. Used if lbrycrdd is " - "launched by this application.") - parser.add_argument("--lbrycrd_wallet_conf", - help="The configuration file for the LBRYcrd wallet. Default: ~/.lbrycrd/lbrycrd.conf", - type=str) - - args = parser.parse_args() - - if args.no_dht_bootstrap: - bootstrap_nodes = [] - else: - bootstrap_nodes = [(args.dht_bootstrap_host, args.dht_bootstrap_port)] - - if args.no_listen_peer: - peer_port = None - else: - peer_port = args.peer_port - - if args.no_listen_dht: - dht_node_port = None - else: - dht_node_port = args.dht_node_port - - 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") - else: - data_dir = os.path.join(os.path.expanduser("~"), ".lbrynet") - else: - data_dir = args.data_dir - if not os.path.exists(data_dir): - os.mkdir(data_dir) - created_data_dir = True - - log_format = "(%(asctime)s)[%(filename)s:%(lineno)s] %(funcName)s(): %(message)s" formatter = logging.Formatter(log_format) @@ -567,17 +564,16 @@ def launch_lbry_console(): 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) + 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) - 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/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..9bab2e2d8 100644 --- a/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py +++ b/lbrynet/lbrynet_daemon/Apps/LBRYURIHandler.py @@ -1,51 +1,87 @@ import os import json import webbrowser -import xmlrpclib, sys +import subprocess +import sys -def render_video(path): - r = r'
' - return r +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 + self.start_timeout = 0 + self.daemon = JSONRPCProxy.from_url(API_CONNECTION_STRING) + + def check_status(self): + status = None + try: + 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: + 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: + 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 and 'LBRYURIHandler' not in d] + try: + status = json.loads(self.daemon.is_running())['result'] + except: + pass + + 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})) + 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') def main(args): - if len(args) == 0: - args.append('lbry://wonderfullife') + if len(args) != 1: + args = ['lbry://lbry'] - daemon = xmlrpclib.ServerProxy('http://localhost:7080/') - - 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:]) - path = r['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) - - else: - webbrowser.open('file://' + str(path)) - - except: - webbrowser.open('http://lbry.io/get') + 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 941b2316d..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 @@ -42,27 +46,61 @@ from lbrynet.lbryfile.LBRYFileMetadataManager import DBLBRYFileMetadataManager, 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 - -# 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 -class LBRYDaemon(xmlrpc.XMLRPC): +class Bunch: + def __init__(self, params): + self.__dict__.update(params) + + +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,107 +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()) - # if sys.platform == "darwin": - # d.addCallback(lambda _: self._update()) - # d.addCallback(lambda _: self.status_app.run()) - # 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: @@ -326,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, @@ -342,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)) @@ -359,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): @@ -370,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 @@ -399,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()) @@ -410,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: @@ -425,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: @@ -463,7 +437,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 @@ -512,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 @@ -536,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)) @@ -558,9 +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: self._path_from_lbry_file(lbry_file) if lbry_file else 'Not found') - d.addErrback(lambda err: str(err)) + 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 @@ -622,6 +599,8 @@ 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 d.addCallback(lambda _: finish_deletion(lbry_file)) @@ -631,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): @@ -645,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) @@ -670,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 @@ -779,120 +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('No name provided') + 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() - 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: @@ -902,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: @@ -933,144 +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): - metadata = json.loads(metadata) + 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.fail() + 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 = 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 @@ -1090,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 @@ -1135,58 +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" + 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'] + + +class LBRYDaemonCommandHandler(object): + def __init__(self, command): + self._api = jsonrpc.Proxy(API_CONNECTION_STRING) + self.command = command + + def run(self, params=None): + if params: + d = self._api.callRemote(self.command, params) else: - return "Status bar not implemented on non OS X" + d = self._api.callRemote(self.command) + return d -def stop(): - daemon = xmlrpclib.ServerProxy("http://localhost:7080/") - try: - status = daemon.is_running() - except: - status = False +class LBRYindex(resource.Resource): + def __init__(self, ui_dir): + resource.Resource.__init__(self) + self.ui_dir = ui_dir - if status: - daemon.stop() - print "LBRYnet daemon stopped" - else: - print "LBRYnet daemon wasn't running" + isLeaf = False + + def _delayed_render(self, request, results): + 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): + return static.File(os.path.join(self.ui_dir, "index.html")).render_GET(request) -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 LBRYFileRender(resource.Resource): + isLeaf = False - args = parser.parse_args() + def _render_path(self, path): + extension = os.path.splitext(path)[1] + if extension in ['mp4', 'flv', 'mov', 'ogv']: + return r'
' - 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 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 -if __name__ == '__main__': - main() \ No newline at end of file +# class LBRYFilePage(resource.Resource): +# isLeaf = False +# +# def _delayed_render(self, request, results): +# request.write(str(results)) +# request.finish() +# +# h = "%s" +# +# 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: "" + ''.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..ce6540d0c --- /dev/null +++ b/lbrynet/lbrynet_daemon/LBRYDaemonControl.py @@ -0,0 +1,70 @@ +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 +from jsonrpc.proxy import JSONRPCProxy + +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__) +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") + + 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(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 diff --git a/lbrynet/lbrynet_daemon/LBRYDownloader.py b/lbrynet/lbrynet_daemon/LBRYDownloader.py index 4ea161c81..4552cd4af 100644 --- a/lbrynet/lbrynet_daemon/LBRYDownloader.py +++ b/lbrynet/lbrynet_daemon/LBRYDownloader.py @@ -1,18 +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): + def __init__(self, sd_identifier, session, wallet, lbry_file_manager, max_key_fee, pay_key=True, data_rate=0.5, + timeout=DEFAULT_TIMEOUT): self.wallet = wallet self.resolved_name = None self.description = None @@ -29,8 +34,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(): @@ -48,28 +70,29 @@ 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 - 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.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(): @@ -77,7 +100,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) @@ -88,7 +111,8 @@ class GetStream(object): downloader.start() - print "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 _: log.info("Downloading " + str(self.stream_hash) + " --> " + str(self.download_path))) return d @@ -116,15 +140,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: @@ -156,19 +181,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: @@ -178,8 +199,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): @@ -203,12 +222,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..ea7c015a3 100644 --- a/lbrynet/lbrynet_daemon/LBRYPublisher.py +++ b/lbrynet/lbrynet_daemon/LBRYPublisher.py @@ -33,14 +33,16 @@ 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://" + \ str(self.publish_name) + " with txid: " + str(self.tx_hash) - print message + log.info(message) return defer.succeed(message) self.publish_name = name @@ -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 @@ -122,6 +127,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/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 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 diff --git a/setup.py b/setup.py index 68d476243..31cbc6f32 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,15 @@ #!/usr/bin/env python +from lbrynet import __version__ + import ez_setup ez_setup.use_setuptools() -from setuptools import setup, find_packages import sys +import os +from setuptools import setup, find_packages + +base_dir = os.path.abspath(os.path.dirname(__file__)) + console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch_lbry_console', 'lbrynet-stdin-uploader = lbrynet.lbrynet_console.LBRYStdinUploader:launch_stdin_uploader', @@ -15,36 +21,34 @@ 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='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'], +setup(name='lbrynet', version='.'.join([str(x) for x in __version__]), + packages=find_packages(base_dir), + install_requires=requires, 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 + ) diff --git a/setup_osx.py b/setup_osx.py deleted file mode 100644 index 052b51235..000000000 --- a/setup_osx.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -from setuptools import setup - -APP = [os.path.join('lbrynet', 'lbrynet_daemon', 'Apps', 'LBRYOSXStatusBar.py')] -DATA_FILES = [] -OPTIONS = { - 'argv_emulation': True, - 'iconfile': 'app.icns', - 'plist': { - 'LSUIElement': True, - }, - 'includes': ['rumps'] -} - - -setup( - name='LBRY', - app=APP, - data_files=DATA_FILES, - options={'py2app': OPTIONS}, - setup_requires=['py2app'], -) \ No newline at end of file diff --git a/setup_uri_handler.py b/setup_uri_handler.py index 37a38826e..e9ba6749c 100644 --- a/setup_uri_handler.py +++ b/setup_uri_handler.py @@ -4,7 +4,10 @@ import os APP = [os.path.join('lbrynet', 'lbrynet_daemon', 'Apps', 'LBRYURIHandler.py')] DATA_FILES = [] OPTIONS = {'argv_emulation': True, + 'packages': ['jsonrpc'], 'plist': { + 'LSUIElement': True, + 'CFBundleIdentifier': 'io.lbry.LBRYURIHandler', 'CFBundleURLTypes': [ { 'CFBundleURLTypes': 'LBRYURIHandler',