From 578780207726b93dd0af9612f2839bc34bd0ecc7 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Thu, 15 Oct 2015 14:12:22 -0400 Subject: [PATCH] change the console ui to command based rather than option based --- lbrynet/core/DownloadOption.py | 7 +- lbrynet/lbryfile/client/LBRYFileOptions.py | 28 +- lbrynet/lbrylive/client/LiveStreamOptions.py | 50 +- lbrynet/lbrynet_console/CommandHandlers.py | 40 - lbrynet/lbrynet_console/ConsoleControl.py | 91 +- lbrynet/lbrynet_console/ControlHandlers.py | 1134 +++++++++++------ lbrynet/lbrynet_console/LBRYConsole.py | 85 +- lbrynet/lbrynet_console/interfaces.py | 10 + .../BlindRepeaterControlHandlers.py | 165 +-- 9 files changed, 934 insertions(+), 676 deletions(-) delete mode 100644 lbrynet/lbrynet_console/CommandHandlers.py diff --git a/lbrynet/core/DownloadOption.py b/lbrynet/core/DownloadOption.py index 0e990902e..87964fa46 100644 --- a/lbrynet/core/DownloadOption.py +++ b/lbrynet/core/DownloadOption.py @@ -1,4 +1,8 @@ -class DownloadChoice(object): +class DownloadOptionChoice(object): + """A possible choice that can be picked for some option. + + An option can have one or more choices that can be picked from. + """ def __init__(self, value, short_description, long_description, bool_options_description=None): self.value = value self.short_description = short_description @@ -7,6 +11,7 @@ class DownloadChoice(object): class DownloadOption(object): + """An option for a user to select a value from several different choices.""" def __init__(self, option_types, long_description, short_description, default_value, default_value_description): self.option_types = option_types diff --git a/lbrynet/lbryfile/client/LBRYFileOptions.py b/lbrynet/lbryfile/client/LBRYFileOptions.py index daa4f899c..551448a15 100644 --- a/lbrynet/lbryfile/client/LBRYFileOptions.py +++ b/lbrynet/lbryfile/client/LBRYFileOptions.py @@ -1,5 +1,5 @@ from lbrynet.lbryfile.StreamDescriptor import LBRYFileStreamType, LBRYFileStreamDescriptorValidator -from lbrynet.core.DownloadOption import DownloadOption, DownloadChoice +from lbrynet.core.DownloadOption import DownloadOption, DownloadOptionChoice def add_lbry_file_to_sd_identifier(sd_identifier): @@ -20,16 +20,16 @@ class LBRYFileOptions(object): return "%f LBC/MB" % prm.min_blob_data_payment_rate rate_choices = [] - rate_choices.append(DownloadChoice(prm.min_blob_data_payment_rate, - "No change - %s" % get_default_data_rate_description(), - "No change - %s" % get_default_data_rate_description())) + rate_choices.append(DownloadOptionChoice(prm.min_blob_data_payment_rate, + "No change - %s" % get_default_data_rate_description(), + "No change - %s" % get_default_data_rate_description())) if prm.min_blob_data_payment_rate is not None: - rate_choices.append(DownloadChoice(None, - "Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate), - "Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate))) - rate_choices.append(DownloadChoice(float, - "Enter rate in LBC/MB", - "Enter rate in LBC/MB")) + rate_choices.append(DownloadOptionChoice(None, + "Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate), + "Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate))) + rate_choices.append(DownloadOptionChoice(float, + "Enter rate in LBC/MB", + "Enter rate in LBC/MB")) options = [ DownloadOption( @@ -41,10 +41,10 @@ class LBRYFileOptions(object): ), DownloadOption( [ - DownloadChoice(bool, - None, - None, - bool_options_description=("Allow", "Disallow")), + DownloadOptionChoice(bool, + None, + None, + bool_options_description=("Allow", "Disallow")), ], "Allow reuploading data downloaded for this file", "allow upload", diff --git a/lbrynet/lbrylive/client/LiveStreamOptions.py b/lbrynet/lbrylive/client/LiveStreamOptions.py index 04f78c62b..4568edb6d 100644 --- a/lbrynet/lbrylive/client/LiveStreamOptions.py +++ b/lbrynet/lbrylive/client/LiveStreamOptions.py @@ -1,5 +1,5 @@ from lbrynet.lbrylive.StreamDescriptor import LiveStreamType, LBRYLiveStreamDescriptorValidator -from lbrynet.core.DownloadOption import DownloadOption, DownloadChoice +from lbrynet.core.DownloadOption import DownloadOption, DownloadOptionChoice def add_live_stream_to_sd_identifier(sd_identifier, base_live_stream_payment_rate_manager): @@ -23,15 +23,15 @@ class LiveStreamOptions(object): options = [ DownloadOption( [ - DownloadChoice(None, - "No change", - "No change"), - DownloadChoice(None, - "Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate), - "Default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate)), - DownloadChoice(float, - "Rate in LBC/MB", - "Rate in LBC/MB") + DownloadOptionChoice(None, + "No change", + "No change"), + DownloadOptionChoice(None, + "Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate), + "Default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate)), + DownloadOptionChoice(float, + "Rate in LBC/MB", + "Rate in LBC/MB") ], "rate which will be paid for data", "data payment rate", @@ -40,15 +40,15 @@ class LiveStreamOptions(object): ), DownloadOption( [ - DownloadChoice(None, - "No change", - "No change"), - DownloadChoice(None, - "Application default (%s LBC/MB)" % str(self.base_live_stream_prm.min_live_blob_info_payment_rate), - "Default (%s LBC/MB)" % str(self.base_live_stream_prm.min_live_blob_info_payment_rate)), - DownloadChoice(float, - "Rate in LBC/MB", - "Rate in LBC/MB") + DownloadOptionChoice(None, + "No change", + "No change"), + DownloadOptionChoice(None, + "Application default (%s LBC/MB)" % str(self.base_live_stream_prm.min_live_blob_info_payment_rate), + "Default (%s LBC/MB)" % str(self.base_live_stream_prm.min_live_blob_info_payment_rate)), + DownloadOptionChoice(float, + "Rate in LBC/MB", + "Rate in LBC/MB") ], "rate which will be paid for metadata", "metadata payment rate", @@ -57,12 +57,12 @@ class LiveStreamOptions(object): ), DownloadOption( [ - DownloadChoice(True, - "Allow reuploading data downloaded for this file", - "Allow reuploading"), - DownloadChoice(False, - "Disallow reuploading data downloaded for this file", - "Disallow reuploading") + DownloadOptionChoice(True, + "Allow reuploading data downloaded for this file", + "Allow reuploading"), + DownloadOptionChoice(False, + "Disallow reuploading data downloaded for this file", + "Disallow reuploading") ], "allow reuploading data downloaded for this file", "allow upload", diff --git a/lbrynet/lbrynet_console/CommandHandlers.py b/lbrynet/lbrynet_console/CommandHandlers.py deleted file mode 100644 index 2e1eb0b91..000000000 --- a/lbrynet/lbrynet_console/CommandHandlers.py +++ /dev/null @@ -1,40 +0,0 @@ -import logging -from zope.interface import implements -from twisted.internet import defer -from lbrynet.lbrynet_console.interfaces import ICommandHandlerFactory, ICommandHandler - -log = logging.getLogger(__name__) - - -class CommandHandlerFactory(object): - implements(ICommandHandlerFactory) - short_help = "This should be overridden" - full_help = "This should really be overridden" - control_handler_class = None - - def __init__(self, *args): - self.args = args - - def get_handler(self, *args): - all_args = self.args + args - return self.control_handler_class(*all_args) - - -class CommandHandler(object): - implements(ICommandHandler) - - def __init__(self): - self.finished_deferred = defer.Deferred() - - def handle_line(self): - raise NotImplementedError() - - -class AddStream(CommandHandler): - pass - - -class AddStreamFactory(CommandHandlerFactory): - control_handler_class = AddStream - short_help = "Pull from the network" - full_help = "Pull from the network" \ No newline at end of file diff --git a/lbrynet/lbrynet_console/ConsoleControl.py b/lbrynet/lbrynet_console/ConsoleControl.py index 54eb2d276..367e3eb29 100644 --- a/lbrynet/lbrynet_console/ConsoleControl.py +++ b/lbrynet/lbrynet_console/ConsoleControl.py @@ -9,66 +9,8 @@ log = logging.getLogger(__name__) class ConsoleControl(basic.LineReceiver): from os import linesep as delimiter - def __init__(self, control_handlers): - self.control_handlers = {} - self.categories = {} - categories = set([category for category, handler in control_handlers]) - prompt_number = 0 - for category in categories: - self.categories[prompt_number] = category - for handler in [handler for cat, handler in control_handlers if cat == category]: - self.control_handlers[prompt_number] = handler - prompt_number += 1 - self.current_handler = None - - def connectionMade(self): - self.show_prompt() - - def lineReceived(self, line): - - def show_response(response): - if response is not None: - self.sendLine(response) - - def show_error(err): - self.sendLine(err.getErrorMessage()) - - if self.current_handler is None: - try: - num = int(line) - except ValueError: - num = None - if num in self.control_handlers: - self.current_handler = self.control_handlers[num].get_handler() - line = None - if self.current_handler is not None: - try: - r = self.current_handler.handle_line(line) - done, ds = r[0], [d for d in r[1:] if d is not None] - except Exception as e: - done = True - ds = [defer.fail(e)] - if done is True: - self.current_handler = None - map(lambda d: d.addCallbacks(show_response, show_error), ds) - if self.current_handler is None: - self.show_prompt() - - def show_prompt(self): - self.sendLine("Options:") - for num, handler in self.control_handlers.iteritems(): - if num in self.categories: - self.sendLine("") - self.sendLine(self.categories[num]) - self.sendLine("") - self.sendLine("[" + str(num) + "] " + handler.get_prompt_description()) - - -class ConsoleControl2(basic.LineReceiver): - from os import linesep as delimiter - def __init__(self, command_handlers): - self.command_handlers = command_handlers + self.command_handlers = {h.command: h for h in command_handlers} self.current_handler = None def connectionMade(self): @@ -79,7 +21,7 @@ class ConsoleControl2(basic.LineReceiver): self.transport.write(s) def show_prompt(self): - self.send(">") + self.send("> ") def show_help_overview(self): self.sendLine("Available commands:") @@ -93,9 +35,18 @@ class ConsoleControl2(basic.LineReceiver): self.current_handler = None self.show_prompt() + def handler_failed(self, err): + self.current_handler = None + self.sendLine("An error occurred:") + self.sendLine(err.getTraceback()) + self.show_prompt() + def lineReceived(self, line): if self.current_handler is None: words = line.split() + if len(words) == 0: + self.show_prompt() + return command, args = words[0], words[1:] if command == "help": if len(args) == 0: @@ -127,22 +78,32 @@ class ConsoleControl2(basic.LineReceiver): else: command_handler = self.command_handlers[candidates[0]] try: - self.current_handler = command_handler.get_handler(self, *args) - except Exception as e: + self.current_handler = command_handler.get_handler(self) + except Exception: self.current_handler = None import traceback - self.sendline(traceback.format_exc()) + self.sendLine(traceback.format_exc()) log.error(traceback.format_exc()) self.show_prompt() return - self.current_handler.finished_deferred.addCallback(lambda _: self.handler_done()) + try: + self.current_handler.start(*args) + except TypeError: + self.current_handler = None + self.sendLine("Invalid arguments. Type 'help ' for the argument list.") + import traceback + log.error(traceback.format_exc()) + self.show_prompt() + return + self.current_handler.finished_deferred.addCallbacks(lambda _: self.handler_done(), + self.handler_failed) else: try: self.current_handler.handle_line(line) except Exception as e: self.current_handler = None import traceback - self.sendline(traceback.format_exc()) + self.sendLine(traceback.format_exc()) log.error(traceback.format_exc()) self.show_prompt() return \ No newline at end of file diff --git a/lbrynet/lbrynet_console/ControlHandlers.py b/lbrynet/lbrynet_console/ControlHandlers.py index feeb64bb5..7926ee180 100644 --- a/lbrynet/lbrynet_console/ControlHandlers.py +++ b/lbrynet/lbrynet_console/ControlHandlers.py @@ -5,7 +5,7 @@ from lbrynet.core.PaymentRateManager import PaymentRateManager from lbrynet.lbryfilemanager.LBRYFileCreator import create_lbry_file from lbrynet.lbryfilemanager.LBRYFileDownloader import ManagedLBRYFileDownloader from lbrynet.lbryfile.StreamDescriptor import get_sd_info -from lbrynet.lbrynet_console.interfaces import IControlHandler, IControlHandlerFactory +from lbrynet.lbrynet_console.interfaces import ICommandHandler, ICommandHandlerFactory from lbrynet.core.StreamDescriptor import download_sd_blob, BlobStreamDescriptorReader from lbrynet.core.Error import UnknownNameError, InvalidBlobHashError, InsufficientFundsError from lbrynet.core.Error import InvalidStreamInfoError @@ -24,31 +24,84 @@ class InvalidValueError(Exception): pass -class ControlHandlerFactory(object): - implements(IControlHandlerFactory) +#class ControlHandlerFactory(object): +# implements(IControlHandlerFactory) +# control_handler_class = None + +# def get_prompt_description(self): +# return self.control_handler_class.prompt_description + +# def __init__(self, *args): +# self.args = args + +# def get_handler(self): +# args = self.args +# return self.control_handler_class(*args) + + +#class ControlHandler(object): +# implements(IControlHandler) + +# prompt_description = None + + +class CommandHandlerFactory(object): + implements(ICommandHandlerFactory) + short_help = "This should be overridden" + full_help = "This should really be overridden" + command = "this-must-be-overridden" control_handler_class = None - def get_prompt_description(self): - return self.control_handler_class.prompt_description - def __init__(self, *args): self.args = args - def get_handler(self): - args = self.args - return self.control_handler_class(*args) + def get_prompt_description(self): + return self.control_handler_class.prompt_description + + def get_handler(self, console): + return self.control_handler_class(console, *self.args) -class ControlHandler(object): - implements(IControlHandler) +class CommandHandler(object): + implements(ICommandHandler) prompt_description = None + def __init__(self, console): + self.console = console + self.finished_deferred = defer.Deferred() -class RecursiveControlHandler(ControlHandler): + def start(self): + pass - def __init__(self, exit_after_one_done=False, reset_after_each_done=False): + def handle_line(self, line): + pass + + +def get_shortcuts_for_options(option_names): + shortcut_keys = [] + names_with_shortcuts = [] + for option_name in option_names: + name_with_shortcut = '' + found_shortcut = False + for c in option_name: + if not found_shortcut and not c.lower() in shortcut_keys: + name_with_shortcut += '[' + c.lower() + ']' + shortcut_keys.append(c.lower()) + found_shortcut = True + else: + name_with_shortcut += c + if found_shortcut is False: + shortcut_keys.append("") + names_with_shortcuts.append(name_with_shortcut) + return shortcut_keys, names_with_shortcuts + + +class RecursiveCommandHandler(CommandHandler): + + def __init__(self, console, exit_after_one_done=False, reset_after_each_done=False): + CommandHandler.__init__(self, console) self.current_handler = None self.exit_after_one_done = exit_after_one_done self.reset_after_each_done = reset_after_each_done @@ -60,6 +113,22 @@ class RecursiveControlHandler(ControlHandler): def _set_control_handlers(self): self.control_handlers = {i + 1: handler for i, handler in enumerate(self._get_control_handler_factories())} + def start(self): + self._show_prompt() + + def handler_finished(self): + self.current_handler = None + if self.exit_after_one_done is True: + self.finished_deferred.callback(None) + else: + if self.reset_after_each_done: + self._set_control_handlers() + self._show_prompt() + + def handler_failed(self, err): + log.error("An error occurred in some handler: %s", err.getTraceback()) + self.finished_deferred.callback(None) + def handle_line(self, line): if self.current_handler is None: if line is None: @@ -70,53 +139,58 @@ class RecursiveControlHandler(ControlHandler): except ValueError: num = None if num == 0: - return True, None + self.finished_deferred.callback(None) + return if num in self.control_handlers: - self.current_handler = self.control_handlers[num].get_handler() - line = None - ds = [] + self.current_handler = self.control_handlers[num].get_handler(self.console) + self.current_handler.finished_deferred.addCallbacks(lambda _: self.handler_finished(), + self.handler_failed) + self.current_handler.start() + return if self.current_handler is not None: - r = self.current_handler.handle_line(line) - done, ds = r[0], list(r[1:]) - if done is True: - self.current_handler = None - if self.exit_after_one_done is True: - return r - if self.reset_after_each_done: - self._set_control_handlers() + self.current_handler.handle_line(line) + return if self.current_handler is None: - ds += [self.get_prompt()] - return (False,) + tuple(ds) + self._show_prompt() - def get_prompt(self): + def _show_prompt(self): prompt_string = "Options:\n" prompt_string += "[0] Exit this menu\n" for num, handler in self.control_handlers.iteritems(): prompt_string += "[" + str(num) + "] " + handler.get_prompt_description() + "\n" - return defer.succeed(prompt_string) + self.console.sendLine(prompt_string) -class ModifyPaymentRate(ControlHandler): +class ModifyPaymentRate(CommandHandler): - def __init__(self): + def __init__(self, console): + CommandHandler.__init__(self, console) self._prompt_choices = {'cancel': (self._cancel, "Don't change anything")} + self.got_input = False + + def start(self): + self._show_prompt_string() def handle_line(self, line): - if line is None: - return False, defer.succeed(self._get_prompt_string()) - elif line.lower() in self._prompt_choices: - return self._prompt_choices[line.lower()][0]() - else: - try: - rate = float(line) - except ValueError: - return True, defer.succeed("Rate must be a number") - d = self._set_rate(rate) - d.addCallback(lambda _: "Successfully set the rate") - return True, d + if self.got_input is False: + self.got_input = True + if line.lower() in self._prompt_choices: + d = self._prompt_choices[line.lower()][0]() + d.addCallback(self._choice_made) + else: + try: + rate = float(line) + except ValueError: + self.console.sendLine("Rate must be a number") + self.finished_deferred.callback(None) + return + d = self._set_rate(rate) - def _cancel(self): - return True, defer.succeed("No change was made") + d.addCallback(lambda _: self._choice_made("Successfully set the rate")) + + @staticmethod + def _cancel(): + return defer.succeed("No change was made") def _set_rate(self, rate): pass @@ -124,45 +198,67 @@ class ModifyPaymentRate(ControlHandler): def _get_current_status(self): pass - def _get_prompt_string(self): + def _choice_made(self, result=None): + if result is not None: + self.console.sendLine(result) + self.finished_deferred.callback(None) + + def _show_prompt_string(self): prompt_string = self._get_current_status() + "\n" for prompt_choice, (func, help_string) in self._prompt_choices.iteritems(): prompt_string += prompt_choice + ": " + help_string + "\n" prompt_string += "To change the current rate, enter the desired rate\n" prompt_string += "Then hit enter\n" - return prompt_string + self.console.sendLine(prompt_string) -class ApplicationStatus(ControlHandler): - prompt_description = "Application Status" +class ApplicationStatus(CommandHandler): + #prompt_description = "Application Status" - def __init__(self, rate_limiter, dht_node): + def __init__(self, console, rate_limiter, dht_node): + CommandHandler.__init__(self, console) self.rate_limiter = rate_limiter self.dht_node = dht_node - def handle_line(self, line): - assert line is None, "Application status should not be passed any arguments" + def start(self): + d = self._show_status() + d.chainDeferred(self.finished_deferred) + return d + + def _show_status(self): status = "Total bytes uploaded: " + str(self.rate_limiter.total_ul_bytes) + "\n" status += "Total bytes downloaded: " + str(self.rate_limiter.total_dl_bytes) + "\n" if self.dht_node is not None: status += "Approximate number of nodes in DHT: " + str(self.dht_node.getApproximateTotalDHTNodes()) + "\n" status += "Approximate number of blobs in DHT: " + str(self.dht_node.getApproximateTotalHashes()) + "\n" - return True, defer.succeed(status) + self.console.sendLine(status) + return defer.succeed(None) -class ApplicationStatusFactory(ControlHandlerFactory): +class ApplicationStatusFactory(CommandHandlerFactory): control_handler_class = ApplicationStatus + command = "application-status" + short_help = "Show application status" + full_help = "Show total bytes uploaded to other peers, total bytes downloaded from peers," \ + " approximate number of nodes in the DHT, and approximate number of hashes" \ + " in the DHT" -class GetWalletBalances(ControlHandler): - prompt_description = "Show wallet point balances" +class GetWalletBalances(CommandHandler): + #prompt_description = "Show wallet point balances" - def __init__(self, wallet): + def __init__(self, console, wallet): + CommandHandler.__init__(self, console) self.wallet = wallet - def handle_line(self, line): - assert line is None, "Show wallet balances should not be passed any arguments" - return True, self._get_wallet_balances() + def start(self): + d = self._get_wallet_balances() + d.chainDeferred(self.finished_deferred) + return d + + #def handle_line(self, line): + # assert line is None, "Show wallet balances should not be passed any arguments" + # return True, self._get_wallet_balances() def _get_wallet_balances(self): d = self.wallet.get_balance() @@ -171,98 +267,135 @@ class GetWalletBalances(ControlHandler): if balance == 0: balance = 0 balance_string = "balance: " + str(balance) + " LBC\n" - return balance_string + self.console.sendLine(balance_string) d.addCallback(format_balance) return d -class GetWalletBalancesFactory(ControlHandlerFactory): +class GetWalletBalancesFactory(CommandHandlerFactory): control_handler_class = GetWalletBalances + command = "wallet-balance" + short_help = "Show LBRYcrd balance" + full_help = "Show the LBRYcrd balance of the wallet to which this application is connected" -class GetNewWalletAddress(ControlHandler): - prompt_description = "Get a new LBRYcrd address" +class GetNewWalletAddress(CommandHandler): + #prompt_description = "Get a new LBRYcrd address" - def __init__(self, wallet): + def __init__(self, console, wallet): + CommandHandler.__init__(self, console) self.wallet = wallet - def handle_line(self, line): - assert line is None, "Get new LBRYcrd address should not be passed any arguments" + def start(self): + d = self._get_new_address() + d.chainDeferred(self.finished_deferred) + return d + + def _get_new_address(self): + #assert line is None, "Get new LBRYcrd address should not be passed any arguments" d = self.wallet.get_new_address() - d.addCallback(lambda address: str(address)) - return True, d + + def show_address(address): + self.console.sendLine(str(address)) + + d.addCallback(show_address) + return d -class GetNewWalletAddressFactory(ControlHandlerFactory): +class GetNewWalletAddressFactory(CommandHandlerFactory): control_handler_class = GetNewWalletAddress + command = "get-new-address" + short_help = "Get a new LBRYcrd address" + full_help = "Get a new LBRYcrd address from the wallet to which this application is connected" -class ShutDown(ControlHandler): - prompt_description = "Shut down" +class ShutDown(CommandHandler): + #prompt_description = "Shut down" - def __init__(self, lbry_service): + def __init__(self, console, lbry_service): + CommandHandler.__init__(self, console) self.lbry_service = lbry_service - def handle_line(self, line): - assert line is None, "Shut down should not be passed any arguments" - return True, self._shut_down() + def start(self): + d = self._shut_down() + return d + + #def handle_line(self, line): + # assert line is None, "Shut down should not be passed any arguments" + # return True, self._shut_down() def _shut_down(self): d = self.lbry_service.shut_down() def stop_reactor(): from twisted.internet import reactor + self.console.sendLine("Shutting down.") reactor.stop() d.addBoth(lambda _: stop_reactor()) - - d.addCallback(lambda _: "Shut down successfully") return d -class ShutDownFactory(ControlHandlerFactory): +class ShutDownFactory(CommandHandlerFactory): control_handler_class = ShutDown + command = "exit" + short_help = "Shut down" + full_help = "Shut down" -class LBRYFileStatus(ControlHandler): - prompt_description = "Print status information for all LBRY Files" +class LBRYFileStatus(CommandHandler): + #prompt_description = "Print status information for all LBRY Files" - def __init__(self, lbry_file_manager): + def __init__(self, console, lbry_file_manager): + CommandHandler.__init__(self, console) self.lbry_file_manager = lbry_file_manager - def handle_line(self, line): - assert line is None, "print status should not be passed any arguments" + def start(self): d = self.lbry_file_manager.get_lbry_file_status_reports() - d.addCallback(self.format_statuses) - return True, d + d.addCallback(self._show_statuses) + d.chainDeferred(self.finished_deferred) + return d - def format_statuses(self, status_reports): + #def handle_line(self, line): + # assert line is None, "print status should not be passed any arguments" + # d = self.lbry_file_manager.get_lbry_file_status_reports() + # d.addCallback(self.format_statuses) + # return True, d + + def _show_statuses(self, status_reports): status_strings = [] for status_report in status_reports: s = status_report.name + " status: " + status_report.running_status + "\n" s += str(status_report.num_completed) + " completed out of " + str(status_report.num_known) + "\n" status_strings.append(s) - return ''.join(status_strings) + self.console.sendLine(''.join(status_strings)) -class LBRYFileStatusFactory(ControlHandlerFactory): +class LBRYFileStatusFactory(CommandHandlerFactory): control_handler_class = LBRYFileStatus + command = "lbryfile-status" + short_help = "Print status information for LBRY files" + full_help = "Print the status information for all streams that are being saved to disk." \ + "This includes whether the stream is currently downloading and teh progress" \ + "of the download." -class AddStream(ControlHandler): - prompt_description = None - line_prompt = None +class AddStream(CommandHandler): + #prompt_description = None + #line_prompt = None cancel_prompt = "Trying to locate the stream's metadata. Type \"cancel\" to cancel..." - canceled_message = "Canceled locating the stream's metadata." - line_prompt2 = "Modify options? (y/n)" - line_prompt3 = "Start download? (y/n)" + canceled_message = "Canceled downloading." - def __init__(self, sd_identifier, base_payment_rate_manager): + def __init__(self, console, sd_identifier, base_payment_rate_manager): + CommandHandler.__init__(self, console) self.sd_identifier = sd_identifier self.loading_metadata_deferred = None self.metadata = None self.factory = None + self.factory_choice_strings = None # (command, command_string, shortcut) + self.factory_choices = None # {command: factory} + self.download_options = [] self.options_left = [] self.options_chosen = [] self.current_option = None @@ -272,73 +405,112 @@ class AddStream(ControlHandler): self.loading_failed = False self.payment_rate_manager = PaymentRateManager(base_payment_rate_manager) + def start(self): + self.console.sendLine(self.cancel_prompt) + self.loading_metadata_deferred.addCallback(self._handle_metadata) + self.loading_metadata_deferred.addErrback(self._handle_load_canceled) + self.loading_metadata_deferred.addErrback(self._handle_load_failed) + def handle_line(self, line): - if line is None: - return False, defer.succeed(self.line_prompt) - if self.loading_failed is True: - return True, None + # first, print that metadata is being looked up. give the option to cancel, and + # listen for the word cancel + # when that's done, present the metadata, how to change options, how to cancel, + # and list the ways to download + # + # + #if line is None: + # return False, defer.succeed(self.line_prompt) + #if self.loading_failed is True: + # return True, None if self.loading_metadata_deferred is not None: if line.lower() == "cancel": self.loading_metadata_deferred.cancel() self.loading_metadata_deferred = None - return True, None else: - return False, defer.succeed(self.cancel_prompt) - if self.metadata is None: - self.loading_metadata_deferred = self._load_metadata(line) - cancel_prompt_d = defer.succeed(self.cancel_prompt) - self.loading_metadata_deferred.addCallback(self._choose_factory) - self.loading_metadata_deferred.addErrback(self._handle_load_canceled) - self.loading_metadata_deferred.addErrback(self._handle_load_failed) - return False, cancel_prompt_d, self.loading_metadata_deferred - if self.factory is None: - try: - choice = int(line) - except ValueError: - return False, defer.succeed(self._show_factory_choices()) - if choice in xrange(len(self.metadata.factories)): - self.factory = self.metadata.factories[choice] - return False, defer.succeed(self._show_info_and_options()) - else: - return False, defer.succeed(self._show_factory_choices()) - if self.got_options_response is False: - self.got_options_response = True - if line == 'y' or line == 'Y' and self.options_left: - return False, defer.succeed(self._get_next_option_prompt()) - else: - self.options_chosen = [option.default_value for option in self.options_left] - self.options_left = [] - return False, defer.succeed(self.line_prompt3) + self.console.sendLine(self.cancel_prompt) + return + + #if self.metadata is None: + # self.loading_metadata_deferred = self._load_metadata(line) + # cancel_prompt_d = defer.succeed(self.cancel_prompt) + # self.loading_metadata_deferred.addCallback(self._choose_factory) + # self.loading_metadata_deferred.addErrback(self._handle_load_canceled) + # self.loading_metadata_deferred.addErrback(self._handle_load_failed) + # return False, cancel_prompt_d, self.loading_metadata_deferred + if self.current_option is not None: if self.current_choice is None: try: self.current_choice = self._get_choice_from_input(line) except InvalidChoiceError: - return False, defer.succeed(self._get_next_option_prompt(invalid_choice=True)) + self.console.sendLine(self._get_next_option_prompt(invalid_choice=True)) + return choice = self.current_option.option_types[self.current_choice] if choice.value == float or choice.value == bool: - return False, defer.succeed(self._get_choice_value_prompt()) + self.console.sendLine(self._get_choice_value_prompt()) + return else: value = choice.value else: try: value = self._get_value_for_choice(line) except InvalidValueError: - return False, defer.succeed(self._get_choice_value_prompt(invalid_value=True)) + self.console.sendLine(self._get_choice_value_prompt(invalid_value=True)) + return self.options_chosen.append(value) self.current_choice = None self.current_option = None self.options_left = self.options_left[1:] if self.options_left: - return False, defer.succeed(self._get_next_option_prompt()) + self.console.sendLine(self._get_next_option_prompt()) + return else: self.current_option = None - return False, defer.succeed(self.line_prompt3) - if line == 'y' or line == 'Y': - d = self._start_download() - else: - d = defer.succeed("Download cancelled") - return True, d + self._show_factory_choices() + return + if self.factory_choice_strings is not None: + command = self._get_factory_choice_command(line) + if command == "cancel": + self.console.sendLine(self.canceled_message) + self.finished_deferred.callback(None) + elif command == "options": + self.options_left = self.download_options[:] + self.options_chosen = [] + self.console.sendLine(self._get_next_option_prompt()) + else: + if command in self.factory_choices: + self.factory = self.factory_choices[command] + self._start_download() + self.console.sendLine("Downloading in the background") + self.finished_deferred.callback(None) + else: + self._show_factory_choices() + return + + #if self.factory is None: + # try: + # choice = int(line) + # except ValueError: + # return False, defer.succeed(self._show_factory_choices()) + # if choice in xrange(len(self.metadata.factories)): + # self.factory = self.metadata.factories[choice] + # return False, defer.succeed(self._show_info_and_options()) + # else: + # return False, defer.succeed(self._show_factory_choices()) + #if self.got_options_response is False: + # self.got_options_response = True + # if line == 'y' or line == 'Y' and self.options_left: + # return False, defer.succeed(self._get_next_option_prompt()) + # else: + # self.options_chosen = [option.default_value for option in self.options_left] + # self.options_left = [] + # return False, defer.succeed(self.line_prompt3) + + #if line == 'y' or line == 'Y': + # d = self._start_download() + #else: + # d = defer.succeed("Download cancelled") + #return True, d def _get_choice_from_input(self, line): try: @@ -349,45 +521,64 @@ class AddStream(ControlHandler): return choice_num raise InvalidChoiceError() + def _get_factory_choice_command(self, line): + for command, printed_command, shortcut in self.factory_choice_strings: + if line == command or line == shortcut: + return command + def _load_metadata(self, sd_file): return defer.fail(NotImplementedError()) def _handle_load_canceled(self, err): err.trap(defer.CancelledError) - return defer.succeed(self.canceled_message) + self.console.sendLine(self.canceled_message) + self.finished_deferred.callback(None) def _handle_load_failed(self, err): self.loading_failed = True log.error("An exception occurred attempting to load the stream descriptor: %s", err.getTraceback()) - return defer.succeed("An unexpected error occurred attempting to load the stream's metadata.\n" - "See console.log for further details.\n\n" - "Press enter to continue") + self.console.sendLine("An unexpected error occurred attempting to load the stream's metadata.\n" + "See console.log for further details.\n\n") + self.finished_deferred.callback(None) - def _choose_factory(self, metadata): + def _handle_metadata(self, metadata): self.loading_metadata_deferred = None self.metadata = metadata - if len(self.metadata.factories) == 1: - self.factory = self.metadata.factories[0] - return self._show_info_and_options() + self.factory_choices = {} + for factory in self.metadata.factories: + self.factory_choices[factory.get_description()] = factory + self.download_options = self.metadata.options.get_downloader_options(self.metadata.validator, + self.payment_rate_manager) + self.options_chosen = [option.default_value for option in self.download_options] + self.factory_choice_strings = [] + factory_choice_names = ['cancel'] + if self.download_options: + factory_choice_names.append('options') + factory_choice_names += self.factory_choices.keys() + shortcuts, names_with_shortcuts = get_shortcuts_for_options(factory_choice_names) + self.factory_choice_strings = zip(factory_choice_names, names_with_shortcuts, shortcuts) + #if len(self.metadata.factories) == 1: + # self.factory = self.metadata.factories[0] + # return self._show_info_and_options() + self._show_info_and_options() return self._show_factory_choices() def _show_factory_choices(self): - prompt = "Choose what to do with the file:\n" - for i, factory in enumerate(self.metadata.factories): - prompt += "[" + str(i) + "] " + factory.get_description() + '\n' - return str(prompt) + prompt = "\n" + for factory_choice_string in self.factory_choice_strings: + prompt += factory_choice_string[1] + '\n' + self.console.sendLine(str(prompt)) def _show_info_and_options(self): - self.options_left = self.metadata.options.get_downloader_options(self.metadata.validator, - self.payment_rate_manager) + #self.download_options = self.metadata.options.get_downloader_options(self.metadata.validator, + # self.payment_rate_manager) prompt = "Stream info:\n" for info_line in self._get_info_to_show(): prompt += info_line[0] + ": " + info_line[1] + "\n" prompt += "\nOptions:\n" - for option in self.options_left: + for option in self.download_options: prompt += option.long_description + ": " + str(option.default_value_description) + "\n" - prompt += "\nModify options? (y/n)" - return str(prompt) + self.console.sendLine(str(prompt)) def _get_info_to_show(self): return self.metadata.validator.info_to_show() @@ -456,10 +647,10 @@ class AddStream(ControlHandler): def _handle_download_error(self, err): if err.check(InsufficientFundsError): - return "Download stopped due to insufficient funds." + self.console.sendLine("Download stopped due to insufficient funds.") else: log.error("An unexpected error has caused the download to stop: %s" % err.getTraceback()) - return "An unexpected error has caused the download to stop. See console.log for details." + self.console.sendLine("An unexpected error has caused the download to stop. See console.log for details.") def _make_downloader(self): return self.factory.make_downloader(self.metadata, self.options_chosen, @@ -467,60 +658,78 @@ class AddStream(ControlHandler): class AddStreamFromSD(AddStream): - prompt_description = "Add a stream from a stream descriptor file" - line_prompt = "Stream descriptor file name:" + #prompt_description = "Add a stream from a stream descriptor file" + #line_prompt = "Stream descriptor file name:" - def _load_metadata(self, sd_file): - return self.sd_identifier.get_metadata_for_sd_file(sd_file) + def start(self, sd_file): + self.loading_metadata_deferred = self.sd_identifier.get_metadata_for_sd_file(sd_file) + return AddStream.start(self) -class AddStreamFromSDFactory(ControlHandlerFactory): +class AddStreamFromSDFactory(CommandHandlerFactory): control_handler_class = AddStreamFromSD + command = "get-sd" + short_help = "Download a stream from a plaintext stream descriptor file" + full_help = "Download a stream from a plaintext stream descriptor file.\n" \ + "Takes one argument, the filename of the stream descriptor.\n\n" \ + "get-sd " class AddStreamFromHash(AddStream): - prompt_description = "Add a stream from a hash" - line_prompt = "Stream descriptor hash:" + #prompt_description = "Add a stream from a hash" + #line_prompt = "Stream descriptor hash:" - def __init__(self, sd_identifier, session): - AddStream.__init__(self, sd_identifier, session.base_payment_rate_manager) + def __init__(self, console, sd_identifier, session): + AddStream.__init__(self, console, sd_identifier, session.base_payment_rate_manager) self.session = session - def _load_metadata(self, sd_hash): - d = download_sd_blob(self.session, sd_hash, self.payment_rate_manager) - d.addCallback(self.sd_identifier.get_metadata_for_sd_blob) - return d + def start(self, sd_hash): + self.loading_metadata_deferred = download_sd_blob(self.session, sd_hash, + self.payment_rate_manager) + self.loading_metadata_deferred.addCallback(self.sd_identifier.get_metadata_for_sd_blob) + AddStream.start(self) def _handle_load_failed(self, err): self.loading_failed = True if err.check(InvalidBlobHashError): - return defer.succeed("The hash you entered is invalid. It must be 96 characters long and " - "contain only hex characters.\n\nPress enter to continue") + self.console.sendLine("The hash you entered is invalid. It must be 96 characters long" + " and contain only hex characters.\n\n") + self.finished_deferred.callback(None) + return if err.check(InsufficientFundsError): - return defer.succeed("Insufficient funds to download the metadata blob.\n\nPress enter to continue") + self.console.sendLine("Insufficient funds to download the metadata blob.\n\n") + self.finished_deferred.callback(None) + return return AddStream._handle_load_failed(self, err) -class AddStreamFromHashFactory(ControlHandlerFactory): +class AddStreamFromHashFactory(CommandHandlerFactory): control_handler_class = AddStreamFromHash + command = "get-hash" + short_help = "Download a stream from a hash" + full_help = "Download a stream from the hash of the stream descriptor. The stream " \ + "descriptor file will be downloaded from LBRYnet and then read.\n" \ + "Takes one argument, the sha384 hashsum of the stream descriptor.\n\n" \ + "get-hash " class AddStreamFromLBRYcrdName(AddStreamFromHash): - prompt_description = "Add a stream from a short name" - line_prompt = "Short name:" + #prompt_description = "Add a stream from a short name" + #line_prompt = "Short name:" - def __init__(self, sd_identifier, session, wallet): - AddStreamFromHash.__init__(self, sd_identifier, session) + def __init__(self, console, sd_identifier, session, wallet): + AddStreamFromHash.__init__(self, console, sd_identifier, session) self.wallet = wallet self.resolved_name = None self.description = None self.key_fee = None self.key_fee_address = None - def _load_metadata(self, name): - d = self._resolve_name(name) - d.addCallback(lambda stream_hash: AddStreamFromHash._load_metadata(self, stream_hash)) - return d + def start(self, name): + self.loading_metadata_deferred = self._resolve_name(name) + self.loading_metadata_deferred.addCallback(lambda stream_hash: download_sd_blob(self.session, stream_hash, self.payment_rate_manager)) + self.loading_metadata_deferred.addCallback(self.sd_identifier.get_metadata_for_sd_blob) + AddStream.start(self) def _resolve_name(self, name): def get_name_from_info(stream_info): @@ -542,11 +751,13 @@ class AddStreamFromLBRYcrdName(AddStreamFromHash): def _handle_load_failed(self, err): self.loading_failed = True if err.check(UnknownNameError): - return defer.succeed("The name %s could not be found.\n\n" - "Press enter to continue" % err.getErrorMessage()) + self.console.sendLine("The name %s could not be found.\n\n" % err.getErrorMessage()) + self.finished_deferred.callback(None) + return elif err.check(InvalidBlobHashError): - return defer.succeed("The metadata for this name is invalid. The stream cannot be downloaded.\n\n" + - "Press enter to continue") + self.console.sendLine("The metadata for this name is invalid. The stream cannot be downloaded.\n\n") + self.finished_deferred.callback(None) + return return AddStreamFromHash._handle_load_failed(self, err) def _start_download(self): @@ -574,13 +785,20 @@ class AddStreamFromLBRYcrdName(AddStreamFromHash): return i -class AddStreamFromLBRYcrdNameFactory(ControlHandlerFactory): +class AddStreamFromLBRYcrdNameFactory(CommandHandlerFactory): control_handler_class = AddStreamFromLBRYcrdName + command = "get" + short_help = "Download a stream from a name" + full_help = "Download a stream associated with a name on the LBRYcrd blockchain. The name will be" \ + " looked up on the blockchain, and if it is associated with a stream descriptor hash," \ + " that stream descriptor will be downloaded and read.\n" \ + "Takes one argument, the name\n\n" \ + "get " -class LBRYFileChooser(RecursiveControlHandler): +class LBRYFileChooser(RecursiveCommandHandler): - def __init__(self, lbry_file_manager, factory_class, *args, **kwargs): + def __init__(self, console, lbry_file_manager, factory_class, *args, **kwargs): """ @param lbry_file_manager: @@ -595,7 +813,7 @@ class LBRYFileChooser(RecursiveControlHandler): self.lbry_file_manager = lbry_file_manager self.factory_class = factory_class self.args = args - RecursiveControlHandler.__init__(self, **kwargs) + RecursiveCommandHandler.__init__(self, console, **kwargs) def _get_control_handler_factories(self): control_handler_factories = [] @@ -604,43 +822,61 @@ class LBRYFileChooser(RecursiveControlHandler): return control_handler_factories -class LBRYFileChooserFactory(ControlHandlerFactory): +class LBRYFileChooserFactory(CommandHandlerFactory): def get_prompt_description(self): lbry_file = self.args[0] return lbry_file.file_name class DeleteLBRYFileChooser(LBRYFileChooser): - prompt_description = "Delete LBRY File" + #prompt_description = "Delete LBRY File" - def __init__(self, stream_info_manager, blob_manager, lbry_file_manager): - LBRYFileChooser.__init__(self, lbry_file_manager, DeleteLBRYFileFactory, stream_info_manager, - blob_manager, lbry_file_manager, exit_after_one_done=True) + def __init__(self, console, stream_info_manager, blob_manager, lbry_file_manager): + LBRYFileChooser.__init__(self, console, lbry_file_manager, DeleteLBRYFileFactory, + stream_info_manager, blob_manager, lbry_file_manager, + exit_after_one_done=True) -class DeleteLBRYFileChooserFactory(ControlHandlerFactory): +class DeleteLBRYFileChooserFactory(CommandHandlerFactory): control_handler_class = DeleteLBRYFileChooser + command = "delete-lbryfile" + short_help = "Delete an LBRY file" + full_help = "Delete an LBRY file which has been downloaded or created by this application" -class DeleteLBRYFile(ControlHandler): - prompt_description = "Delete LBRY File" +class DeleteLBRYFile(CommandHandler): + #prompt_description = "Delete LBRY File" line_prompt = "Also delete data? (y/n):" - def __init__(self, lbry_file, stream_info_manager, blob_manager, lbry_file_manager): + def __init__(self, console, lbry_file, stream_info_manager, blob_manager, lbry_file_manager): + CommandHandler.__init__(self, console) self.lbry_file = lbry_file self.stream_info_manager = stream_info_manager self.blob_manager = blob_manager self.lbry_file_manager = lbry_file_manager + self.got_input = False + + def start(self): + self.console.sendLine(self.line_prompt) def handle_line(self, line): - if line is None: - return False, defer.succeed(self.line_prompt) - delete_data = False - if line == 'y' or line == 'Y': - delete_data = True - d = self._delete_lbry_file(delete_data) - d.addCallback(lambda _: "Successfully deleted " + str(self.lbry_file.stream_name)) - return True, d + #if line is None: + # return False, defer.succeed(self.line_prompt) + if self.got_input is False: + self.got_input = True + delete_data = False + if line == 'y' or line == 'Y': + delete_data = True + d = self._delete_lbry_file(delete_data) + + def show_done(): + self.console.sendLine("Successfully deleted " + str(self.lbry_file.stream_name)) + + def delete_failed(err): + self.console.sendLine("Deletion unsuccessful. Reason: %s" % err.getErrorMessage()) + + d.addCallbacks(lambda _: show_done(), delete_failed) + d.chainDeferred(self.finished_deferred) def _delete_lbry_file(self, delete_data): d = self.lbry_file_manager.delete_lbry_file(self.lbry_file.stream_hash) @@ -690,30 +926,36 @@ class DeleteLBRYFileFactory(LBRYFileChooserFactory): class ToggleLBRYFileRunningChooser(LBRYFileChooser): - prompt_description = "Toggle whether an LBRY File is running" + #prompt_description = "Toggle whether an LBRY File is running" - def __init__(self, lbry_file_manager): - LBRYFileChooser.__init__(self, lbry_file_manager, ToggleLBRYFileRunningFactory, lbry_file_manager, - exit_after_one_done=True) + def __init__(self, console, lbry_file_manager): + LBRYFileChooser.__init__(self, console, lbry_file_manager, ToggleLBRYFileRunningFactory, + lbry_file_manager, exit_after_one_done=True) -class ToggleLBRYFileRunningChooserFactory(ControlHandlerFactory): +class ToggleLBRYFileRunningChooserFactory(CommandHandlerFactory): control_handler_class = ToggleLBRYFileRunningChooser + command = "toggle-running" + short_help = "Toggle whether an LBRY file is running" + full_help = "Toggle whether an LBRY file, which is being saved by this application," \ + "is currently being downloaded." -class ToggleLBRYFileRunning(ControlHandler): - prompt_description = "Toggle whether an LBRY File is running" +class ToggleLBRYFileRunning(CommandHandler): + #prompt_description = "Toggle whether an LBRY File is running" - def __init__(self, lbry_file, lbry_file_manager): + def __init__(self, console, lbry_file, lbry_file_manager): + CommandHandler.__init__(self, console) self.lbry_file = lbry_file self.lbry_file_manager = lbry_file_manager - def handle_line(self, line): + def start(self): d = self.lbry_file_manager.toggle_lbry_file_running(self.lbry_file.stream_hash) d.addErrback(self._handle_download_error) - return True, d + self.finished_deferred.callback(None) - def _handle_download_error(self, err): + @staticmethod + def _handle_download_error(err): if err.check(InsufficientFundsError): return "Download stopped due to insufficient funds." else: @@ -725,22 +967,21 @@ class ToggleLBRYFileRunningFactory(LBRYFileChooserFactory): control_handler_class = ToggleLBRYFileRunning -class CreateLBRYFile(ControlHandler): - prompt_description = "Create an LBRY File from file" +class CreateLBRYFile(CommandHandler): + #prompt_description = "Create an LBRY File from file" line_prompt = "File name: " - def __init__(self, session, lbry_file_manager): + def __init__(self, console, session, lbry_file_manager): + CommandHandler.__init__(self, console) self.session = session self.lbry_file_manager = lbry_file_manager - def handle_line(self, line): - if line is None: - return False, defer.succeed(self.line_prompt) - else: - d = create_lbry_file(self.session, self.lbry_file_manager, line, open(line)) - d.addCallback(self.add_to_lbry_files) - d.addCallback(lambda _: "Successfully created " + str(line)) - return True, d + def start(self, file_name): + d = create_lbry_file(self.session, self.lbry_file_manager, file_name, open(file_name)) + d.addCallback(self.add_to_lbry_files) + d.addCallback(lambda _: self.console.sendLine("Successfully created " + str(file_name))) + self.console.sendLine("Creating an LBRY file from " + str(file_name) + " in the background.") + self.finished_deferred.callback(None) def add_to_lbry_files(self, stream_hash): prm = PaymentRateManager(self.session.base_payment_rate_manager) @@ -755,33 +996,43 @@ class CreateLBRYFile(ControlHandler): return d -class CreateLBRYFileFactory(ControlHandlerFactory): +class CreateLBRYFileFactory(CommandHandlerFactory): control_handler_class = CreateLBRYFile + command = "create-lbryfile" + short_help = "LBRYize a file" + full_help = "Split a file up into encrypted chunks compatible with LBRYnet" class PublishStreamDescriptorChooser(LBRYFileChooser): - prompt_description = "Publish a stream descriptor file to the DHT for an LBRY File" + #prompt_description = "Publish a stream descriptor file to the DHT for an LBRY File" - def __init__(self, stream_info_manager, blob_manager, lbry_file_manager): - LBRYFileChooser.__init__(self, lbry_file_manager, PublishStreamDescriptorFactory, stream_info_manager, - blob_manager, lbry_file_manager, exit_after_one_done=True) + def __init__(self, console, stream_info_manager, blob_manager, lbry_file_manager): + LBRYFileChooser.__init__(self, console, lbry_file_manager, PublishStreamDescriptorFactory, + stream_info_manager, blob_manager, lbry_file_manager, + exit_after_one_done=True) -class PublishStreamDescriptorChooserFactory(ControlHandlerFactory): +class PublishStreamDescriptorChooserFactory(CommandHandlerFactory): control_handler_class = PublishStreamDescriptorChooser + command = "publish-lbryfile" + short_help = "Put a stream descriptor onto LBRYnet" + full_help = "Make a stream descriptor available on LBRYnet at its sha384 hashsum" -class PublishStreamDescriptor(ControlHandler): - prompt_description = "Publish a stream descriptor file to the DHT for an LBRY File" +class PublishStreamDescriptor(CommandHandler): + #prompt_description = "Publish a stream descriptor file to the DHT for an LBRY File" - def __init__(self, lbry_file, stream_info_manager, blob_manager, lbry_file_manager): + def __init__(self, console, lbry_file, stream_info_manager, blob_manager, lbry_file_manager): + CommandHandler.__init__(self, console) self.lbry_file = lbry_file self.stream_info_manager = stream_info_manager self.blob_manager = blob_manager self.lbry_file_manager = lbry_file_manager - def handle_line(self, line): - return True, self._publish_sd_blob() + def start(self): + d = self._publish_sd_blob() + d.addCallback(lambda sd_hash: self.console.sendLine(sd_hash)) + d.chainDeferred(self.finished_deferred) def _publish_sd_blob(self): descriptor_writer = BlobStreamDescriptorWriter(self.blob_manager) @@ -803,33 +1054,38 @@ class PublishStreamDescriptorFactory(LBRYFileChooserFactory): class ShowPublishedSDHashesChooser(LBRYFileChooser): - prompt_description = "Show published stream descriptors for an LBRY File" + #prompt_description = "Show published stream descriptors for an LBRY File" - def __init__(self, stream_info_manager, lbry_file_manager): - LBRYFileChooser.__init__(self, lbry_file_manager, ShowPublishedSDHashesFactory, stream_info_manager, - lbry_file_manager) + def __init__(self, console, stream_info_manager, lbry_file_manager): + LBRYFileChooser.__init__(self, console, lbry_file_manager, ShowPublishedSDHashesFactory, + stream_info_manager, lbry_file_manager) -class ShowPublishedSDHashesChooserFactory(ControlHandlerFactory): +class ShowPublishedSDHashesChooserFactory(CommandHandlerFactory): control_handler_class = ShowPublishedSDHashesChooser + command = "show-lbryfile-sd-hashes" + short_help = "Show the published stream descriptor files associated with an LBRY file" + full_help = "Show the published stream descriptor files associated with an LBRY file" -class ShowPublishedSDHashes(ControlHandler): - prompt_description = "Show published stream descriptors for an LBRY File" +class ShowPublishedSDHashes(CommandHandler): + #prompt_description = "Show published stream descriptors for an LBRY File" - def __init__(self, lbry_file, stream_info_manager, lbry_file_manager): + def __init__(self, console, lbry_file, stream_info_manager, lbry_file_manager): + CommandHandler.__init__(self, console) self.lbry_file = lbry_file self.stream_info_manager = stream_info_manager self.lbry_file_manager = lbry_file_manager - def handle_line(self, line): - return True, self._show_sd_hashes() + def start(self): + d = self._show_sd_hashes() + d.chainDeferred(self.finished_deferred) def _show_sd_hashes(self): d = self.stream_info_manager.get_sd_blob_hashes_for_stream(self.lbry_file.stream_hash) def format_blob_hashes(sd_blob_hashes): - return "\n".join([str(b) for b in sd_blob_hashes]) + self.console.sendLine("\n".join([str(b) for b in sd_blob_hashes])) d.addCallback(format_blob_hashes) return d @@ -840,39 +1096,46 @@ class ShowPublishedSDHashesFactory(LBRYFileChooserFactory): class CreatePlainStreamDescriptorChooser(LBRYFileChooser): - prompt_description = "Create a plain stream descriptor file for an LBRY File" + #prompt_description = "Create a plain stream descriptor file for an LBRY File" - def __init__(self, lbry_file_manager): - LBRYFileChooser.__init__(self, lbry_file_manager, CreatePlainStreamDescriptorFactory, lbry_file_manager, + def __init__(self, console, lbry_file_manager): + LBRYFileChooser.__init__(self, console, lbry_file_manager, + CreatePlainStreamDescriptorFactory, lbry_file_manager, exit_after_one_done=True) -class CreatePlainStreamDescriptorChooserFactory(ControlHandlerFactory): +class CreatePlainStreamDescriptorChooserFactory(CommandHandlerFactory): control_handler_class = CreatePlainStreamDescriptorChooser + command = "create-stream-descriptor" + short_help = "Create a plaintext stream descriptor file for an LBRY file" + full_help = "Create a plaintext stream descriptor file for an LBRY file" -class CreatePlainStreamDescriptor(ControlHandler): +class CreatePlainStreamDescriptor(CommandHandler): prompt_description = "Create a plain stream descriptor file for an LBRY File" - def __init__(self, lbry_file, lbry_file_manager): + def __init__(self, console, lbry_file, lbry_file_manager): + CommandHandler.__init__(self, console) self.lbry_file = lbry_file self.lbry_file_manager = lbry_file_manager self.sd_file_name = None + def start(self): + self.console.sendLine(self._get_file_name_prompt()) + def handle_line(self, line): - if line is None: - return False, self._get_file_name_prompt() - self.sd_file_name = line - d = threads.deferToThread(self._get_file_name) - d.addCallback(self._create_sd) - return True, d + if self.sd_file_name is None: + self.sd_file_name = line + d = threads.deferToThread(self._get_file_name) + d.addCallback(self._create_sd) + d.chainDeferred(self.finished_deferred) def _get_file_name_prompt(self): file_name = self.lbry_file.file_name if not file_name: file_name = "_" file_name += ".cryptsd" - return defer.succeed("Stream Descriptor file name (blank for default, %s):" % file_name) + return "Stream Descriptor file name (blank for default, %s):" % file_name def _get_file_name(self): if self.sd_file_name: @@ -893,7 +1156,7 @@ class CreatePlainStreamDescriptor(ControlHandler): descriptor_writer = PlainStreamDescriptorWriter(file_name) d = get_sd_info(self.lbry_file_manager.stream_info_manager, self.lbry_file.stream_hash, True) d.addCallback(descriptor_writer.create_descriptor) - d.addCallback(lambda sd_file_name: "Wrote stream metadata to " + sd_file_name) + d.addCallback(lambda sd_file_name: self.console.sendLine("Wrote stream metadata to " + sd_file_name)) return d @@ -902,24 +1165,30 @@ class CreatePlainStreamDescriptorFactory(LBRYFileChooserFactory): class ShowLBRYFileStreamHashChooser(LBRYFileChooser): - prompt_description = "Show an LBRY File's stream hash (not usually what you want)" + #prompt_description = "Show an LBRY File's stream hash (not usually what you want)" - def __init__(self, lbry_file_manager): - LBRYFileChooser.__init__(self, lbry_file_manager, ShowLBRYFileStreamHashFactory) + def __init__(self, console, lbry_file_manager): + LBRYFileChooser.__init__(self, console, lbry_file_manager, ShowLBRYFileStreamHashFactory) -class ShowLBRYFileStreamHashChooserFactory(ControlHandlerFactory): +class ShowLBRYFileStreamHashChooserFactory(CommandHandlerFactory): control_handler_class = ShowLBRYFileStreamHashChooser + command = "lbryfile-streamhash" + short_help = "Show an LBRY file's stream hash" + full_help = "Show the stream hash of an LBRY file, which is how the LBRY file is referenced internally" \ + " by this application and therefore not usually what you want to see." -class ShowLBRYFileStreamHash(ControlHandler): - prompt_description = "Show an LBRY File's stream hash (not usually what you want)" +class ShowLBRYFileStreamHash(CommandHandler): + #prompt_description = "Show an LBRY File's stream hash (not usually what you want)" - def __init__(self, lbry_file): + def __init__(self, console, lbry_file): + CommandHandler.__init__(self, console) self.lbry_file = lbry_file - def handle_line(self, line): - return True, defer.succeed(str(self.lbry_file.stream_hash)) + def start(self): + self.console.sendLine(str(self.lbry_file.stream_hash)) + self.finished_deferred.callback(None) class ShowLBRYFileStreamHashFactory(LBRYFileChooserFactory): @@ -929,8 +1198,8 @@ class ShowLBRYFileStreamHashFactory(LBRYFileChooserFactory): class ModifyLBRYFileDataPaymentRate(ModifyPaymentRate): prompt_description = "Modify LBRY File data payment rate" - def __init__(self, lbry_file, lbry_file_manager): - ModifyPaymentRate.__init__(self) + def __init__(self, console, lbry_file, lbry_file_manager): + ModifyPaymentRate.__init__(self, console) self._prompt_choices['unset'] = (self._unset, "Use the default LBRY file data rate") self.lbry_file = lbry_file self.lbry_file_manager = lbry_file_manager @@ -939,7 +1208,7 @@ class ModifyLBRYFileDataPaymentRate(ModifyPaymentRate): def _unset(self): d = self._set_rate(None) d.addCallback(lambda _: "Using the default LBRY file data rate") - return True, d + return d def _set_rate(self, rate): self.payment_rate_manager.min_blob_data_payment_rate = rate @@ -954,28 +1223,31 @@ class ModifyLBRYFileDataPaymentRate(ModifyPaymentRate): return status -class ModifyLBRYFileDataPaymentRateFactory(ControlHandlerFactory): +class ModifyLBRYFileDataPaymentRateFactory(CommandHandlerFactory): control_handler_class = ModifyLBRYFileDataPaymentRate class ModifyLBRYFileOptionsChooser(LBRYFileChooser): - prompt_description = "Modify an LBRY File's options" + #prompt_description = "Modify an LBRY File's options" - def __init__(self, lbry_file_manager): - LBRYFileChooser.__init__(self, lbry_file_manager, ModifyLBRYFileOptionsFactory, lbry_file_manager) + def __init__(self, console, lbry_file_manager): + LBRYFileChooser.__init__(self, console, lbry_file_manager, ModifyLBRYFileOptionsFactory, lbry_file_manager) -class ModifyLBRYFileOptionsChooserFactory(ControlHandlerFactory): +class ModifyLBRYFileOptionsChooserFactory(CommandHandlerFactory): control_handler_class = ModifyLBRYFileOptionsChooser + command = "modify-lbryfile-options" + short_help = "Modify an LBRY file's options" + full_help = "Modify an LBRY file's options" -class ModifyLBRYFileOptions(RecursiveControlHandler): - prompt_description = "Modify an LBRY File's options" +class ModifyLBRYFileOptions(RecursiveCommandHandler): + #prompt_description = "Modify an LBRY File's options" - def __init__(self, lbry_file, lbry_file_manager): + def __init__(self, console, lbry_file, lbry_file_manager): self.lbry_file = lbry_file self.lbry_file_manager = lbry_file_manager - RecursiveControlHandler.__init__(self) + RecursiveCommandHandler.__init__(self, console) def _get_control_handler_factories(self): factories = [] @@ -987,17 +1259,18 @@ class ModifyLBRYFileOptionsFactory(LBRYFileChooserFactory): control_handler_class = ModifyLBRYFileOptions -class ClaimName(ControlHandler): - prompt_description = "Publish to an lbry:// address" +class ClaimName(CommandHandler): + #prompt_description = "Publish to an lbry:// address" other_hash_prompt = "Enter the hash you would like to publish:" short_desc_prompt = "Enter a short description:" - sd_failure_message = "Unable to find a stream descriptor for that file.\n\nPress enter to continue" + sd_failure_message = "Unable to find a stream descriptor for that file." requested_price_prompt = "Enter the fee others should pay for the decryption key for this stream. Leave blank for no fee:" lbrycrd_address_prompt = "Enter the LBRYcrd address to which the key fee should be sent. If left blank a new address will be used from the wallet:" bid_amount_prompt = "Enter the number of credits you wish to use to support your bid for the name:" choose_name_prompt = "Enter the name to which you would like to publish:" - def __init__(self, wallet, lbry_file_manager, blob_manager, sd_identifier): + def __init__(self, console, wallet, lbry_file_manager, blob_manager, sd_identifier): + CommandHandler.__init__(self, console) self.wallet = wallet self.lbry_file_manager = lbry_file_manager self.blob_manager = blob_manager @@ -1012,46 +1285,58 @@ class ClaimName(ControlHandler): self.chosen_address = None self.bid_amount = None self.chosen_name = None - self.failed = False self.short_description = None self.verified = False + def start(self): + self.console.sendLine(self._get_file_type_options()) + def handle_line(self, line): - if line is None: - return False, defer.succeed(self._get_file_type_options()) - if self.failed is True: - return True, defer.succeed(None) + #if line is None: + # return False, defer.succeed(self._get_file_type_options()) + #if self.failed is True: + # return True, defer.succeed(None) if self.file_type_chosen is None: try: choice = int(line) except ValueError: choice = -1 if choice < 0 or choice >= len(self.file_type_options): - return False, defer.succeed("You must enter a valid number.\n\n%s" % self._get_file_type_options()) + self.console.sendLine("You must enter a valid number.\n\n%s" % self._get_file_type_options()) + return if self.file_type_options[choice][0] is None: - return True, defer.succeed("Publishing canceled.") + self.console.sendLine("Publishing canceled.") + self.finished_deferred.callback(None) + return self.file_type_chosen = self.file_type_options[choice][0] if self.file_type_chosen == "hash": - return False, defer.succeed(self.other_hash_prompt) + self.console.sendLine(self.other_hash_prompt) + return else: - return False, self._set_sd_hash_and_get_desc_prompt() + self._set_sd_hash_and_get_desc_prompt() + return if self.sd_hash is None: self.sd_hash = line - return False, defer.succeed(self.short_desc_prompt) + self.console.sendLine(self.short_desc_prompt) + return if self.short_description is None: self.short_description = line - return False, defer.succeed(self.requested_price_prompt) + self.console.sendLine(self.requested_price_prompt) + return if self.key_fee_chosen is False: if line: try: self.key_fee = float(line) except ValueError: - return False, defer.succeed("Leave blank or enter a floating point number.\n\n%s" % self.requested_price_prompt) + self.console.sendLine("Leave blank or enter a floating point number.\n\n%s" % self.requested_price_prompt) + return self.key_fee_chosen = True if self.key_fee is None or self.key_fee <= 0: self.need_address = False - return False, defer.succeed(self.bid_amount_prompt) - return False, defer.succeed(self.lbrycrd_address_prompt) + self.console.sendLine(self.bid_amount_prompt) + return + self.console.sendLine(self.lbrycrd_address_prompt) + return if self.need_address is True: if line: self.chosen_address = line @@ -1059,22 +1344,26 @@ class ClaimName(ControlHandler): else: d = self._get_new_address() self.need_address = False - d.addCallback(lambda _: self.bid_amount_prompt) - return False, d + d.addCallback(lambda _: self.console.sendLine(self.bid_amount_prompt)) + return if self.bid_amount is None: try: self.bid_amount = float(line) except ValueError: - return False, defer.succeed("Must be a floating point number.\n\n%s" % self.bid_amount_prompt) - return False, defer.succeed(self.choose_name_prompt) + self.console.sendLine("Must be a floating point number.\n\n%s" % self.bid_amount_prompt) + return + self.console.sendLine(self.choose_name_prompt) + return if self.chosen_name is None: self.chosen_name = line - return False, defer.succeed(self._get_verification_prompt()) + self.console.sendLine(self._get_verification_prompt()) + return if self.verified is False: if line.lower() == "yes": - return True, self._claim_name() + d = self._claim_name() else: - return True, defer.succeed("Claim canceled") + d = defer.succeed("Claim canceled") + d.chainDeferred(self.finished_deferred) def _get_file_type_options(self): options = [] @@ -1097,7 +1386,6 @@ class ClaimName(ControlHandler): def _choose_sd(self, sd_blob_hashes): if not sd_blob_hashes: - self.failed = True return defer.succeed(False) self.sd_hash = sd_blob_hashes[0] return defer.succeed(True) @@ -1105,7 +1393,19 @@ class ClaimName(ControlHandler): def _set_sd_hash_and_get_desc_prompt(self): d = self.lbry_file_manager.stream_info_manager.get_sd_blob_hashes_for_stream(self.file_type_chosen.stream_hash) d.addCallback(self._choose_sd) - d.addCallback(lambda success: self.short_desc_prompt if success else self.sd_failure_message) + + def sd_hash_set(success): + if success: + self.console.sendLine(self.short_desc_prompt) + else: + self.console.sendLine(self.sd_failure_message) + self.finished_deferred.callback(None) + + def sd_hash_failed(err): + self.console.sendLine("An error occurred getting the stream descriptor hash: %s" % err.getErrorMessage()) + self.finished_deferred.callback(None) + + d.addCallbacks(sd_hash_set, sd_hash_failed) return d def _get_new_address(self): @@ -1135,19 +1435,22 @@ class ClaimName(ControlHandler): d = self.wallet.claim_name(self.chosen_name, self.sd_hash, float(self.bid_amount), description=self.short_description, key_fee=self.key_fee, key_fee_address=self.chosen_address) - d.addCallback(lambda response: str(response)) + d.addCallback(lambda response: self.console.sendLine(response)) return d -class ClaimNameFactory(ControlHandlerFactory): +class ClaimNameFactory(CommandHandlerFactory): control_handler_class = ClaimName + command = "claim-name" + short_help = "Associate an LBRY file with a name on LBRYnet" + full_help = "Associate an LBRY file (or any hash) with a name on LBRYnet" class ModifyDefaultDataPaymentRate(ModifyPaymentRate): prompt_description = "Modify default data payment rate" - def __init__(self, payment_rate_manager, settings): - ModifyPaymentRate.__init__(self) + def __init__(self, console, payment_rate_manager, settings): + ModifyPaymentRate.__init__(self, console) self.settings = settings self.payment_rate_manager = payment_rate_manager @@ -1161,36 +1464,38 @@ class ModifyDefaultDataPaymentRate(ModifyPaymentRate): return status -class ModifyDefaultDataPaymentRateFactory(ControlHandlerFactory): +class ModifyDefaultDataPaymentRateFactory(CommandHandlerFactory): control_handler_class = ModifyDefaultDataPaymentRate -class ForceCheckBlobFileConsistency(ControlHandler): +class ForceCheckBlobFileConsistency(CommandHandler): prompt_description = "Verify consistency of stored blobs" - def __init__(self, blob_manager): + def __init__(self, console, blob_manager): + CommandHandler.__init__(self, console) self.blob_manager = blob_manager - def handle_line(self, line): - assert line is None, "Check consistency should not be passed any arguments" - return True, self._check_consistency() + def start(self): + self._check_consistency() + self.console.sendLine("Checking consistency in the background.") + self.finished_deferred.callback(None) def _check_consistency(self): d = self.blob_manager.check_consistency() - d.addCallback(lambda _: "Finished checking stored blobs") + d.addCallback(lambda _: self.console.sendLine("Finished checking stored blobs")) return d -class ForceCheckBlobFileConsistencyFactory(ControlHandlerFactory): +class ForceCheckBlobFileConsistencyFactory(CommandHandlerFactory): control_handler_class = ForceCheckBlobFileConsistency -class ModifyApplicationDefaults(RecursiveControlHandler): - prompt_description = "Modify application settings" +class ModifyApplicationDefaults(RecursiveCommandHandler): + #prompt_description = "Modify application settings" - def __init__(self, lbry_service): + def __init__(self, console, lbry_service): self.lbry_service = lbry_service - RecursiveControlHandler.__init__(self) + RecursiveCommandHandler.__init__(self, console) def _get_control_handler_factories(self): return [ModifyDefaultDataPaymentRateFactory(self.lbry_service.session.base_payment_rate_manager, @@ -1198,19 +1503,24 @@ class ModifyApplicationDefaults(RecursiveControlHandler): ForceCheckBlobFileConsistencyFactory(self.lbry_service.session.blob_manager)] -class ModifyApplicationDefaultsFactory(ControlHandlerFactory): +class ModifyApplicationDefaultsFactory(CommandHandlerFactory): control_handler_class = ModifyApplicationDefaults + command = "modify-application-defaults" + short_help = "Modify application settings" + full_help = "Modify application settings" -class ShowServerStatus(ControlHandler): - prompt_description = "Show the status of the server" +class ShowServerStatus(CommandHandler): + #prompt_description = "Show the status of the server" - def __init__(self, lbry_service): + def __init__(self, console, lbry_service): + CommandHandler.__init__(self, console) self.lbry_service = lbry_service - def handle_line(self, line): - assert line is None, "Show server status should not be passed any arguments" - return True, self._get_status() + def start(self): + #assert line is None, "Show server status should not be passed any arguments" + d = self._get_status() + d.chainDeferred(self.finished_deferred) def _get_status(self): status_string = "Server status:\n" @@ -1227,54 +1537,63 @@ class ShowServerStatus(ControlHandler): #status_string += "Min crypt info payment rate: " #status_string += str(self.lbry_service._server_payment_rate_manager.get_min_live_blob_info_payment_rate()) #status_string += "\n" - return defer.succeed(status_string) + self.console.sendLine(status_string) + return defer.succeed(None) -class ShowServerStatusFactory(ControlHandlerFactory): +class ShowServerStatusFactory(CommandHandlerFactory): control_handler_class = ShowServerStatus + command = "server-status" + short_help = "Show the server's status" + full_help = "Show the port on which the server is running, whether the server is running, and the" \ + " payment rate which the server accepts for data uploads" -class StartServer(ControlHandler): +class StartServer(CommandHandler): prompt_description = "Start the server" - def __init__(self, lbry_service): + def __init__(self, console, lbry_service): + CommandHandler.__init__(self, console) self.lbry_service = lbry_service - def handle_line(self, line): - assert line is None, "Start server should not be passed any arguments" + def start(self): + #assert line is None, "Start server should not be passed any arguments" d = self.lbry_service.start_server() d.addCallback(lambda _: self.lbry_service.settings.save_server_running_status(running=True)) - d.addCallback(lambda _: "Successfully started the server") - return True, d + d.addCallback(lambda _: self.console.sendLine("Successfully started the server")) + d.chainDeferred(self.finished_deferred) + #return True, d -class StartServerFactory(ControlHandlerFactory): +class StartServerFactory(CommandHandlerFactory): control_handler_class = StartServer -class StopServer(ControlHandler): +class StopServer(CommandHandler): prompt_description = "Stop the server" - def __init__(self, lbry_service): + def __init__(self, console, lbry_service): + CommandHandler.__init__(self, console) self.lbry_service = lbry_service - def handle_line(self, line): - assert line is None, "Stop server should not be passed any arguments" + def start(self): + #assert line is None, "Stop server should not be passed any arguments" d = self.lbry_service.stop_server() d.addCallback(lambda _: self.lbry_service.settings.save_server_running_status(running=False)) - d.addCallback(lambda _: "Successfully stopped the server") - return True, d + d.addCallback(lambda _: self.console.sendLine("Successfully stopped the server")) + d.chainDeferred(self.finished_deferred) + #return True, d -class StopServerFactory(ControlHandlerFactory): +class StopServerFactory(CommandHandlerFactory): control_handler_class = StopServer class ModifyServerDataPaymentRate(ModifyPaymentRate): prompt_description = "Modify server data payment rate" - def __init__(self, payment_rate_manager, settings): - ModifyPaymentRate.__init__(self) + def __init__(self, console, payment_rate_manager, settings): + ModifyPaymentRate.__init__(self, console) self._prompt_choices['unset'] = (self._unset, "Use the application default data rate") self.settings = settings self.payment_rate_manager = payment_rate_manager @@ -1282,7 +1601,7 @@ class ModifyServerDataPaymentRate(ModifyPaymentRate): def _unset(self): d = self._set_rate(None) d.addCallback(lambda _: "Using the application default data rate") - return True, d + return d def _set_rate(self, rate): self.payment_rate_manager.min_blob_data_payment_rate = rate @@ -1297,7 +1616,7 @@ class ModifyServerDataPaymentRate(ModifyPaymentRate): return status -class ModifyServerDataPaymentRateFactory(ControlHandlerFactory): +class ModifyServerDataPaymentRateFactory(CommandHandlerFactory): control_handler_class = ModifyServerDataPaymentRate @@ -1335,21 +1654,22 @@ class ModifyServerDataPaymentRateFactory(ControlHandlerFactory): # control_handler_class = ModifyServerCryptInfoPaymentRate -class DisableQueryHandler(ControlHandler): - def __init__(self, query_handlers, query_handler, settings): +class DisableQueryHandler(CommandHandler): + def __init__(self, console, query_handlers, query_handler, settings): + CommandHandler.__init__(self, console) self.query_handlers = query_handlers self.query_handler = query_handler self.settings = settings - def handle_line(self, line): - assert line is None, "DisableQueryHandler should not be passed any arguments" + def start(self): + #assert line is None, "DisableQueryHandler should not be passed any arguments" self.query_handlers[self.query_handler] = False d = self.settings.disable_query_handler(self.query_handler.get_primary_query_identifier()) - d.addCallback(lambda _: "Disabled the query handler") - return True, d + d.addCallback(lambda _: self.console.sendLine("Disabled the query handler")) + d.chainDeferred(self.finished_deferred) -class DisableQueryHandlerFactory(ControlHandlerFactory): +class DisableQueryHandlerFactory(CommandHandlerFactory): control_handler_class = DisableQueryHandler def get_prompt_description(self): @@ -1357,21 +1677,22 @@ class DisableQueryHandlerFactory(ControlHandlerFactory): return "Disable " + str(query_handler.get_description()) -class EnableQueryHandler(ControlHandler): - def __init__(self, query_handlers, query_handler, settings): +class EnableQueryHandler(CommandHandler): + def __init__(self, console, query_handlers, query_handler, settings): + CommandHandler.__init__(self, console) self.query_handlers = query_handlers self.query_handler = query_handler self.settings = settings - def handle_line(self, line): - assert line is None, "EnableQueryHandler should not be passed any arguments" + def start(self): + #assert line is None, "EnableQueryHandler should not be passed any arguments" self.query_handlers[self.query_handler] = True d = self.settings.enable_query_handler(self.query_handler.get_primary_query_identifier()) - d.addCallback(lambda _: "Enabled the query handler") - return True, d + d.addCallback(lambda _: self.console.sendLine("Enabled the query handler")) + d.chainDeferred(self.finished_deferred) -class EnableQueryHandlerFactory(ControlHandlerFactory): +class EnableQueryHandlerFactory(CommandHandlerFactory): control_handler_class = EnableQueryHandler def get_prompt_description(self): @@ -1379,13 +1700,13 @@ class EnableQueryHandlerFactory(ControlHandlerFactory): return "Enable " + str(query_handler.get_description()) -class ModifyServerEnabledQueries(RecursiveControlHandler): +class ModifyServerEnabledQueries(RecursiveCommandHandler): prompt_description = "Modify which queries the server will respond to" - def __init__(self, query_handlers, settings): + def __init__(self, console, query_handlers, settings): self.query_handlers = query_handlers self.settings = settings - RecursiveControlHandler.__init__(self, reset_after_each_done=True) + RecursiveCommandHandler.__init__(self, console, reset_after_each_done=True) def _get_control_handler_factories(self): factories = [] @@ -1397,33 +1718,34 @@ class ModifyServerEnabledQueries(RecursiveControlHandler): return factories -class ModifyServerEnabledQueriesFactory(ControlHandlerFactory): +class ModifyServerEnabledQueriesFactory(CommandHandlerFactory): control_handler_class = ModifyServerEnabledQueries -class ImmediateAnnounceAllBlobs(ControlHandler): +class ImmediateAnnounceAllBlobs(CommandHandler): prompt_description = "Immediately announce all blob hashes to the DHT" - def __init__(self, blob_manager): + def __init__(self, console, blob_manager): + CommandHandler.__init__(self, console) self.blob_manager = blob_manager - def handle_line(self, line): - assert line is None, "Immediate Announce should not be passed any arguments" + def start(self): + #assert line is None, "Immediate Announce should not be passed any arguments" d = self.blob_manager.immediate_announce_all_blobs() - d.addCallback(lambda _: "Done announcing") - return True, d + d.addCallback(lambda _: self.console.sendLine("Done announcing")) + d.chainDeferred(self.finished_deferred) -class ImmediateAnnounceAllBlobsFactory(ControlHandlerFactory): +class ImmediateAnnounceAllBlobsFactory(CommandHandlerFactory): control_handler_class = ImmediateAnnounceAllBlobs -class ModifyServerSettings(RecursiveControlHandler): - prompt_description = "Modify server settings" +class ModifyServerSettings(RecursiveCommandHandler): + #prompt_description = "Modify server settings" - def __init__(self, lbry_service): + def __init__(self, console, lbry_service): self.lbry_service = lbry_service - RecursiveControlHandler.__init__(self, reset_after_each_done=True) + RecursiveCommandHandler.__init__(self, console, reset_after_each_done=True) def _get_control_handler_factories(self): factories = [] @@ -1445,13 +1767,16 @@ class ModifyServerSettings(RecursiveControlHandler): return factories -class ModifyServerSettingsFactory(ControlHandlerFactory): +class ModifyServerSettingsFactory(CommandHandlerFactory): control_handler_class = ModifyServerSettings + command = "modify-server-settings" + short_help = "Modify server settings" + full_help = "Modify server settings" -class PeerChooser(RecursiveControlHandler): +class PeerChooser(RecursiveCommandHandler): - def __init__(self, peer_manager, factory_class, *args, **kwargs): + def __init__(self, console, peer_manager, factory_class, *args, **kwargs): """ @param peer_manager: @@ -1466,7 +1791,7 @@ class PeerChooser(RecursiveControlHandler): self.peer_manager = peer_manager self.factory_class = factory_class self.args = args - RecursiveControlHandler.__init__(self, **kwargs) + RecursiveCommandHandler.__init__(self, console, **kwargs) def _get_control_handler_factories(self): control_handler_factories = [] @@ -1475,20 +1800,22 @@ class PeerChooser(RecursiveControlHandler): return control_handler_factories -class PeerChooserFactory(ControlHandlerFactory): +class PeerChooserFactory(CommandHandlerFactory): def get_prompt_description(self): peer = self.args[0] return str(peer) -class ShowPeerStats(ControlHandler): +class ShowPeerStats(CommandHandler): prompt_description = "Show the peer's stats" - def __init__(self, peer): + def __init__(self, console, peer): + CommandHandler.__init__(self, console) self.peer = peer - def handle_line(self, line): - return True, defer.succeed(self._get_peer_stats_string()) + def start(self): + self.console.sendLine(self._get_peer_stats_string()) + self.finished_deferred.callback(None) def _get_peer_stats_string(self): stats = "Statistics for " + str(self.peer) + '\n' @@ -1499,14 +1826,14 @@ class ShowPeerStats(ControlHandler): return stats -class ShowPeerStatsFactory(ControlHandlerFactory): +class ShowPeerStatsFactory(CommandHandlerFactory): control_handler_class = ShowPeerStats -class PeerStatsAndSettings(RecursiveControlHandler): - def __init__(self, peer): +class PeerStatsAndSettings(RecursiveCommandHandler): + def __init__(self, console, peer): self.peer = peer - RecursiveControlHandler.__init__(self, reset_after_each_done=True) + RecursiveCommandHandler.__init__(self, console, reset_after_each_done=True) def _get_control_handler_factories(self): factories = [] @@ -1519,11 +1846,14 @@ class PeerStatsAndSettingsFactory(PeerChooserFactory): class PeerStatsAndSettingsChooser(PeerChooser): - prompt_description = "View peer stats and modify peer settings" + #prompt_description = "View peer stats and modify peer settings" - def __init__(self, peer_manager): - PeerChooser.__init__(self, peer_manager, PeerStatsAndSettingsFactory) + def __init__(self, console, peer_manager): + PeerChooser.__init__(self, console, peer_manager, PeerStatsAndSettingsFactory) -class PeerStatsAndSettingsChooserFactory(ControlHandlerFactory): - control_handler_class = PeerStatsAndSettingsChooser \ No newline at end of file +class PeerStatsAndSettingsChooserFactory(CommandHandlerFactory): + control_handler_class = PeerStatsAndSettingsChooser + command = "peer-stats" + short_help = "Show some peer statistics" + full_help = "Show some peer statistics" \ No newline at end of file diff --git a/lbrynet/lbrynet_console/LBRYConsole.py b/lbrynet/lbrynet_console/LBRYConsole.py index b28ed89cb..475f067ab 100644 --- a/lbrynet/lbrynet_console/LBRYConsole.py +++ b/lbrynet/lbrynet_console/LBRYConsole.py @@ -4,7 +4,7 @@ import os.path import argparse from yapsy.PluginManager import PluginManager from twisted.internet import defer, threads, stdio, task -from lbrynet.lbrynet_console.ConsoleControl import ConsoleControl, ConsoleControl2 +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 @@ -79,7 +79,6 @@ class LBRYConsole(): os.path.join(self.db_dir, "plugins"), os.path.join(os.path.dirname(__file__), "plugins"), ]) - self.control_handlers = [] self.command_handlers = [] self.query_handlers = {} @@ -120,7 +119,7 @@ class LBRYConsole(): def add_control_handlers(self, control_handlers): for control_handler in control_handlers: - self.control_handlers.append(control_handler) + self.command_handlers.append(control_handler) def add_query_handlers(self, query_handlers): @@ -300,65 +299,42 @@ class LBRYConsole(): return defer.succeed(True) def _setup_control_handlers(self): - self.command_handlers = [('get', AddStreamFactory(self.sd_identifier, self.session, - self.session.wallet))] handlers = [ - ('General', - ApplicationStatusFactory(self.session.rate_limiter, self.session.dht_node)), - ('General', - GetWalletBalancesFactory(self.session.wallet)), - ('General', - ModifyApplicationDefaultsFactory(self)), - ('General', - ShutDownFactory(self)), - ('General', - PeerStatsAndSettingsChooserFactory(self.session.peer_manager)), - ('lbryfile', - LBRYFileStatusFactory(self.lbry_file_manager)), - ('Stream Downloading', - AddStreamFromSDFactory(self.sd_identifier, self.session.base_payment_rate_manager)), - ('lbryfile', - DeleteLBRYFileChooserFactory(self.lbry_file_metadata_manager, self.session.blob_manager, - self.lbry_file_manager)), - ('lbryfile', - ToggleLBRYFileRunningChooserFactory(self.lbry_file_manager)), - ('lbryfile', - CreateLBRYFileFactory(self.session, self.lbry_file_manager)), - ('lbryfile', - PublishStreamDescriptorChooserFactory(self.lbry_file_metadata_manager, - self.session.blob_manager, - self.lbry_file_manager)), - ('lbryfile', - ShowPublishedSDHashesChooserFactory(self.lbry_file_metadata_manager, - self.lbry_file_manager)), - ('lbryfile', - CreatePlainStreamDescriptorChooserFactory(self.lbry_file_manager)), - ('lbryfile', - ShowLBRYFileStreamHashChooserFactory(self.lbry_file_manager)), - ('lbryfile', - ModifyLBRYFileOptionsChooserFactory(self.lbry_file_manager)), - ('Stream Downloading', - AddStreamFromHashFactory(self.sd_identifier, self.session)) + ApplicationStatusFactory(self.session.rate_limiter, self.session.dht_node), + GetWalletBalancesFactory(self.session.wallet), + ModifyApplicationDefaultsFactory(self), + ShutDownFactory(self), + PeerStatsAndSettingsChooserFactory(self.session.peer_manager), + LBRYFileStatusFactory(self.lbry_file_manager), + AddStreamFromSDFactory(self.sd_identifier, self.session.base_payment_rate_manager), + DeleteLBRYFileChooserFactory(self.lbry_file_metadata_manager, self.session.blob_manager, + self.lbry_file_manager), + ToggleLBRYFileRunningChooserFactory(self.lbry_file_manager), + CreateLBRYFileFactory(self.session, self.lbry_file_manager), + PublishStreamDescriptorChooserFactory(self.lbry_file_metadata_manager, + self.session.blob_manager, + self.lbry_file_manager), + ShowPublishedSDHashesChooserFactory(self.lbry_file_metadata_manager, + self.lbry_file_manager), + CreatePlainStreamDescriptorChooserFactory(self.lbry_file_manager), + ShowLBRYFileStreamHashChooserFactory(self.lbry_file_manager), + ModifyLBRYFileOptionsChooserFactory(self.lbry_file_manager), + AddStreamFromHashFactory(self.sd_identifier, self.session), ] self.add_control_handlers(handlers) if self.wallet_type == 'lbrycrd': lbrycrd_handlers = [ - ('Stream Downloading', - AddStreamFromLBRYcrdNameFactory(self.sd_identifier, self.session, - self.session.wallet)), - ('General', - ClaimNameFactory(self.session. wallet, self.lbry_file_manager, - self.session.blob_manager, self.sd_identifier)), - ('General', - GetNewWalletAddressFactory(self.session.wallet)) + AddStreamFromLBRYcrdNameFactory(self.sd_identifier, self.session, + self.session.wallet), + ClaimNameFactory(self.session. wallet, self.lbry_file_manager, + self.session.blob_manager, self.sd_identifier), + GetNewWalletAddressFactory(self.session.wallet), ] self.add_control_handlers(lbrycrd_handlers) if self.peer_port is not None: server_handlers = [ - ('Server', - ShowServerStatusFactory(self)), - ('Server', - ModifyServerSettingsFactory(self)), + ShowServerStatusFactory(self), + ModifyServerSettingsFactory(self), ] self.add_control_handlers(server_handlers) @@ -435,8 +411,7 @@ class LBRYConsole(): return defer.succeed(True) def _start_controller(self): - #self.control_class(self.control_handlers) - ConsoleControl2(self.command_handlers) + self.control_class(self.command_handlers) return defer.succeed(True) def _shut_down(self): diff --git a/lbrynet/lbrynet_console/interfaces.py b/lbrynet/lbrynet_console/interfaces.py index 54bc33b64..26d55bf3e 100644 --- a/lbrynet/lbrynet_console/interfaces.py +++ b/lbrynet/lbrynet_console/interfaces.py @@ -10,5 +10,15 @@ class IControlHandlerFactory(Interface): class IControlHandler(Interface): + def handle_line(self, line): + pass + + +class ICommandHandlerFactory(Interface): + def get_handler(self): + pass + + +class ICommandHandler(Interface): def handle_line(self, line): pass \ No newline at end of file diff --git a/lbrynet/lbrynet_console/plugins/BlindRepeater/BlindRepeaterControlHandlers.py b/lbrynet/lbrynet_console/plugins/BlindRepeater/BlindRepeaterControlHandlers.py index 6ee7bd254..db88d58ae 100644 --- a/lbrynet/lbrynet_console/plugins/BlindRepeater/BlindRepeaterControlHandlers.py +++ b/lbrynet/lbrynet_console/plugins/BlindRepeater/BlindRepeaterControlHandlers.py @@ -1,111 +1,121 @@ -from lbrynet.lbrynet_console.ControlHandlers import ControlHandler, ControlHandlerFactory -from lbrynet.lbrynet_console.ControlHandlers import RecursiveControlHandler, ModifyPaymentRate +from lbrynet.lbrynet_console.ControlHandlers import CommandHandler, CommandHandlerFactory +from lbrynet.lbrynet_console.ControlHandlers import RecursiveCommandHandler, ModifyPaymentRate from twisted.internet import defer -class StartRepeater(ControlHandler): +class StartRepeater(CommandHandler): prompt_description = "Start the blind repeater" - def __init__(self, repeater, settings): + def __init__(self, console, repeater, settings): + CommandHandler.__init__(self, console) self.repeater = repeater self.settings = settings - def handle_line(self, line): - assert line is None, "Start repeater should not be passed any arguments" + def start(self): + #assert line is None, "Start repeater should not be passed any arguments" d = self.settings.save_repeater_status(running=True) d.addCallback(lambda _: self.repeater.start()) - d.addCallback(lambda _: "Started the repeater") - return True, d + d.addCallback(lambda _: self.console.sendLine("Started the repeater")) + d.chainDeferred(self.finished_deferred) -class StartRepeaterFactory(ControlHandlerFactory): +class StartRepeaterFactory(CommandHandlerFactory): control_handler_class = StartRepeater -class StopRepeater(ControlHandler): +class StopRepeater(CommandHandler): prompt_description = "Stop the blind repeater" - def __init__(self, repeater, settings): + def __init__(self, console, repeater, settings): + CommandHandler.__init__(self, console) self.repeater = repeater self.settings = settings - def handle_line(self, line): - assert line is None, "Stop repeater should not be passed any arguments" + def start(self): + #assert line is None, "Stop repeater should not be passed any arguments" d = self.settings.save_repeater_status(running=False) d.addCallback(lambda _: self.repeater.stop()) - d.addCallback(lambda _: "Stopped the repeater") - return True, d + d.addCallback(lambda _: self.console.sendLine("Stopped the repeater")) + d.chainDeferred(self.finished_deferred) -class StopRepeaterFactory(ControlHandlerFactory): +class StopRepeaterFactory(CommandHandlerFactory): control_handler_class = StopRepeater -class UpdateMaxSpace(ControlHandler): +class UpdateMaxSpace(CommandHandler): prompt_description = "Set the maximum space to be used by the blind repeater" line_prompt = "Maximum space (in bytes):" - def __init__(self, repeater, settings): + def __init__(self, console, repeater, settings): + CommandHandler.__init__(self, console) self.repeater = repeater self.settings = settings + def start(self): + self.console.sendLine(self.line_prompt) + def handle_line(self, line): - if line is None: - return False, defer.succeed(self.line_prompt) - return True, self._set_max_space(line) + d = self._set_max_space(line) + d.chainDeferred(self.finished_deferred) def _set_max_space(self, line): max_space = int(line) d = self.settings.save_max_space(max_space) d.addCallback(lambda _: self.repeater.set_max_space(max_space)) - d.addCallback(lambda _: "Set the maximum space to " + str(max_space) + " bytes") + d.addCallback(lambda _: self.console.sendLine("Set the maximum space to " + str(max_space) + " bytes")) return d -class UpdateMaxSpaceFactory(ControlHandlerFactory): +class UpdateMaxSpaceFactory(CommandHandlerFactory): control_handler_class = UpdateMaxSpace -class AddApprovedPeer(ControlHandler): +class AddApprovedPeer(CommandHandler): prompt_description = "Add a peer to the approved list of peers to check for valuable blob hashes" host_prompt = "Peer host in dotted quad (e.g. 127.0.0.1)" port_prompt = "Peer port (e.g. 4444)" - def __init__(self, repeater, peer_manager, settings): + def __init__(self, console, repeater, peer_manager, settings): + CommandHandler.__init__(self, console) self.repeater = repeater self.peer_manager = peer_manager self.settings = settings self.host_to_add = None + def start(self): + self.console.sendLine(self.host_prompt) + def handle_line(self, line): - if line is None: - return False, defer.succeed(self.host_prompt) - elif self.host_to_add is None: + #if line is None: + # return False, defer.succeed(self.host_prompt) + if self.host_to_add is None: self.host_to_add = line - return False, defer.succeed(self.port_prompt) + self.console.sendLine(self.port_prompt) else: self.host_to_add, host = None, self.host_to_add - return True, self._add_peer(host, line) + d = self._add_peer(host, line) + d.chainDeferred(self.finished_deferred) def _add_peer(self, host, port): peer = self.peer_manager.get_peer(host, int(port)) d = self.settings.save_approved_peer(host, int(port)) d.addCallback(lambda _: self.repeater.add_approved_peer(peer)) - d.addCallback(lambda _: "Successfully added peer") + d.addCallback(lambda _: self.console.sendLine("Successfully added peer")) return d -class AddApprovedPeerFactory(ControlHandlerFactory): +class AddApprovedPeerFactory(CommandHandlerFactory): control_handler_class = AddApprovedPeer -class ApprovedPeerChooser(RecursiveControlHandler): +class ApprovedPeerChooser(RecursiveCommandHandler): - def __init__(self, repeater, factory_class, *args, **kwargs): + def __init__(self, console, repeater, factory_class, *args, **kwargs): self.repeater = repeater self.factory_class = factory_class self.args = args - RecursiveControlHandler.__init__(self, **kwargs) + RecursiveCommandHandler.__init__(self, console, **kwargs) def _get_control_handler_factories(self): control_handler_factories = [] @@ -114,7 +124,7 @@ class ApprovedPeerChooser(RecursiveControlHandler): return control_handler_factories -class ApprovedPeerChooserFactory(ControlHandlerFactory): +class ApprovedPeerChooserFactory(CommandHandlerFactory): def get_prompt_description(self): peer = self.args[0] return str(peer) @@ -123,30 +133,32 @@ class ApprovedPeerChooserFactory(ControlHandlerFactory): class DeleteApprovedPeerChooser(ApprovedPeerChooser): prompt_description = "Remove a peer from the approved list of peers to check for valuable blob hashes" - def __init__(self, repeater, settings): - ApprovedPeerChooser.__init__(self, repeater, DeleteApprovedPeerFactory, repeater, settings, - exit_after_one_done=True) + def __init__(self, console, repeater, settings): + ApprovedPeerChooser.__init__(self, console, repeater, DeleteApprovedPeerFactory, repeater, + settings, exit_after_one_done=True) -class DeleteApprovedPeerChooserFactory(ControlHandlerFactory): +class DeleteApprovedPeerChooserFactory(CommandHandlerFactory): control_handler_class = DeleteApprovedPeerChooser -class DeleteApprovedPeer(ControlHandler): +class DeleteApprovedPeer(CommandHandler): prompt_description = "Remove a peer from the approved list of peers to check for valuable blob hashes" - def __init__(self, peer, repeater, settings): + def __init__(self, console, peer, repeater, settings): + CommandHandler.__init__(self, console) self.repeater = repeater self.settings = settings self.peer_to_remove = peer - def handle_line(self, line): - return True, self._remove_peer() + def start(self): + d = self._remove_peer() + d.chainDeferred(self.finished_deferred) def _remove_peer(self): d = self.settings.remove_approved_peer(self.peer_to_remove.host, int(self.peer_to_remove.port)) d.addCallback(lambda _: self.repeater.remove_approved_peer(self.peer_to_remove)) - d.addCallback(lambda _: "Successfully removed peer") + d.addCallback(lambda _: self.console.sendLine("Successfully removed peer")) return d @@ -154,38 +166,43 @@ class DeleteApprovedPeerFactory(ApprovedPeerChooserFactory): control_handler_class = DeleteApprovedPeer -class ShowApprovedPeers(ControlHandler): +class ShowApprovedPeers(CommandHandler): prompt_description = "Show the list of peers approved to be checked for valuable blob hashes" - def __init__(self, repeater): + def __init__(self, console, repeater): + CommandHandler.__init__(self, console) self.repeater = repeater - def handle_line(self, line): - assert line is None, "Show approved peers should not be passed any arguments" - return True, self._show_peers() + def start(self): + #assert line is None, "Show approved peers should not be passed any arguments" + d = self._show_peers() + d.chainDeferred(self.finished_deferred) def _show_peers(self): peer_string = "Approved peers:\n" for peer in self.repeater.approved_peers: peer_string += str(peer) + "\n" - return defer.succeed(peer_string) + self.console.sendLine(peer_string) + return defer.succeed(None) -class ShowApprovedPeersFactory(ControlHandlerFactory): +class ShowApprovedPeersFactory(CommandHandlerFactory): control_handler_class = ShowApprovedPeers -class RepeaterStatus(ControlHandler): +class RepeaterStatus(CommandHandler): prompt_description = "Show the repeater's status" - def __init__(self, repeater): + def __init__(self, console, repeater): + CommandHandler.__init__(self, console) self.repeater = repeater - def handle_line(self, line): - assert line is None, "Show repeater status should not be passed any arguments" - return True, defer.maybeDeferred(self._get_status) + def start(self): + #assert line is None, "Show repeater status should not be passed any arguments" + self._show_status() + self.finished_deferred.callback(None) - def _get_status(self): + def _show_status(self): status_string = "Repeater status: " + self.repeater.status() + "\n" if self.repeater.stopped is False: @@ -197,25 +214,25 @@ class RepeaterStatus(ControlHandler): status_string += "Maximum space: " + str(max_space) + " bytes\n" status_string += "Space used: " + str(space_used) + " bytes\n" - return defer.succeed(status_string) + self.console.sendLine(status_string) -class RepeaterStatusFactory(ControlHandlerFactory): +class RepeaterStatusFactory(CommandHandlerFactory): control_handler_class = RepeaterStatus class ModifyDataPaymentRate(ModifyPaymentRate): prompt_description = "Modify Blind Repeater data payment rate" - def __init__(self, repeater, settings): - ModifyPaymentRate.__init__(self) + def __init__(self, console, repeater, settings): + ModifyPaymentRate.__init__(self, console) self._prompt_choices['unset'] = (self._unset, "Use the application default data rate") self.payment_rate_manager = repeater.payment_rate_manager self.settings = settings def _unset(self): self._set_rate(None) - return True, defer.succeed("Using the application default data rate") + return defer.succeed("Using the application default data rate") def _set_rate(self, rate): @@ -237,15 +254,15 @@ class ModifyDataPaymentRate(ModifyPaymentRate): return status -class ModifyDataPaymentRateFactory(ControlHandlerFactory): +class ModifyDataPaymentRateFactory(CommandHandlerFactory): control_handler_class = ModifyDataPaymentRate class ModifyInfoPaymentRate(ModifyPaymentRate): prompt_description = "Modify Blind Repeater valuable info payment rate" - def __init__(self, repeater, settings): - ModifyPaymentRate.__init__(self) + def __init__(self, console, repeater, settings): + ModifyPaymentRate.__init__(self, console) self.payment_rate_manager = repeater.payment_rate_manager self.settings = settings @@ -264,15 +281,15 @@ class ModifyInfoPaymentRate(ModifyPaymentRate): return status -class ModifyInfoPaymentRateFactory(ControlHandlerFactory): +class ModifyInfoPaymentRateFactory(CommandHandlerFactory): control_handler_class = ModifyInfoPaymentRate class ModifyHashPaymentRate(ModifyPaymentRate): prompt_description = "Modify Blind Repeater valuable hash payment rate" - def __init__(self, repeater, settings): - ModifyPaymentRate.__init__(self) + def __init__(self, console, repeater, settings): + ModifyPaymentRate.__init__(self, console) self.payment_rate_manager = repeater.payment_rate_manager self.settings = settings @@ -291,18 +308,18 @@ class ModifyHashPaymentRate(ModifyPaymentRate): return status -class ModifyHashPaymentRateFactory(ControlHandlerFactory): +class ModifyHashPaymentRateFactory(CommandHandlerFactory): control_handler_class = ModifyHashPaymentRate -class ModifyRepeaterOptions(RecursiveControlHandler): +class ModifyRepeaterOptions(RecursiveCommandHandler): prompt_description = "Modify Blind Repeater options" - def __init__(self, repeater, lbry_session, settings): + def __init__(self, console, repeater, lbry_session, settings): self.repeater = repeater self.lbry_session = lbry_session self.settings = settings - RecursiveControlHandler.__init__(self) + RecursiveCommandHandler.__init__(self, console) def _get_control_handler_factories(self): return [ModifyDataPaymentRateFactory(self.repeater, self.settings), @@ -314,5 +331,5 @@ class ModifyRepeaterOptions(RecursiveControlHandler): ] -class ModifyRepeaterOptionsFactory(ControlHandlerFactory): +class ModifyRepeaterOptionsFactory(CommandHandlerFactory): control_handler_class = ModifyRepeaterOptions \ No newline at end of file