lbry-sdk/lbrynet/lbrynet_console/ControlHandlers.py

1281 lines
47 KiB
Python
Raw Normal View History

2015-08-20 17:27:15 +02:00
import logging
from zope.interface import implements
from lbrynet.core.StreamDescriptor import PlainStreamDescriptorWriter, BlobStreamDescriptorWriter
from lbrynet.core.PaymentRateManager import PaymentRateManager
from lbrynet.lbryfilemanager.LBRYFileCreator import create_lbry_file
from lbrynet.lbryfile.StreamDescriptor import get_sd_info
from lbrynet.lbrynet_console.interfaces import IControlHandler, IControlHandlerFactory
from lbrynet.core.StreamDescriptor import download_sd_blob
from twisted.internet import defer
log = logging.getLogger(__name__)
2015-08-20 17:27:15 +02:00
class InvalidChoiceError(Exception):
pass
class InvalidValueError(Exception):
pass
2015-08-20 17:27:15 +02:00
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 RecursiveControlHandler(ControlHandler):
def __init__(self, exit_after_one_done=False, reset_after_each_done=False):
self.current_handler = None
self.exit_after_one_done = exit_after_one_done
self.reset_after_each_done = reset_after_each_done
self._set_control_handlers()
def _get_control_handler_factories(self):
pass
def _set_control_handlers(self):
self.control_handlers = {i + 1: handler for i, handler in enumerate(self._get_control_handler_factories())}
def handle_line(self, line):
if self.current_handler is None:
if line is None:
num = None
else:
try:
num = int(line)
except ValueError:
num = None
if num == 0:
return True, None
if num in self.control_handlers:
self.current_handler = self.control_handlers[num].get_handler()
line = None
ds = []
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()
if self.current_handler is None:
ds += [self.get_prompt()]
return (False,) + tuple(ds)
def get_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)
class ModifyPaymentRate(ControlHandler):
def __init__(self):
self._prompt_choices = {'cancel': (self._cancel, "Don't change anything")}
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
def _cancel(self):
return True, defer.succeed("No change was made")
def _set_rate(self, rate):
pass
def _get_current_status(self):
pass
def _get_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
class ApplicationStatus(ControlHandler):
prompt_description = "Application Status"
def __init__(self, rate_limiter, dht_node):
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"
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)
class ApplicationStatusFactory(ControlHandlerFactory):
control_handler_class = ApplicationStatus
class GetWalletBalances(ControlHandler):
prompt_description = "Show wallet point balances"
def __init__(self, wallet):
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 _get_wallet_balances(self):
d = self.wallet.get_balance()
def format_balance(balance):
balance_string = "id: 1\n"
balance_string += "balance: " + str(balance) + "\n"
return balance_string
d.addCallback(format_balance)
return d
class GetWalletBalancesFactory(ControlHandlerFactory):
control_handler_class = GetWalletBalances
class ShutDown(ControlHandler):
prompt_description = "Shut down"
def __init__(self, lbry_service):
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 _shut_down(self):
d = self.lbry_service.shut_down()
def stop_reactor():
from twisted.internet import reactor
reactor.stop()
d.addBoth(lambda _: stop_reactor())
d.addCallback(lambda _: "Shut down successfully")
return d
class ShutDownFactory(ControlHandlerFactory):
control_handler_class = ShutDown
class LBRYFileStatus(ControlHandler):
prompt_description = "Print status information for all LBRY Files"
def __init__(self, lbry_file_manager):
self.lbry_file_manager = lbry_file_manager
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 format_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)
class LBRYFileStatusFactory(ControlHandlerFactory):
control_handler_class = LBRYFileStatus
class AddStream(ControlHandler):
prompt_description = None
line_prompt = None
cancel_prompt = "Trying to locate the stream descriptor. Type \"cancel\" to cancel."
canceled_message = "Canceled locating the stream descriptor"
line_prompt2 = "Modify options? (y/n)"
line_prompt3 = "Start download? (y/n)"
def __init__(self, sd_identifier, base_payment_rate_manager):
self.sd_identifier = sd_identifier
self.loading_info_and_factories_deferred = None
self.factories = None
self.factory = None
self.info_validator = None
self.options = None
2015-08-20 17:27:15 +02:00
self.options_left = []
self.options_chosen = []
self.current_option = None
self.current_choice = None
2015-08-20 17:27:15 +02:00
self.downloader = None
self.got_options_response = False
self.loading_failed = False
self.payment_rate_manager = PaymentRateManager(base_payment_rate_manager)
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
if self.loading_info_and_factories_deferred is not None:
if line.lower() == "cancel":
self.loading_info_and_factories_deferred.cancel()
self.loading_info_and_factories_deferred = None
return True, None
else:
return False, defer.succeed(self.cancel_prompt)
if self.factories is None:
self.loading_info_and_factories_deferred = self._load_info_and_factories(line)
cancel_prompt_d = defer.succeed(self.cancel_prompt)
self.loading_info_and_factories_deferred.addCallback(self._choose_factory)
self.loading_info_and_factories_deferred.addErrback(self._handle_load_canceled)
self.loading_info_and_factories_deferred.addErrback(self._handle_load_failed)
return False, cancel_prompt_d, self.loading_info_and_factories_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.factories)):
self.factory = self.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)
2015-08-20 17:27:15 +02:00
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))
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())
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.options_chosen.append(value)
self.current_choice = None
self.current_option = None
2015-08-20 17:27:15 +02:00
self.options_left = self.options_left[1:]
if self.options_left:
return False, defer.succeed(self._get_next_option_prompt())
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
def _get_choice_from_input(self, line):
try:
choice_num = int(line)
except ValueError:
raise InvalidChoiceError()
if 0 <= choice_num < len(self.current_option.option_types):
return choice_num
raise InvalidChoiceError()
2015-08-20 17:27:15 +02:00
def _load_info_and_factories(self, sd_file):
return defer.fail(NotImplementedError())
def _handle_load_canceled(self, err):
err.trap(defer.CancelledError)
return defer.succeed(self.canceled_message)
def _handle_load_failed(self, err):
self.loading_failed = True
log.error("An exception occurred attempting to load the stream descriptor: %s", err.getTraceback())
2015-08-20 17:27:15 +02:00
return defer.succeed("Encountered a problem while loading the stream descriptor: %s\n"
"See console.log for further details.\n"
"Press enter to continue" % err.getErrorMessage())
def _choose_factory(self, info_and_factories):
self.loading_info_and_factories_deferred = None
self.info_validator, self.options, self.factories = info_and_factories
2015-08-20 17:27:15 +02:00
if len(self.factories) == 1:
self.factory = self.factories[0]
return 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.factories):
prompt += "[" + str(i) + "] " + factory.get_description() + '\n'
return str(prompt)
def _show_info_and_options(self):
self.options_left = self.options.get_downloader_options(self.info_validator,
2015-08-20 17:27:15 +02:00
self.payment_rate_manager)
prompt = "Stream info:\n"
for info_line in self.info_validator.info_to_show():
prompt += info_line[0] + ": " + info_line[1] + "\n"
prompt += "\nOptions:\n"
for option in self.options_left:
prompt += option.long_description + ": " + str(option.default_value_description) + "\n"
2015-08-20 17:27:15 +02:00
prompt += "\nModify options? (y/n)"
return str(prompt)
def _get_list_of_option_types(self):
options_string = ""
for i, option_type in enumerate(self.current_option.option_types):
options_string += "[%s] %s\n" % (str(i), option_type.long_description)
options_string += "Enter choice:"
return options_string
2015-08-20 17:27:15 +02:00
def _get_choice_value_prompt(self, invalid_value=False):
choice = self.current_option.option_types[self.current_choice]
choice_string = ""
if invalid_value is True:
"Invalid value entered. Try again.\n"
if choice.short_description is not None:
choice_string += choice.short_description + "\n"
if choice.value == float:
choice_string += "Enter floating point number (e.g. 1.0):"
elif choice.value == bool:
true_string = "Yes"
false_string = "No"
if choice.bool_options_description is not None:
true_string, false_string = choice.bool_options_description
choice_string += "[0] %s\n[1] %s\nEnter choice:" % (true_string, false_string)
else:
NotImplementedError()
return choice_string
def _get_value_for_choice(self, input):
choice = self.current_option.option_types[self.current_choice]
if choice.value == float:
try:
return float(input)
except ValueError:
raise InvalidValueError()
elif choice.value == bool:
if input == "0":
return True
elif input == "1":
return False
raise InvalidValueError()
raise NotImplementedError()
def _get_next_option_prompt(self, invalid_choice=False):
2015-08-20 17:27:15 +02:00
assert len(self.options_left), "Something went wrong. There were no options left"
self.current_option = self.options_left[0]
2015-08-20 17:27:15 +02:00
choice_string = ""
if invalid_choice is True:
2015-08-20 17:27:15 +02:00
choice_string += "Invalid response entered. Try again.\n"
choice_string += self.current_option.long_description + "\n"
if len(self.current_option.option_types) > 1:
choice_string += self._get_list_of_option_types()
elif len(self.current_option.option_types) == 1:
self.current_choice = 0
choice_string += self._get_choice_value_prompt()
2015-08-20 17:27:15 +02:00
return choice_string
def _start_download(self):
d = self._make_downloader()
d.addCallback(lambda stream_downloader: stream_downloader.start())
return d
def _make_downloader(self):
return self.factory.make_downloader(self.info_validator, self.options_chosen,
self.payment_rate_manager)
class AddStreamFromSD(AddStream):
prompt_description = "Add a stream from a stream descriptor file"
line_prompt = "Stream descriptor file name:"
def _load_info_and_factories(self, sd_file):
return self.sd_identifier.get_info_and_factories_for_sd_file(sd_file)
class AddStreamFromSDFactory(ControlHandlerFactory):
control_handler_class = AddStreamFromSD
class AddStreamFromHash(AddStream):
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)
self.session = session
def _load_info_and_factories(self, sd_hash):
d = download_sd_blob(self.session, sd_hash, self.payment_rate_manager)
d.addCallback(self.sd_identifier.get_info_and_factories_for_sd_blob)
return d
class AddStreamFromHashFactory(ControlHandlerFactory):
control_handler_class = AddStreamFromHash
class AddStreamFromLBRYcrdName(AddStreamFromHash):
prompt_description = "Add a stream from a short name"
line_prompt = "Short name:"
def __init__(self, sd_identifier, session, name_resolver):
AddStreamFromHash.__init__(self, sd_identifier, session)
self.name_resolver = name_resolver
def _load_info_and_factories(self, name):
d = self._resolve_name(name)
d.addCallback(lambda stream_hash: AddStreamFromHash._load_info_and_factories(self, stream_hash))
return d
def _resolve_name(self, name):
def get_name_from_info(stream_info):
return stream_info['stream_hash']
d = self.name_resolver.get_stream_info_for_name(name)
d.addCallback(get_name_from_info)
return d
class AddStreamFromLBRYcrdNameFactory(ControlHandlerFactory):
control_handler_class = AddStreamFromLBRYcrdName
class LBRYFileChooser(RecursiveControlHandler):
def __init__(self, lbry_file_manager, factory_class, *args, **kwargs):
"""
@param lbry_file_manager:
@param factory_class:
@param args: all arguments that will be passed to the factory
@param kwargs: all arguments that will be passed to the superclass' __init__
@return:
"""
self.lbry_file_manager = lbry_file_manager
self.factory_class = factory_class
self.args = args
RecursiveControlHandler.__init__(self, **kwargs)
def _get_control_handler_factories(self):
control_handler_factories = []
for lbry_file in self.lbry_file_manager.lbry_files:
control_handler_factories.append(self.factory_class(lbry_file, *self.args))
return control_handler_factories
class LBRYFileChooserFactory(ControlHandlerFactory):
def get_prompt_description(self):
lbry_file = self.args[0]
return lbry_file.file_name
class DeleteLBRYFileChooser(LBRYFileChooser):
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)
class DeleteLBRYFileChooserFactory(ControlHandlerFactory):
control_handler_class = DeleteLBRYFileChooser
class DeleteLBRYFile(ControlHandler):
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):
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):
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
def _delete_lbry_file(self, delete_data):
d = self.lbry_file_manager.delete_lbry_file(self.lbry_file.stream_hash)
def finish_deletion():
if delete_data is True:
d = self._delete_data()
else:
d = defer.succeed(True)
d.addCallback(lambda _: self._delete_stream_data())
return d
d.addCallback(lambda _: finish_deletion())
return d
def _delete_data(self):
d1 = self.stream_info_manager.get_blobs_for_stream(self.lbry_file.stream_hash)
def get_blob_hashes(blob_infos):
return [b[0] for b in blob_infos if b[0] is not None]
d1.addCallback(get_blob_hashes)
d2 = self.stream_info_manager.get_sd_blob_hashes_for_stream(self.lbry_file.stream_hash)
def combine_blob_hashes(results):
blob_hashes = []
for success, result in results:
if success is True:
blob_hashes.extend(result)
return blob_hashes
def delete_blobs(blob_hashes):
self.blob_manager.delete_blobs(blob_hashes)
return True
dl = defer.DeferredList([d1, d2], fireOnOneErrback=True)
dl.addCallback(combine_blob_hashes)
dl.addCallback(delete_blobs)
return dl
def _delete_stream_data(self):
return self.stream_info_manager.delete_stream(self.lbry_file.stream_hash)
class DeleteLBRYFileFactory(LBRYFileChooserFactory):
control_handler_class = DeleteLBRYFile
class ToggleLBRYFileRunningChooser(LBRYFileChooser):
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)
class ToggleLBRYFileRunningChooserFactory(ControlHandlerFactory):
control_handler_class = ToggleLBRYFileRunningChooser
class ToggleLBRYFileRunning(ControlHandler):
prompt_description = "Toggle whether an LBRY File is running"
def __init__(self, lbry_file, lbry_file_manager):
self.lbry_file = lbry_file
self.lbry_file_manager = lbry_file_manager
def handle_line(self, line):
d = self.lbry_file_manager.toggle_lbry_file_running(self.lbry_file.stream_hash)
return True, d
class ToggleLBRYFileRunningFactory(LBRYFileChooserFactory):
control_handler_class = ToggleLBRYFileRunning
class CreateLBRYFile(ControlHandler):
prompt_description = "Create an LBRY File from file"
line_prompt = "File name: "
def __init__(self, session, lbry_file_manager):
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 add_to_lbry_files(self, stream_hash):
prm = PaymentRateManager(self.session.base_payment_rate_manager)
d = self.lbry_file_manager.add_lbry_file(stream_hash, prm)
d.addCallback(lambda lbry_file_downloader: lbry_file_downloader.restore())
return d
class CreateLBRYFileFactory(ControlHandlerFactory):
control_handler_class = CreateLBRYFile
class PublishStreamDescriptorChooser(LBRYFileChooser):
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)
class PublishStreamDescriptorChooserFactory(ControlHandlerFactory):
control_handler_class = PublishStreamDescriptorChooser
class PublishStreamDescriptor(ControlHandler):
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):
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 _publish_sd_blob(self):
descriptor_writer = BlobStreamDescriptorWriter(self.blob_manager)
d = get_sd_info(self.lbry_file_manager.stream_info_manager, self.lbry_file.stream_hash, True)
d.addCallback(descriptor_writer.create_descriptor)
def add_sd_blob_to_stream(sd_blob_hash):
d = self.stream_info_manager.save_sd_blob_hash_to_stream(self.lbry_file.stream_hash, sd_blob_hash)
d.addCallback(lambda _: sd_blob_hash)
return d
d.addCallback(add_sd_blob_to_stream)
return d
class PublishStreamDescriptorFactory(LBRYFileChooserFactory):
control_handler_class = PublishStreamDescriptor
class ShowPublishedSDHashesChooser(LBRYFileChooser):
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)
class ShowPublishedSDHashesChooserFactory(ControlHandlerFactory):
control_handler_class = ShowPublishedSDHashesChooser
class ShowPublishedSDHashes(ControlHandler):
prompt_description = "Show published stream descriptors for an LBRY File"
def __init__(self, lbry_file, stream_info_manager, lbry_file_manager):
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 _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])
d.addCallback(format_blob_hashes)
return d
class ShowPublishedSDHashesFactory(LBRYFileChooserFactory):
control_handler_class = ShowPublishedSDHashes
class CreatePlainStreamDescriptorChooser(LBRYFileChooser):
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,
exit_after_one_done=True)
class CreatePlainStreamDescriptorChooserFactory(ControlHandlerFactory):
control_handler_class = CreatePlainStreamDescriptorChooser
class CreatePlainStreamDescriptor(ControlHandler):
prompt_description = "Create a plain stream descriptor file for an LBRY File"
line_prompt = "Stream Descriptor file name (blank for default):"
def __init__(self, lbry_file, lbry_file_manager):
self.lbry_file = lbry_file
self.lbry_file_manager = lbry_file_manager
self.sd_file_name = None
def handle_line(self, line):
if line is None:
return False, defer.succeed(self.line_prompt)
self.sd_file_name = line
return True, self._create_sd()
def _create_sd(self):
if not self.sd_file_name:
self.sd_file_name = None
descriptor_writer = PlainStreamDescriptorWriter(self.sd_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)
return d
class CreatePlainStreamDescriptorFactory(LBRYFileChooserFactory):
control_handler_class = CreatePlainStreamDescriptor
class ShowLBRYFileStreamHashChooser(LBRYFileChooser):
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)
class ShowLBRYFileStreamHashChooserFactory(ControlHandlerFactory):
control_handler_class = ShowLBRYFileStreamHashChooser
class ShowLBRYFileStreamHash(ControlHandler):
prompt_description = "Show an LBRY File's stream hash (not usually what you want)"
def __init__(self, lbry_file):
self.lbry_file = lbry_file
def handle_line(self, line):
return True, defer.succeed(str(self.lbry_file.stream_hash))
class ShowLBRYFileStreamHashFactory(LBRYFileChooserFactory):
control_handler_class = ShowLBRYFileStreamHash
class ModifyLBRYFileDataPaymentRate(ModifyPaymentRate):
prompt_description = "Modify LBRY File data payment rate"
def __init__(self, lbry_file, lbry_file_manager):
ModifyPaymentRate.__init__(self)
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
self.payment_rate_manager = lbry_file.payment_rate_manager
def _unset(self):
d = self._set_rate(None)
d.addCallback(lambda _: "Using the default LBRY file data rate")
return True, d
def _set_rate(self, rate):
self.payment_rate_manager.min_blob_data_payment_rate = rate
return self.lbry_file_manager.set_lbry_file_data_payment_rate(self.lbry_file.stream_hash, rate)
def _get_current_status(self):
status = "The LBRY file's current data payment rate is "
effective_rate = self.payment_rate_manager.get_effective_min_blob_data_payment_rate()
if self.payment_rate_manager.min_blob_data_payment_rate is None:
status += "set to use the default LBRY file data payment rate, "
status += str(effective_rate)
return status
class ModifyLBRYFileDataPaymentRateFactory(ControlHandlerFactory):
control_handler_class = ModifyLBRYFileDataPaymentRate
class ModifyLBRYFileOptionsChooser(LBRYFileChooser):
prompt_description = "Modify an LBRY File's options"
def __init__(self, lbry_file_manager):
LBRYFileChooser.__init__(self, lbry_file_manager, ModifyLBRYFileOptionsFactory, lbry_file_manager)
class ModifyLBRYFileOptionsChooserFactory(ControlHandlerFactory):
control_handler_class = ModifyLBRYFileOptionsChooser
class ModifyLBRYFileOptions(RecursiveControlHandler):
prompt_description = "Modify an LBRY File's options"
def __init__(self, lbry_file, lbry_file_manager):
self.lbry_file = lbry_file
self.lbry_file_manager = lbry_file_manager
RecursiveControlHandler.__init__(self)
def _get_control_handler_factories(self):
factories = []
factories.append(ModifyLBRYFileDataPaymentRateFactory(self.lbry_file, self.lbry_file_manager))
return factories
class ModifyLBRYFileOptionsFactory(LBRYFileChooserFactory):
control_handler_class = ModifyLBRYFileOptions
class ClaimName(ControlHandler):
prompt_description = "Associate a short name with a stream descriptor hash"
line_prompt = "Stream descriptor hash:"
line_prompt_2 = "Short name:"
line_prompt_3 = "Amount:"
def __init__(self, name_resolver):
self.name_resolver = name_resolver
self.sd_hash = None
self.short_name = None
self.amount = None
def handle_line(self, line):
if line is None:
return False, defer.succeed(self.line_prompt)
if self.sd_hash is None:
self.sd_hash = line
return False, defer.succeed(self.line_prompt_2)
if self.short_name is None:
self.short_name = line
return False, defer.succeed(self.line_prompt_3)
self.amount = line
return True, self._claim_name()
def _claim_name(self):
return self.name_resolver.claim_name(self.sd_hash, self.short_name, float(self.amount))
class ClaimNameFactory(ControlHandlerFactory):
control_handler_class = ClaimName
class ModifyDefaultDataPaymentRate(ModifyPaymentRate):
prompt_description = "Modify default data payment rate"
def __init__(self, payment_rate_manager, settings):
ModifyPaymentRate.__init__(self)
self.settings = settings
self.payment_rate_manager = payment_rate_manager
def _set_rate(self, rate):
self.payment_rate_manager.min_blob_data_payment_rate = rate
return self.settings.save_default_data_payment_rate(rate)
def _get_current_status(self):
status = "The current default data payment rate is "
status += str(self.payment_rate_manager.min_blob_data_payment_rate)
return status
class ModifyDefaultDataPaymentRateFactory(ControlHandlerFactory):
control_handler_class = ModifyDefaultDataPaymentRate
class ForceCheckBlobFileConsistency(ControlHandler):
prompt_description = "Verify consistency of stored blobs"
def __init__(self, blob_manager):
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 _check_consistency(self):
d = self.blob_manager.check_consistency()
d.addCallback(lambda _: "Finished checking stored blobs")
return d
class ForceCheckBlobFileConsistencyFactory(ControlHandlerFactory):
control_handler_class = ForceCheckBlobFileConsistency
class ModifyApplicationDefaults(RecursiveControlHandler):
prompt_description = "Modify application settings"
def __init__(self, lbry_service):
self.lbry_service = lbry_service
RecursiveControlHandler.__init__(self)
def _get_control_handler_factories(self):
return [ModifyDefaultDataPaymentRateFactory(self.lbry_service.session.base_payment_rate_manager,
self.lbry_service.settings),
ForceCheckBlobFileConsistencyFactory(self.lbry_service.session.blob_manager)]
class ModifyApplicationDefaultsFactory(ControlHandlerFactory):
control_handler_class = ModifyApplicationDefaults
class ShowServerStatus(ControlHandler):
prompt_description = "Show the status of the server"
def __init__(self, lbry_service):
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 _get_status(self):
status_string = "Server status:\n"
status_string += "Port: " + str(self.lbry_service.peer_port) + "\n"
status_string += "Running: " + str(self.lbry_service.lbry_server_port is not None) + "\n"
if self.lbry_service.blob_request_payment_rate_manager is not None:
rate = self.lbry_service.blob_request_payment_rate_manager.get_effective_min_blob_data_payment_rate()
status_string += "Min blob data payment rate: "
if self.lbry_service.blob_request_payment_rate_manager.min_blob_data_payment_rate is None:
status_string += "Using application default (" + str(rate) + ")\n"
else:
status_string += str(rate)
status_string += "\n"
#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)
class ShowServerStatusFactory(ControlHandlerFactory):
control_handler_class = ShowServerStatus
class StartServer(ControlHandler):
prompt_description = "Start the server"
def __init__(self, lbry_service):
self.lbry_service = lbry_service
def handle_line(self, line):
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
class StartServerFactory(ControlHandlerFactory):
control_handler_class = StartServer
class StopServer(ControlHandler):
prompt_description = "Stop the server"
def __init__(self, lbry_service):
self.lbry_service = lbry_service
def handle_line(self, line):
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
class StopServerFactory(ControlHandlerFactory):
control_handler_class = StopServer
class ModifyServerDataPaymentRate(ModifyPaymentRate):
prompt_description = "Modify server data payment rate"
def __init__(self, payment_rate_manager, settings):
ModifyPaymentRate.__init__(self)
self._prompt_choices['unset'] = (self._unset, "Use the application default data rate")
self.settings = settings
self.payment_rate_manager = payment_rate_manager
def _unset(self):
d = self._set_rate(None)
d.addCallback(lambda _: "Using the application default data rate")
return True, d
def _set_rate(self, rate):
self.payment_rate_manager.min_blob_data_payment_rate = rate
return self.settings.save_server_data_payment_rate(rate)
def _get_current_status(self):
effective_rate = self.payment_rate_manager.get_effective_min_blob_data_payment_rate()
status = "The current server data payment rate is "
if self.payment_rate_manager.min_blob_data_payment_rate is None:
status += "set to use the application default, "
status += str(effective_rate)
return status
class ModifyServerDataPaymentRateFactory(ControlHandlerFactory):
control_handler_class = ModifyServerDataPaymentRate
# class ModifyServerCryptInfoPaymentRate(ModifyPaymentRate):
# prompt_description = "Modify server live stream metadata payment rate"
#
# def __init__(self, payment_rate_manager, settings):
# ModifyPaymentRate.__init__(self)
# self._prompt_choices['unset'] = (self._unset,
# "Use the application default live stream metadata rate")
# self.settings = settings
# self.payment_rate_manager = payment_rate_manager
#
# def _unset(self):
# d = self._set_rate(None)
# d.addCallback(lambda _: "Using the application default live stream metadata rate")
# return True, d
#
# def _set_rate(self, rate):
# self.payment_rate_manager.min_live_blob_info_payment_rate = rate
# return self.settings.save_server_crypt_info_payment_rate(rate)
#
# def _get_current_status(self):
# effective_rate = self.payment_rate_manager.get_effective_min_live_blob_info_payment_rate()
# status = "The current server live stream metadata payment rate is "
# if self.payment_rate_manager.get_min_blob_data_payment_rate() is None:
# status += "set to use the application default, "
# status += str(effective_rate)
# else:
# status += str(effective_rate)
# return status
#
#
# class ModifyServerCryptInfoPaymentRateFactory(ControlHandlerFactory):
# control_handler_class = ModifyServerCryptInfoPaymentRate
class DisableQueryHandler(ControlHandler):
def __init__(self, query_handlers, query_handler, settings):
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"
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
class DisableQueryHandlerFactory(ControlHandlerFactory):
control_handler_class = DisableQueryHandler
def get_prompt_description(self):
query_handler = self.args[1]
return "Disable " + str(query_handler.get_description())
class EnableQueryHandler(ControlHandler):
def __init__(self, query_handlers, query_handler, settings):
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"
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
class EnableQueryHandlerFactory(ControlHandlerFactory):
control_handler_class = EnableQueryHandler
def get_prompt_description(self):
query_handler = self.args[1]
return "Enable " + str(query_handler.get_description())
class ModifyServerEnabledQueries(RecursiveControlHandler):
prompt_description = "Modify which queries the server will respond to"
def __init__(self, query_handlers, settings):
self.query_handlers = query_handlers
self.settings = settings
RecursiveControlHandler.__init__(self, reset_after_each_done=True)
def _get_control_handler_factories(self):
factories = []
for query_handler, enabled in self.query_handlers.iteritems():
if enabled:
factories.append(DisableQueryHandlerFactory(self.query_handlers, query_handler, self.settings))
else:
factories.append(EnableQueryHandlerFactory(self.query_handlers, query_handler, self.settings))
return factories
class ModifyServerEnabledQueriesFactory(ControlHandlerFactory):
control_handler_class = ModifyServerEnabledQueries
class ImmediateAnnounceAllBlobs(ControlHandler):
prompt_description = "Immediately announce all blob hashes to the DHT"
def __init__(self, blob_manager):
self.blob_manager = blob_manager
def handle_line(self, line):
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
class ImmediateAnnounceAllBlobsFactory(ControlHandlerFactory):
control_handler_class = ImmediateAnnounceAllBlobs
class ModifyServerSettings(RecursiveControlHandler):
prompt_description = "Modify server settings"
def __init__(self, lbry_service):
self.lbry_service = lbry_service
RecursiveControlHandler.__init__(self, reset_after_each_done=True)
def _get_control_handler_factories(self):
factories = []
if self.lbry_service.lbry_server_port is not None:
factories.append(StopServerFactory(self.lbry_service))
else:
factories.append(StartServerFactory(self.lbry_service))
factories.append(
ModifyServerDataPaymentRateFactory(
self.lbry_service.blob_request_payment_rate_manager,
self.lbry_service.settings
)
)
#factories.append(ModifyServerCryptInfoPaymentRateFactory(self.lbry_service._server_payment_rate_manager,
# self.lbry_service.settings))
factories.append(ModifyServerEnabledQueriesFactory(self.lbry_service.query_handlers,
self.lbry_service.settings))
factories.append(ImmediateAnnounceAllBlobsFactory(self.lbry_service.session.blob_manager))
return factories
class ModifyServerSettingsFactory(ControlHandlerFactory):
control_handler_class = ModifyServerSettings
class PeerChooser(RecursiveControlHandler):
def __init__(self, peer_manager, factory_class, *args, **kwargs):
"""
@param peer_manager:
@param factory_class:
@param args: all arguments that will be passed to the factory
@param kwargs: all arguments that will be passed to the superclass' __init__
@return:
"""
self.peer_manager = peer_manager
self.factory_class = factory_class
self.args = args
RecursiveControlHandler.__init__(self, **kwargs)
def _get_control_handler_factories(self):
control_handler_factories = []
for peer in self.peer_manager.peers:
control_handler_factories.append(self.factory_class(peer, *self.args))
return control_handler_factories
class PeerChooserFactory(ControlHandlerFactory):
def get_prompt_description(self):
peer = self.args[0]
return str(peer)
class ShowPeerStats(ControlHandler):
prompt_description = "Show the peer's stats"
def __init__(self, peer):
self.peer = peer
def handle_line(self, line):
return True, defer.succeed(self._get_peer_stats_string())
def _get_peer_stats_string(self):
stats = "Statistics for " + str(self.peer) + '\n'
stats += " current_score: " + str(self.peer.score) + '\n'
stats += " is_available: " + str(self.peer.is_available()) + '\n'
for stat_type, amount in self.peer.stats.iteritems():
stats += " " + stat_type + ": " + str(amount) + "\n"
return stats
class ShowPeerStatsFactory(ControlHandlerFactory):
control_handler_class = ShowPeerStats
class PeerStatsAndSettings(RecursiveControlHandler):
def __init__(self, peer):
self.peer = peer
RecursiveControlHandler.__init__(self, reset_after_each_done=True)
def _get_control_handler_factories(self):
factories = []
factories.append(ShowPeerStatsFactory(self.peer))
return factories
class PeerStatsAndSettingsFactory(PeerChooserFactory):
control_handler_class = PeerStatsAndSettings
class PeerStatsAndSettingsChooser(PeerChooser):
prompt_description = "View peer stats and modify peer settings"
def __init__(self, peer_manager):
PeerChooser.__init__(self, peer_manager, PeerStatsAndSettingsFactory)
class PeerStatsAndSettingsChooserFactory(ControlHandlerFactory):
control_handler_class = PeerStatsAndSettingsChooser