lbry-sdk/lbrynet/daemon/DaemonCLI.py

225 lines
6.8 KiB
Python
Raw Normal View History

2016-11-11 19:40:19 +01:00
import json
2017-01-03 20:13:01 +01:00
import os
2017-01-09 20:03:25 +01:00
import sys
import colorama
2017-05-28 22:02:22 +02:00
from docopt import docopt
from collections import OrderedDict
2017-01-09 20:03:25 +01:00
from lbrynet import conf
from lbrynet.core import utils
from lbrynet.daemon.auth.client import JSONRPCException, LBRYAPIClient, AuthAPIClient
refactor lbrynet-daemon into modular components (#1164) * add daemon Component and ComponentManager classes * convert directory and SQLiteStorage setup to be a Component * support callbacks to component setups * Fixed typo in ComponentManager * convert wallet to be Component * Use storage from session. * Remove create_session internal function and PEP8 * Starting to convert session to its own component. Removed ref to `self.storage` from Daemon.py * Making DHT component(broken) * Refactored classes to reduce redundancy in getting config setting * DHT is now it's own component * Fixed `test_streamify` test * Fixed regression caused by removing `peer_manager` from session * refactor ComponentManager and Component to use instance instead of class methods * Hash announcer, file manager, stream identifier components * Query Handler and server components * Reflector Component * Fixed test_streamify(well Jack did, but ¯\_(ツ)_/¯) * All tests now passing * Pylint fixes * Oops(That's all you're gonna get :-P) * Making decorators(WIP, commit so that I don't lose work) * Decorator made and decorating of functions done(some other changes) * import fixes and removed temporary test function * Fixed new broken tests from daemon refactor * Sanitization of modules * Reworded errors * wallet unlock condition checks, fixed breaking changes * Rebased on amster and other crazy stuff * Started writing tests * Tests for component manager * Fix Daemon Tests * Fixed passing mutable args in init * Using constants instead of strings. Added CHANGELOG.md * Now components can be skipped by setting relevant config in file. * P-Y-L-I-N-T #angry_emoji
2018-07-05 21:21:52 +02:00
from lbrynet.daemon.Daemon import Daemon
from lbrynet.core.system_info import get_platform
2016-11-11 19:40:19 +01:00
from jsonrpc.common import RPCError
from requests.exceptions import ConnectionError
from urllib2 import URLError, HTTPError
from httplib import UNAUTHORIZED
2016-07-06 09:02:55 +02:00
2017-05-28 22:02:22 +02:00
def remove_brackets(key):
if key.startswith("<") and key.endswith(">"):
return str(key[1:-1])
return key
refactor lbrynet-daemon into modular components (#1164) * add daemon Component and ComponentManager classes * convert directory and SQLiteStorage setup to be a Component * support callbacks to component setups * Fixed typo in ComponentManager * convert wallet to be Component * Use storage from session. * Remove create_session internal function and PEP8 * Starting to convert session to its own component. Removed ref to `self.storage` from Daemon.py * Making DHT component(broken) * Refactored classes to reduce redundancy in getting config setting * DHT is now it's own component * Fixed `test_streamify` test * Fixed regression caused by removing `peer_manager` from session * refactor ComponentManager and Component to use instance instead of class methods * Hash announcer, file manager, stream identifier components * Query Handler and server components * Reflector Component * Fixed test_streamify(well Jack did, but ¯\_(ツ)_/¯) * All tests now passing * Pylint fixes * Oops(That's all you're gonna get :-P) * Making decorators(WIP, commit so that I don't lose work) * Decorator made and decorating of functions done(some other changes) * import fixes and removed temporary test function * Fixed new broken tests from daemon refactor * Sanitization of modules * Reworded errors * wallet unlock condition checks, fixed breaking changes * Rebased on amster and other crazy stuff * Started writing tests * Tests for component manager * Fix Daemon Tests * Fixed passing mutable args in init * Using constants instead of strings. Added CHANGELOG.md * Now components can be skipped by setting relevant config in file. * P-Y-L-I-N-T #angry_emoji
2018-07-05 21:21:52 +02:00
def set_kwargs(parsed_args):
2017-05-28 22:02:22 +02:00
kwargs = OrderedDict()
for key, arg in parsed_args.iteritems():
if arg is None:
continue
refactor lbrynet-daemon into modular components (#1164) * add daemon Component and ComponentManager classes * convert directory and SQLiteStorage setup to be a Component * support callbacks to component setups * Fixed typo in ComponentManager * convert wallet to be Component * Use storage from session. * Remove create_session internal function and PEP8 * Starting to convert session to its own component. Removed ref to `self.storage` from Daemon.py * Making DHT component(broken) * Refactored classes to reduce redundancy in getting config setting * DHT is now it's own component * Fixed `test_streamify` test * Fixed regression caused by removing `peer_manager` from session * refactor ComponentManager and Component to use instance instead of class methods * Hash announcer, file manager, stream identifier components * Query Handler and server components * Reflector Component * Fixed test_streamify(well Jack did, but ¯\_(ツ)_/¯) * All tests now passing * Pylint fixes * Oops(That's all you're gonna get :-P) * Making decorators(WIP, commit so that I don't lose work) * Decorator made and decorating of functions done(some other changes) * import fixes and removed temporary test function * Fixed new broken tests from daemon refactor * Sanitization of modules * Reworded errors * wallet unlock condition checks, fixed breaking changes * Rebased on amster and other crazy stuff * Started writing tests * Tests for component manager * Fix Daemon Tests * Fixed passing mutable args in init * Using constants instead of strings. Added CHANGELOG.md * Now components can be skipped by setting relevant config in file. * P-Y-L-I-N-T #angry_emoji
2018-07-05 21:21:52 +02:00
elif key.startswith("--") and remove_brackets(key[2:]) not in kwargs:
k = remove_brackets(key[2:])
2017-05-28 22:02:22 +02:00
elif remove_brackets(key) not in kwargs:
k = remove_brackets(key)
kwargs[k] = guess_type(arg, k)
2017-05-28 22:02:22 +02:00
return kwargs
2017-01-09 20:03:25 +01:00
def main():
argv = sys.argv[1:]
# check if a config file has been specified. If so, shift
# all the arguments so that the parsing can continue without
# noticing
if len(argv) and argv[0] == "--conf":
if len(argv) < 2:
print_error("No config file specified for --conf option")
print_help()
return
conf.conf_file = argv[1]
argv = argv[2:]
if len(argv):
method, args = argv[0], argv[1:]
2017-05-28 22:02:22 +02:00
else:
print_help()
return
if method in ['help', '--help', '-h']:
if len(args) == 1:
print_help_for_command(args[0])
else:
print_help()
return
2017-01-09 20:03:25 +01:00
elif method in ['version', '--version']:
print utils.json_dumps_pretty(get_platform(get_ip=False))
return
2017-05-28 22:02:22 +02:00
if method not in Daemon.callable_methods:
if method not in Daemon.deprecated_methods:
print_error("\"%s\" is not a valid command." % method)
return
new_method = Daemon.deprecated_methods[method]._new_command
print_error("\"%s\" is deprecated, using \"%s\"." % (method, new_method))
method = new_method
2017-05-28 22:02:22 +02:00
fn = Daemon.callable_methods[method]
parsed = docopt(fn.__doc__, args)
refactor lbrynet-daemon into modular components (#1164) * add daemon Component and ComponentManager classes * convert directory and SQLiteStorage setup to be a Component * support callbacks to component setups * Fixed typo in ComponentManager * convert wallet to be Component * Use storage from session. * Remove create_session internal function and PEP8 * Starting to convert session to its own component. Removed ref to `self.storage` from Daemon.py * Making DHT component(broken) * Refactored classes to reduce redundancy in getting config setting * DHT is now it's own component * Fixed `test_streamify` test * Fixed regression caused by removing `peer_manager` from session * refactor ComponentManager and Component to use instance instead of class methods * Hash announcer, file manager, stream identifier components * Query Handler and server components * Reflector Component * Fixed test_streamify(well Jack did, but ¯\_(ツ)_/¯) * All tests now passing * Pylint fixes * Oops(That's all you're gonna get :-P) * Making decorators(WIP, commit so that I don't lose work) * Decorator made and decorating of functions done(some other changes) * import fixes and removed temporary test function * Fixed new broken tests from daemon refactor * Sanitization of modules * Reworded errors * wallet unlock condition checks, fixed breaking changes * Rebased on amster and other crazy stuff * Started writing tests * Tests for component manager * Fix Daemon Tests * Fixed passing mutable args in init * Using constants instead of strings. Added CHANGELOG.md * Now components can be skipped by setting relevant config in file. * P-Y-L-I-N-T #angry_emoji
2018-07-05 21:21:52 +02:00
kwargs = set_kwargs(parsed)
2017-05-28 22:02:22 +02:00
colorama.init()
2017-01-09 20:03:25 +01:00
conf.initialize_settings()
try:
api = LBRYAPIClient.get_client()
refactor lbrynet-daemon into modular components (#1164) * add daemon Component and ComponentManager classes * convert directory and SQLiteStorage setup to be a Component * support callbacks to component setups * Fixed typo in ComponentManager * convert wallet to be Component * Use storage from session. * Remove create_session internal function and PEP8 * Starting to convert session to its own component. Removed ref to `self.storage` from Daemon.py * Making DHT component(broken) * Refactored classes to reduce redundancy in getting config setting * DHT is now it's own component * Fixed `test_streamify` test * Fixed regression caused by removing `peer_manager` from session * refactor ComponentManager and Component to use instance instead of class methods * Hash announcer, file manager, stream identifier components * Query Handler and server components * Reflector Component * Fixed test_streamify(well Jack did, but ¯\_(ツ)_/¯) * All tests now passing * Pylint fixes * Oops(That's all you're gonna get :-P) * Making decorators(WIP, commit so that I don't lose work) * Decorator made and decorating of functions done(some other changes) * import fixes and removed temporary test function * Fixed new broken tests from daemon refactor * Sanitization of modules * Reworded errors * wallet unlock condition checks, fixed breaking changes * Rebased on amster and other crazy stuff * Started writing tests * Tests for component manager * Fix Daemon Tests * Fixed passing mutable args in init * Using constants instead of strings. Added CHANGELOG.md * Now components can be skipped by setting relevant config in file. * P-Y-L-I-N-T #angry_emoji
2018-07-05 21:21:52 +02:00
api.status()
except (URLError, ConnectionError) as err:
if isinstance(err, HTTPError) and err.code == UNAUTHORIZED:
api = AuthAPIClient.config()
# this can happen if the daemon is using auth with the --http-auth flag
# when the config setting is to not use it
try:
refactor lbrynet-daemon into modular components (#1164) * add daemon Component and ComponentManager classes * convert directory and SQLiteStorage setup to be a Component * support callbacks to component setups * Fixed typo in ComponentManager * convert wallet to be Component * Use storage from session. * Remove create_session internal function and PEP8 * Starting to convert session to its own component. Removed ref to `self.storage` from Daemon.py * Making DHT component(broken) * Refactored classes to reduce redundancy in getting config setting * DHT is now it's own component * Fixed `test_streamify` test * Fixed regression caused by removing `peer_manager` from session * refactor ComponentManager and Component to use instance instead of class methods * Hash announcer, file manager, stream identifier components * Query Handler and server components * Reflector Component * Fixed test_streamify(well Jack did, but ¯\_(ツ)_/¯) * All tests now passing * Pylint fixes * Oops(That's all you're gonna get :-P) * Making decorators(WIP, commit so that I don't lose work) * Decorator made and decorating of functions done(some other changes) * import fixes and removed temporary test function * Fixed new broken tests from daemon refactor * Sanitization of modules * Reworded errors * wallet unlock condition checks, fixed breaking changes * Rebased on amster and other crazy stuff * Started writing tests * Tests for component manager * Fix Daemon Tests * Fixed passing mutable args in init * Using constants instead of strings. Added CHANGELOG.md * Now components can be skipped by setting relevant config in file. * P-Y-L-I-N-T #angry_emoji
2018-07-05 21:21:52 +02:00
api.status()
except:
print_error("Daemon requires authentication, but none was provided.",
suggest_help=False)
return 1
else:
print_error("Could not connect to daemon. Are you sure it's running?",
suggest_help=False)
return 1
2017-01-09 20:03:25 +01:00
2017-01-11 21:31:08 +01:00
# TODO: check if port is bound. Error if its not
2017-05-28 22:02:22 +02:00
try:
2018-03-29 18:19:41 +02:00
result = api.call(method, kwargs)
2017-05-28 22:02:22 +02:00
if isinstance(result, basestring):
# printing the undumped string is prettier
print result
2017-01-09 20:03:25 +01:00
else:
2017-05-28 22:02:22 +02:00
print utils.json_dumps_pretty(result)
except (RPCError, KeyError, JSONRPCException, HTTPError) as err:
if isinstance(err, HTTPError):
error_body = err.read()
try:
error_data = json.loads(error_body)
except ValueError:
print (
"There was an error, and the response was not valid JSON.\n" +
"Raw JSONRPC response:\n" + error_body
)
return 1
print_error(error_data['error']['message'] + "\n", suggest_help=False)
2017-12-13 19:56:44 +01:00
if 'data' in error_data['error'] and 'traceback' in error_data['error']['data']:
print "Here's the traceback for the error you encountered:"
print "\n".join(error_data['error']['data']['traceback'])
print_help_for_command(method)
elif isinstance(err, RPCError):
print_error(err.msg, suggest_help=False)
# print_help_for_command(method)
2017-05-28 22:02:22 +02:00
else:
print_error("Something went wrong\n", suggest_help=False)
2017-12-13 22:43:49 +01:00
print str(err)
2017-01-09 20:03:25 +01:00
2017-05-28 22:02:22 +02:00
return 1
def guess_type(x, key=None):
2017-05-28 22:02:22 +02:00
if not isinstance(x, (unicode, str)):
return x
if key in ('uri', 'channel_name', 'name', 'file_name', 'download_directory'):
return x
2017-03-23 22:44:06 +01:00
if x in ('true', 'True', 'TRUE'):
return True
if x in ('false', 'False', 'FALSE'):
return False
if '.' in x:
try:
return float(x)
except ValueError:
# not a float
pass
try:
return int(x)
except ValueError:
return x
2017-01-09 20:03:25 +01:00
def print_help_suggestion():
print "See `{} help` for more information.".format(os.path.basename(sys.argv[0]))
def print_error(message, suggest_help=True):
error_style = colorama.Style.BRIGHT + colorama.Fore.RED
print error_style + "ERROR: " + message + colorama.Style.RESET_ALL
2017-01-09 20:03:25 +01:00
if suggest_help:
print_help_suggestion()
2017-05-28 22:02:22 +02:00
def print_help():
2017-01-04 23:15:08 +01:00
print "\n".join([
"NAME",
" lbrynet-cli - LBRY command line client.",
"",
"USAGE",
" lbrynet-cli [--conf <config file>] <command> [<args>]",
2017-01-04 23:15:08 +01:00
"",
"EXAMPLES",
" lbrynet-cli commands # list available commands",
" lbrynet-cli status # get daemon status",
" lbrynet-cli --conf ~/l1.conf status # like above but using ~/l1.conf as config file",
" lbrynet-cli resolve_name what # resolve a name",
" lbrynet-cli help resolve_name # get help for a command",
2017-01-04 23:15:08 +01:00
])
2017-05-28 22:02:22 +02:00
def print_help_for_command(command):
fn = Daemon.callable_methods.get(command)
if fn:
print "Help for %s method:\n%s" % (command, fn.__doc__)
2017-01-04 23:15:08 +01:00
def wrap_list_to_term_width(l, width=None, separator=', ', prefix=''):
if width is None:
try:
_, width = os.popen('stty size', 'r').read().split()
width = int(width)
except:
pass
if not width:
width = 80
lines = []
2017-01-09 20:03:25 +01:00
curr_line = ''
2017-01-04 23:15:08 +01:00
for item in l:
new_line = curr_line + item + separator
2017-01-09 20:03:25 +01:00
if len(new_line) + len(prefix) > width:
2017-01-04 23:15:08 +01:00
lines.append(curr_line)
2017-01-09 20:03:25 +01:00
curr_line = item + separator
2017-01-04 23:15:08 +01:00
else:
curr_line = new_line
2017-01-09 20:03:25 +01:00
lines.append(curr_line)
2017-01-04 23:15:08 +01:00
2017-01-09 20:03:25 +01:00
ret = prefix + ("\n" + prefix).join(lines)
if ret.endswith(separator):
ret = ret[:-len(separator)]
return ret
if __name__ == '__main__':
2017-01-09 20:03:25 +01:00
sys.exit(main())