Merge branch 'rename_api_methods'

* rename_api_methods:
  updates based on job's comments
  appveyor is a line-length nazi
  detect authentication error and warn accordingly
  remove authjsonrpc subhandlers. we dont use them
  rpc works with authentication
  restore one deprecated method (for now)
  incorporate job's changes
  remove return codes that are not being used
  make sure deprecated methods still return results
  better cli help
  remove extraneous ellipses in messages
  rename api endpoints
This commit is contained in:
Alex Grintsvayg 2017-01-11 16:36:59 -05:00
commit 93ff4f63b5
18 changed files with 840 additions and 674 deletions

5
.gitignore vendored
View file

@ -9,12 +9,11 @@
/build /build
/dist /dist
/lbrynet.egg-info
.idea/.name .idea/.name
.coverage .coverage
.DS_Store .DS_Store
lbrynet.egg-info/PKG-INFO
# temporary files from the twisted.trial test runner # temporary files from the twisted.trial test runner
_trial_temp/ _trial_temp/

9
FAQ.md
View file

@ -77,9 +77,10 @@ Note: the lbry api can only be used while either the app or lbrynet-daemon comma
sys.exit(0) sys.exit(0)
api = JSONRPCProxy.from_url(API_CONNECTION_STRING) api = JSONRPCProxy.from_url(API_CONNECTION_STRING)
if not api.is_running(): status = api.status()
print api.daemon_status() if not status['is_running']:
print status
else: else:
for func in api.help(): for cmd in api.commands():
print "%s:\n%s" % (func, api.help({'function': func})) print "%s:\n%s" % (cmd, api.help({'command': cmd}))

View file

@ -49,11 +49,12 @@ except:
API_CONNECTION_STRING = "http://localhost:5279/lbryapi" API_CONNECTION_STRING = "http://localhost:5279/lbryapi"
api = JSONRPCProxy.from_url(API_CONNECTION_STRING) api = JSONRPCProxy.from_url(API_CONNECTION_STRING)
if not api.is_running(): status = api.status()
print api.daemon_status() if not status['is_running']:
print status
else: else:
for func in api.help(): for cmd in api.commands():
print "%s:\n%s" % (func, api.help({'function': func})) print "%s:\n%s" % (cmd, api.help({'command': cmd}))
``` ```
If you've installed lbrynet, it comes with a file sharing application, called `lbrynet-daemon`, which breaks If you've installed lbrynet, it comes with a file sharing application, called `lbrynet-daemon`, which breaks

View file

@ -96,9 +96,5 @@ class InvalidAuthenticationToken(Exception):
pass pass
class SubhandlerError(Exception):
pass
class NegotiationError(Exception): class NegotiationError(Exception):
pass pass

View file

@ -182,10 +182,6 @@ class Wallet(object):
"""This class implements the Wallet interface for the LBRYcrd payment system""" """This class implements the Wallet interface for the LBRYcrd payment system"""
implements(IWallet) implements(IWallet)
_FIRST_RUN_UNKNOWN = 0
_FIRST_RUN_YES = 1
_FIRST_RUN_NO = 2
def __init__(self, storage): def __init__(self, storage):
if not isinstance(storage, MetaDataStorage): if not isinstance(storage, MetaDataStorage):
raise ValueError('storage must be an instance of MetaDataStorage') raise ValueError('storage must be an instance of MetaDataStorage')
@ -209,7 +205,6 @@ class Wallet(object):
self._manage_count = 0 self._manage_count = 0
self._balance_refresh_time = 3 self._balance_refresh_time = 3
self._batch_count = 20 self._batch_count = 20
self._first_run = self._FIRST_RUN_UNKNOWN
def start(self): def start(self):
def start_manage(): def start_manage():
@ -703,20 +698,6 @@ class Wallet(object):
def get_available_balance(self): def get_available_balance(self):
return float(self.wallet_balance - self.total_reserved_points) return float(self.wallet_balance - self.total_reserved_points)
def is_first_run(self):
if self._first_run == self._FIRST_RUN_UNKNOWN:
d = self._check_first_run()
def set_first_run(is_first):
self._first_run = self._FIRST_RUN_YES if is_first else self._FIRST_RUN_NO
d.addCallback(set_first_run)
else:
d = defer.succeed(self._FIRST_RUN_YES if self._first_run else self._FIRST_RUN_NO)
d.addCallback(lambda _: self._first_run == self._FIRST_RUN_YES)
return d
def _get_status_of_claim(self, claim_outpoint, name, sd_hash): def _get_status_of_claim(self, claim_outpoint, name, sd_hash):
d = self.get_claims_from_tx(claim_outpoint['txid']) d = self.get_claims_from_tx(claim_outpoint['txid'])
@ -819,9 +800,6 @@ class Wallet(object):
def _get_claims_for_name(self, name): def _get_claims_for_name(self, name):
return defer.fail(NotImplementedError()) return defer.fail(NotImplementedError())
def _check_first_run(self):
return defer.fail(NotImplementedError())
def _send_name_claim(self, name, val, amount): def _send_name_claim(self, name, val, amount):
return defer.fail(NotImplementedError()) return defer.fail(NotImplementedError())
@ -865,13 +843,13 @@ class LBRYumWallet(Wallet):
self._config = config self._config = config
self.network = None self.network = None
self.wallet = None self.wallet = None
self.first_run = False self.is_first_run = False
self.printed_retrieving_headers = False self.printed_retrieving_headers = False
self._start_check = None self._start_check = None
self._catch_up_check = None self._catch_up_check = None
self._caught_up_counter = 0 self._caught_up_counter = 0
self._lag_counter = 0 self._lag_counter = 0
self.blocks_behind_alert = 0 self.blocks_behind = 0
self.catchup_progress = 0 self.catchup_progress = 0
self.max_behind = 0 self.max_behind = 0
@ -881,16 +859,15 @@ class LBRYumWallet(Wallet):
def setup_network(): def setup_network():
self.config = make_config(self._config) self.config = make_config(self._config)
self.network = Network(self.config) self.network = Network(self.config)
alert.info("Loading the wallet...") alert.info("Loading the wallet")
return defer.succeed(self.network.start()) return defer.succeed(self.network.start())
d = setup_network() d = setup_network()
def check_started(): def check_started():
if self.network.is_connecting(): if self.network.is_connecting():
if not self.printed_retrieving_headers and self.network.blockchain.retrieving_headers: if not self.printed_retrieving_headers and self.network.blockchain.retrieving_headers:
alert.info("Running the wallet for the first time...this may take a moment.") alert.info("Running the wallet for the first time. This may take a moment.")
self.printed_retrieving_headers = True self.printed_retrieving_headers = True
return False return False
self._start_check.stop() self._start_check.stop()
@ -941,7 +918,7 @@ class LBRYumWallet(Wallet):
storage = lbryum.wallet.WalletStorage(path) storage = lbryum.wallet.WalletStorage(path)
wallet = lbryum.wallet.Wallet(storage) wallet = lbryum.wallet.Wallet(storage)
if not storage.file_exists: if not storage.file_exists:
self.first_run = True self.is_first_run = True
seed = wallet.make_seed() seed = wallet.make_seed()
wallet.add_seed(seed, None) wallet.add_seed(seed, None)
wallet.create_master_keys(None) wallet.create_master_keys(None)
@ -957,7 +934,13 @@ class LBRYumWallet(Wallet):
local_height = self.network.get_catchup_progress() local_height = self.network.get_catchup_progress()
remote_height = self.network.get_server_height() remote_height = self.network.get_server_height()
if remote_height != 0 and remote_height - local_height <= 5: if remote_height == 0:
return
height_diff = remote_height - local_height
if height_diff <= 5:
self.blocks_behind = 0
msg = "" msg = ""
if self._caught_up_counter != 0: if self._caught_up_counter != 0:
msg += "All caught up. " msg += "All caught up. "
@ -966,27 +949,29 @@ class LBRYumWallet(Wallet):
self._catch_up_check.stop() self._catch_up_check.stop()
self._catch_up_check = None self._catch_up_check = None
blockchain_caught_d.callback(True) blockchain_caught_d.callback(True)
return
elif remote_height != 0: if height_diff < self.blocks_behind:
past_blocks_behind = self.blocks_behind_alert # We're making progress in catching up
self.blocks_behind_alert = remote_height - local_height self._lag_counter = 0
if self.blocks_behind_alert < past_blocks_behind: self.is_lagging = False
self._lag_counter = 0 else:
self.is_lagging = False # No progress. Might be lagging
else: self._lag_counter += 1
self._lag_counter += 1 if self._lag_counter >= 900:
if self._lag_counter >= 900: self.is_lagging = True
self.is_lagging = True
if self.blocks_behind_alert > self.max_behind: self.blocks_behind = height_diff
self.max_behind = self.blocks_behind_alert
self.catchup_progress = int(100 * (self.blocks_behind_alert / (5 + self.max_behind)))
if self._caught_up_counter == 0:
alert.info('Catching up with the blockchain...showing blocks left...')
if self._caught_up_counter % 30 == 0:
alert.info('%d...', (remote_height - local_height))
self._caught_up_counter += 1 if self.blocks_behind > self.max_behind:
self.max_behind = self.blocks_behind
self.catchup_progress = int(100 * (self.blocks_behind / (5 + self.max_behind)))
if self._caught_up_counter == 0:
alert.info('Catching up with the blockchain')
if self._caught_up_counter % 30 == 0:
alert.info('Blocks left: %d', (remote_height - local_height))
self._caught_up_counter += 1
def log_error(err): def log_error(err):
log.warning(err.getErrorMessage()) log.warning(err.getErrorMessage())
@ -1052,9 +1037,6 @@ class LBRYumWallet(Wallet):
def get_name_claims(self): def get_name_claims(self):
return self._run_cmd_as_defer_succeed('getnameclaims') return self._run_cmd_as_defer_succeed('getnameclaims')
def _check_first_run(self):
return defer.succeed(self.first_run)
def _get_claims_for_name(self, name): def _get_claims_for_name(self, name):
return self._run_cmd_as_defer_to_thread('getclaimsforname', name) return self._run_cmd_as_defer_to_thread('getclaimsforname', name)

View file

@ -14,7 +14,7 @@ amount = 0
def destroyNetwork(nodes): def destroyNetwork(nodes):
print 'Destroying Kademlia network...' print 'Destroying Kademlia network'
i = 0 i = 0
for node in nodes: for node in nodes:
i += 1 i += 1
@ -50,12 +50,12 @@ def main():
else: else:
import socket import socket
ipAddress = socket.gethostbyname(socket.gethostname()) ipAddress = socket.gethostbyname(socket.gethostname())
print 'Network interface IP address omitted; using %s...' % ipAddress print 'Network interface IP address omitted; using %s' % ipAddress
startPort = 4000 startPort = 4000
port = startPort+1 port = startPort+1
nodes = [] nodes = []
print 'Creating Kademlia network...' print 'Creating Kademlia network'
try: try:
node = os.spawnlp( node = os.spawnlp(
os.P_NOWAIT, 'lbrynet-launch-node', 'lbrynet-launch-node', str(startPort)) os.P_NOWAIT, 'lbrynet-launch-node', 'lbrynet-launch-node', str(startPort))

View file

@ -16,10 +16,10 @@ def print_usage():
def join_network(udp_port, known_nodes): def join_network(udp_port, known_nodes):
lbryid = generate_id() lbryid = generate_id()
log.info('Creating Node...') log.info('Creating Node')
node = Node(udpPort=udp_port, lbryid=lbryid) node = Node(udpPort=udp_port, lbryid=lbryid)
log.info('Joining network...') log.info('Joining network')
d = node.joinNetwork(known_nodes) d = node.joinNetwork(known_nodes)
def log_network_size(): def log_network_size():

View file

@ -59,7 +59,7 @@ def storeValueCallback(*args, **kwargs):
""" Callback function that is invoked when the storeValue() operation succeeds """ """ Callback function that is invoked when the storeValue() operation succeeds """
print 'Value has been stored in the DHT' print 'Value has been stored in the DHT'
# Now that the value has been stored, schedule that the value is read again after 2.5 seconds # Now that the value has been stored, schedule that the value is read again after 2.5 seconds
print 'Scheduling retrieval in 2.5 seconds...' print 'Scheduling retrieval in 2.5 seconds'
twisted.internet.reactor.callLater(2.5, getValue) twisted.internet.reactor.callLater(2.5, getValue)
@ -72,7 +72,7 @@ def getValue():
""" Retrieves the value of the specified key (KEY) from the DHT """ """ Retrieves the value of the specified key (KEY) from the DHT """
global node, KEY global node, KEY
# Get the value for the specified key (immediately returns a Twisted deferred result) # Get the value for the specified key (immediately returns a Twisted deferred result)
print ('\nRetrieving value from DHT for key "%s"...' % print ('\nRetrieving value from DHT for key "%s"' %
binascii.unhexlify("f7d9dc4de674eaa2c5a022eb95bc0d33ec2e75c6")) binascii.unhexlify("f7d9dc4de674eaa2c5a022eb95bc0d33ec2e75c6"))
deferredResult = node.iterativeFindValue( deferredResult = node.iterativeFindValue(
binascii.unhexlify("f7d9dc4de674eaa2c5a022eb95bc0d33ec2e75c6")) binascii.unhexlify("f7d9dc4de674eaa2c5a022eb95bc0d33ec2e75c6"))
@ -91,13 +91,13 @@ def getValueCallback(result):
print result print result
# Either way, schedule a "delete" operation for the key # Either way, schedule a "delete" operation for the key
print 'Scheduling shutdown in 2.5 seconds...' print 'Scheduling shutdown in 2.5 seconds'
twisted.internet.reactor.callLater(2.5, stop) twisted.internet.reactor.callLater(2.5, stop)
def stop(): def stop():
""" Stops the Twisted reactor, and thus the script """ """ Stops the Twisted reactor, and thus the script """
print '\nStopping Kademlia node and terminating script...' print '\nStopping Kademlia node and terminating script'
twisted.internet.reactor.stop() twisted.internet.reactor.stop()
if __name__ == '__main__': if __name__ == '__main__':
@ -145,7 +145,7 @@ if __name__ == '__main__':
# #
# If you wish to have a pure Kademlia network, use the # If you wish to have a pure Kademlia network, use the
# entangled.kademlia.node.Node class instead # entangled.kademlia.node.Node class instead
print 'Creating Node...' print 'Creating Node'
node = Node(udpPort=int(sys.argv[1]), lbryid=lbryid) node = Node(udpPort=int(sys.argv[1]), lbryid=lbryid)
# Schedule the node to join the Kademlia/Entangled DHT # Schedule the node to join the Kademlia/Entangled DHT

File diff suppressed because it is too large Load diff

View file

@ -1,18 +1,93 @@
import sys
import argparse import argparse
import json import json
import os
import sys
from lbrynet import conf from lbrynet import conf
from lbrynet.lbrynet_daemon.auth.client import LBRYAPIClient from lbrynet.lbrynet_daemon.auth.client import JSONRPCException, LBRYAPIClient
from lbrynet.lbrynet_daemon.Daemon import LOADING_WALLET_CODE
from jsonrpc.common import RPCError from jsonrpc.common import RPCError
from urllib2 import URLError, HTTPError
from httplib import UNAUTHORIZED
def main():
parser = argparse.ArgumentParser(add_help=False)
_, arguments = parser.parse_known_args()
help_msg = "Usage: lbrynet-cli method kwargs\n" \ conf.initialize_settings()
+ "Examples: " \ conf.update_settings_from_file()
+ "lbrynet-cli resolve_name name=what\n" \ api = LBRYAPIClient.get_client()
+ "lbrynet-cli get_balance\n" \
+ "lbrynet-cli help function=resolve_name\n" \ try:
+ "\n******lbrynet-cli functions******\n" status = api.status()
except URLError as err:
if isinstance(err, HTTPError) and err.code == UNAUTHORIZED:
print_error("Daemon requires authentication, but none was provided.",
suggest_help=False)
else:
print_error("Could not connect to daemon. Are you sure it's running?",
suggest_help=False)
return 1
if status['startup_status']['code'] != "started":
print "Daemon is in the process of starting. Please try again in a bit."
message = status['startup_status']['message']
if message:
if (
status['startup_status']['code'] == LOADING_WALLET_CODE
and status['blocks_behind'] > 0
):
message += '. Blocks left: ' + str(status['blocks_behind'])
print " Status: " + message
return 1
if len(arguments) < 1:
print_help(api)
return 1
method = arguments[0]
try:
params = parse_params(arguments[1:])
except InvalidParameters as e:
print_error(e.message)
return 1
# TODO: check if port is bound. Error if its not
if method in ['--help', '-h', 'help']:
if len(params) == 0:
print_help(api)
elif 'command' not in params:
print_error(
'To get help on a specific command, use `{} help command=COMMAND_NAME`'.format(
os.path.basename(sys.argv[0]))
)
else:
print api.call('help', params).strip()
elif method not in api.commands():
print_error("'" + method + "' is not a valid command.")
else:
try:
result = api.call(method, params)
if isinstance(result, basestring):
# printing the undumped string is prettier
print result
else:
print json.dumps(result, sort_keys=True, indent=2, separators=(',', ': '))
except (RPCError, KeyError, JSONRPCException) as err:
# TODO: The api should return proper error codes
# and messages so that they can be passed along to the user
# instead of this generic message.
# https://app.asana.com/0/158602294500137/200173944358192
print "Something went wrong, here's the usage for %s:" % method
print api.call('help', {'command': method})
if hasattr(err, 'msg'):
print "Here's the traceback for the error you encountered:"
print err.msg
return 1
def guess_type(x): def guess_type(x):
@ -28,77 +103,89 @@ def guess_type(x):
return x return x
def parse_params(params):
if len(params) > 1:
return get_params_from_kwargs(params)
elif len(params) == 1:
try:
return json.loads(params[0])
except ValueError:
return get_params_from_kwargs(params)
else:
return {}
class InvalidParameters(Exception):
pass
def get_params_from_kwargs(params): def get_params_from_kwargs(params):
params_for_return = {} params_for_return = {}
for i in params: for i in params:
eq_pos = i.index('=') try:
k, v = i[:eq_pos], i[eq_pos+1:] eq_pos = i.index('=')
except ValueError:
raise InvalidParameters('{} is not in <key>=<value> format'.format(i))
k, v = i[:eq_pos], i[eq_pos + 1:]
params_for_return[k] = guess_type(v) params_for_return[k] = guess_type(v)
return params_for_return return params_for_return
def main(): def print_help_suggestion():
conf.initialize_settings() print "See `{} help` for more information.".format(os.path.basename(sys.argv[0]))
api = LBRYAPIClient.config()
try:
status = api.daemon_status() def print_error(message, suggest_help=True):
assert status.get('code', False) == "started" print "ERROR: " + message
except Exception: if suggest_help:
print_help_suggestion()
def print_help(api):
print "\n".join([
"NAME",
" lbrynet-cli - LBRY command line client.",
"",
"USAGE",
" lbrynet-cli <command> [<args>]",
"",
"EXAMPLES",
" lbrynet-cli commands # list available commands",
" lbrynet-cli status # get daemon status",
" lbrynet-cli resolve_name name=what # resolve a name",
" lbrynet-cli help command=resolve_name # get help for a command",
"",
"COMMANDS",
wrap_list_to_term_width(api.commands(), prefix=' ')
])
def wrap_list_to_term_width(l, width=None, separator=', ', prefix=''):
if width is None:
try: try:
conf.settings.update({'use_auth_http': not conf.settings.use_auth_http}) _, width = os.popen('stty size', 'r').read().split()
api = LBRYAPIClient.config() width = int(width)
status = api.daemon_status() except:
assert status.get('code', False) == "started" pass
except Exception: if not width:
print "lbrynet-daemon isn't running" width = 80
sys.exit(1)
parser = argparse.ArgumentParser() lines = []
parser.add_argument('method', nargs=1) curr_line = ''
parser.add_argument('params', nargs=argparse.REMAINDER, default=None) for item in l:
args = parser.parse_args() new_line = curr_line + item + separator
if len(new_line) + len(prefix) > width:
lines.append(curr_line)
curr_line = item + separator
else:
curr_line = new_line
lines.append(curr_line)
meth = args.method[0] ret = prefix + ("\n" + prefix).join(lines)
params = {} if ret.endswith(separator):
ret = ret[:-len(separator)]
if len(args.params) > 1: return ret
params = get_params_from_kwargs(args.params)
elif len(args.params) == 1:
try:
params = json.loads(args.params[0])
except ValueError:
params = get_params_from_kwargs(args.params)
msg = help_msg
for f in api.help():
msg += f + "\n"
if meth in ['--help', '-h', 'help']:
print msg
sys.exit(1)
if meth in api.help():
try:
if params:
result = LBRYAPIClient.config(service=meth, params=params)
else:
result = LBRYAPIClient.config(service=meth, params=params)
print json.dumps(result, sort_keys=True)
except RPCError as err:
# TODO: The api should return proper error codes
# and messages so that they can be passed along to the user
# instead of this generic message.
# https://app.asana.com/0/158602294500137/200173944358192
print "Something went wrong, here's the usage for %s:" % meth
print api.help({'function': meth})
print "Here's the traceback for the error you encountered:"
print err.msg
else:
print "Unknown function"
print msg
if __name__ == '__main__': if __name__ == '__main__':
main() sys.exit(main())

View file

@ -9,7 +9,7 @@ from jsonrpc.proxy import JSONRPCProxy
from lbrynet import analytics from lbrynet import analytics
from lbrynet import conf from lbrynet import conf
from lbrynet.core import utils from lbrynet.core import utils
from lbrynet.lbrynet_daemon.auth import client from lbrynet.lbrynet_daemon.auth.client import LBRYAPIClient
from lbrynet.lbrynet_daemon.DaemonServer import DaemonServer from lbrynet.lbrynet_daemon.DaemonServer import DaemonServer
@ -24,7 +24,7 @@ def stop():
conf.initialize_settings() conf.initialize_settings()
log_support.configure_console() log_support.configure_console()
try: try:
client.LBRYAPIClient.config().stop() LBRYAPIClient.get_client().call('stop')
except Exception: except Exception:
log.exception('Failed to stop deamon') log.exception('Failed to stop deamon')
else: else:

View file

@ -18,7 +18,7 @@ DOWNLOAD_RUNNING_CODE = 'running'
# TODO: is this ever used? # TODO: is this ever used?
DOWNLOAD_STOPPED_CODE = 'stopped' DOWNLOAD_STOPPED_CODE = 'stopped'
STREAM_STAGES = [ STREAM_STAGES = [
(INITIALIZING_CODE, 'Initializing...'), (INITIALIZING_CODE, 'Initializing'),
(DOWNLOAD_METADATA_CODE, 'Downloading metadata'), (DOWNLOAD_METADATA_CODE, 'Downloading metadata'),
(DOWNLOAD_RUNNING_CODE, 'Started stream'), (DOWNLOAD_RUNNING_CODE, 'Started stream'),
(DOWNLOAD_STOPPED_CODE, 'Paused stream'), (DOWNLOAD_STOPPED_CODE, 'Paused stream'),

View file

@ -23,8 +23,7 @@ class JSONRPCException(Exception):
class AuthAPIClient(object): class AuthAPIClient(object):
def __init__(self, key, timeout, connection, count, service, cookies, auth, url, login_url): def __init__(self, key, timeout, connection, count, cookies, auth, url, login_url):
self.__service_name = service
self.__api_key = key self.__api_key = key
self.__service_url = login_url self.__service_url = login_url
self.__id_count = count self.__id_count = count
@ -35,30 +34,25 @@ class AuthAPIClient(object):
def __getattr__(self, name): def __getattr__(self, name):
if name.startswith('__') and name.endswith('__'): if name.startswith('__') and name.endswith('__'):
# Python internal stuff raise AttributeError # Python internal stuff
raise AttributeError
if self.__service_name is not None:
name = "%s.%s" % (self.__service_name, name)
return AuthAPIClient(key=self.__api_key,
timeout=HTTP_TIMEOUT,
connection=self.__conn,
count=self.__id_count,
service=name,
cookies=self.__cookies,
auth=self.__auth_header,
url=self.__url,
login_url=self.__service_url)
def __call__(self, *args): def f(*args):
return self.call(name, args[0] if args else {})
return f
def call(self, method, params={}):
self.__id_count += 1 self.__id_count += 1
pre_auth_postdata = {'version': '1.1', pre_auth_post_data = {
'method': self.__service_name, 'version': '1.1',
'params': args, 'method': method,
'id': self.__id_count} 'params': [params],
to_auth = get_auth_message(pre_auth_postdata) 'id': self.__id_count
}
to_auth = get_auth_message(pre_auth_post_data)
token = self.__api_key.get_hmac(to_auth) token = self.__api_key.get_hmac(to_auth)
pre_auth_postdata.update({'hmac': token}) pre_auth_post_data.update({'hmac': token})
postdata = json.dumps(pre_auth_postdata) post_data = json.dumps(pre_auth_post_data)
service_url = self.__service_url service_url = self.__service_url
auth_header = self.__auth_header auth_header = self.__auth_header
cookies = self.__cookies cookies = self.__cookies
@ -66,11 +60,13 @@ class AuthAPIClient(object):
req = requests.Request(method='POST', req = requests.Request(method='POST',
url=service_url, url=service_url,
data=postdata, data=post_data,
headers={'Host': host, headers={
'User-Agent': USER_AGENT, 'Host': host,
'Authorization': auth_header, 'User-Agent': USER_AGENT,
'Content-type': 'application/json'}, 'Authorization': auth_header,
'Content-type': 'application/json'
},
cookies=cookies) cookies=cookies)
r = req.prepare() r = req.prepare()
http_response = self.__conn.send(r) http_response = self.__conn.send(r)
@ -101,7 +97,6 @@ class AuthAPIClient(object):
def config(cls, key_name=None, key=None, pw_path=None, def config(cls, key_name=None, key=None, pw_path=None,
timeout=HTTP_TIMEOUT, timeout=HTTP_TIMEOUT,
connection=None, count=0, connection=None, count=0,
service=None,
cookies=None, auth=None, cookies=None, auth=None,
url=None, login_url=None): url=None, login_url=None):
@ -157,21 +152,11 @@ class AuthAPIClient(object):
assert cookies.get(LBRY_SECRET, False), "Missing cookie" assert cookies.get(LBRY_SECRET, False), "Missing cookie"
secret = cookies.get(LBRY_SECRET) secret = cookies.get(LBRY_SECRET)
api_key = APIKey(secret, api_key_name) api_key = APIKey(secret, api_key_name)
return cls(api_key, timeout, conn, id_count, service, cookies, return cls(api_key, timeout, conn, id_count, cookies, auth_header, url, service_url)
auth_header, url, service_url)
class LBRYAPIClient(object): class LBRYAPIClient(object):
@staticmethod @staticmethod
def config(service=None, params=None): def get_client():
if conf.settings.use_auth_http: return AuthAPIClient.config() if conf.settings.use_auth_http else \
if service is None: JSONRPCProxy.from_url(conf.settings.API_CONNECTION_STRING)
return AuthAPIClient.config()
log.error("Try auth")
if params is not None:
return AuthAPIClient.config(service=service)(params)
return AuthAPIClient.config(service=service)()
url = conf.settings.API_CONNECTION_STRING
if service is None:
return JSONRPCProxy.from_url(url)
return JSONRPCProxy.from_url(url).call(service, params)

View file

@ -8,13 +8,15 @@ from twisted.internet import defer
from twisted.python.failure import Failure from twisted.python.failure import Failure
from txjsonrpc import jsonrpclib from txjsonrpc import jsonrpclib
from lbrynet.core.Error import InvalidAuthenticationToken, InvalidHeaderError, SubhandlerError from lbrynet.core.Error import InvalidAuthenticationToken, InvalidHeaderError
from lbrynet import conf from lbrynet import conf
from lbrynet.lbrynet_daemon.auth.util import APIKey, get_auth_message from lbrynet.lbrynet_daemon.auth.util import APIKey, get_auth_message
from lbrynet.lbrynet_daemon.auth.client import LBRY_SECRET from lbrynet.lbrynet_daemon.auth.client import LBRY_SECRET
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
EMPTY_PARAMS = [{}]
def default_decimal(obj): def default_decimal(obj):
if isinstance(obj, Decimal): if isinstance(obj, Decimal):
@ -34,7 +36,6 @@ class JSONRPCException(Exception):
class AuthorizedBase(object): class AuthorizedBase(object):
def __init__(self): def __init__(self):
self.authorized_functions = [] self.authorized_functions = []
self.subhandlers = []
self.callable_methods = {} self.callable_methods = {}
for methodname in dir(self): for methodname in dir(self):
@ -43,21 +44,12 @@ class AuthorizedBase(object):
self.callable_methods.update({methodname.split("jsonrpc_")[1]: method}) self.callable_methods.update({methodname.split("jsonrpc_")[1]: method})
if hasattr(method, '_auth_required'): if hasattr(method, '_auth_required'):
self.authorized_functions.append(methodname.split("jsonrpc_")[1]) self.authorized_functions.append(methodname.split("jsonrpc_")[1])
elif not methodname.startswith("__"):
method = getattr(self, methodname)
if hasattr(method, '_subhandler'):
self.subhandlers.append(method)
@staticmethod @staticmethod
def auth_required(f): def auth_required(f):
f._auth_required = True f._auth_required = True
return f return f
@staticmethod
def subhandler(f):
f._subhandler = True
return f
class AuthJSONRPCServer(AuthorizedBase): class AuthJSONRPCServer(AuthorizedBase):
"""Authorized JSONRPC server used as the base class for the LBRY API """Authorized JSONRPC server used as the base class for the LBRY API
@ -69,12 +61,6 @@ class AuthJSONRPCServer(AuthorizedBase):
@AuthJSONRPCServer.auth_required: this requires the client @AuthJSONRPCServer.auth_required: this requires the client
include a valid hmac authentication token in their request include a valid hmac authentication token in their request
@AuthJSONRPCServer.subhandler: include the tagged method in
the processing of requests, to allow inheriting classes to
modify request handling. Tagged methods will be passed the
request object, and return True when finished to indicate
success
Attributes: Attributes:
allowed_during_startup (list): list of api methods that are allowed_during_startup (list): list of api methods that are
callable before the server has finished startup callable before the server has finished startup
@ -84,8 +70,6 @@ class AuthJSONRPCServer(AuthorizedBase):
authorized_functions (list): list of api methods that require authentication authorized_functions (list): list of api methods that require authentication
subhandlers (list): list of subhandlers
callable_methods (dict): dictionary of api_callable_name: method values callable_methods (dict): dictionary of api_callable_name: method values
""" """
@ -131,6 +115,7 @@ class AuthJSONRPCServer(AuthorizedBase):
if self._initialize_session(session_id): if self._initialize_session(session_id):
def expire_session(): def expire_session():
self._unregister_user_session(session_id) self._unregister_user_session(session_id)
session.startCheckingExpiration() session.startCheckingExpiration()
session.notifyOnExpire(expire_session) session.notifyOnExpire(expire_session)
message = "OK" message = "OK"
@ -138,7 +123,8 @@ class AuthJSONRPCServer(AuthorizedBase):
self._set_headers(request, message, True) self._set_headers(request, message, True)
self._render_message(request, message) self._render_message(request, message)
return server.NOT_DONE_YET return server.NOT_DONE_YET
session.touch() else:
session.touch()
request.content.seek(0, 0) request.content.seek(0, 0)
content = request.content.read() content = request.content.read()
@ -155,12 +141,6 @@ class AuthJSONRPCServer(AuthorizedBase):
token = parsed.pop('hmac', None) token = parsed.pop('hmac', None)
version = self._get_jsonrpc_version(parsed.get('jsonrpc'), id_) version = self._get_jsonrpc_version(parsed.get('jsonrpc'), id_)
try:
self._run_subhandlers(request)
except SubhandlerError as err:
self._render_error(err, request, id_, version)
return server.NOT_DONE_YET
reply_with_next_secret = False reply_with_next_secret = False
if self._use_authentication: if self._use_authentication:
if function_name in self.authorized_functions: if function_name in self.authorized_functions:
@ -182,7 +162,7 @@ class AuthJSONRPCServer(AuthorizedBase):
self._render_error(err, request, id_, version) self._render_error(err, request, id_, version)
return server.NOT_DONE_YET return server.NOT_DONE_YET
if args == [{}]: if args == EMPTY_PARAMS:
d = defer.maybeDeferred(function) d = defer.maybeDeferred(function)
else: else:
d = defer.maybeDeferred(function, *args) d = defer.maybeDeferred(function, *args)
@ -281,6 +261,7 @@ class AuthJSONRPCServer(AuthorizedBase):
return False return False
def _verify_token(self, session_id, message, token): def _verify_token(self, session_id, message, token):
assert token is not None, InvalidAuthenticationToken
to_auth = get_auth_message(message) to_auth = get_auth_message(message)
api_key = self.sessions.get(session_id) api_key = self.sessions.get(session_id)
assert api_key.compare_hmac(to_auth, token), InvalidAuthenticationToken assert api_key.compare_hmac(to_auth, token), InvalidAuthenticationToken
@ -297,18 +278,13 @@ class AuthJSONRPCServer(AuthorizedBase):
version_for_return = jsonrpclib.VERSION_PRE1 version_for_return = jsonrpclib.VERSION_PRE1
return version_for_return return version_for_return
def _run_subhandlers(self, request):
for handler in self.subhandlers:
if not handler(request):
raise SubhandlerError("Subhandler error processing request: %s", request)
def _callback_render(self, result, request, id_, version, auth_required=False): def _callback_render(self, result, request, id_, version, auth_required=False):
result_for_return = result if not isinstance(result, dict) else result['result'] result_for_return = result
if version == jsonrpclib.VERSION_PRE1: if version == jsonrpclib.VERSION_PRE1:
if not isinstance(result, jsonrpclib.Fault): if not isinstance(result, jsonrpclib.Fault):
result_for_return = (result_for_return,) result_for_return = (result_for_return,)
# Convert the result (python) to JSON-RPC
try: try:
encoded_message = jsonrpclib.dumps( encoded_message = jsonrpclib.dumps(
result_for_return, id=id_, version=version, default=default_decimal) result_for_return, id=id_, version=version, default=default_decimal)
@ -318,5 +294,5 @@ class AuthJSONRPCServer(AuthorizedBase):
log.exception("Failed to render API response: %s", result) log.exception("Failed to render API response: %s", result)
self._render_error(err, request, id_, version) self._render_error(err, request, id_, version)
def _render_response(self, result, code): def _render_response(self, result):
return defer.succeed({'result': result, 'code': code}) return defer.succeed(result)

View file

@ -34,7 +34,7 @@ class LBRYURIHandler(object):
except: except:
cmd = r'DIR = "$( cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )"' \ cmd = r'DIR = "$( cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )"' \
r'if [-z "$(pgrep lbrynet-daemon)"]; then' \ r'if [-z "$(pgrep lbrynet-daemon)"]; then' \
r'echo "running lbrynet-daemon..."' \ r'echo "running lbrynet-daemon"' \
r'$DIR / lbrynet - daemon &' \ r'$DIR / lbrynet - daemon &' \
r'sleep 3 # let the daemon load before connecting' \ r'sleep 3 # let the daemon load before connecting' \
r'fi' r'fi'

View file

@ -27,7 +27,7 @@ DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ -z "$(pgrep lbrynet-daemon)" ]; then if [ -z "$(pgrep lbrynet-daemon)" ]; then
echo "running lbrynet-daemon..." echo "running lbrynet-daemon"
$DIR/lbrynet-daemon --no-launch & $DIR/lbrynet-daemon --no-launch &
sleep 3 # let the daemon load before connecting sleep 3 # let the daemon load before connecting
fi fi

View file

@ -11,7 +11,7 @@ from lbrynet import conf
class LBRYURIHandler(object): class LBRYURIHandler(object):
def __init__(self): def __init__(self):
self.started_daemon = False self.started_daemon = False
self.daemon = LBRYAPIClient.config() self.daemon = LBRYAPIClient.get_client()
def handle_osx(self, lbry_name): def handle_osx(self, lbry_name):
self.check_daemon() self.check_daemon()
@ -27,7 +27,7 @@ class LBRYURIHandler(object):
if not self.started_daemon: if not self.started_daemon:
cmd = r'DIR = "$( cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )"' \ cmd = r'DIR = "$( cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )"' \
r'if [-z "$(pgrep lbrynet-daemon)"]; then' \ r'if [-z "$(pgrep lbrynet-daemon)"]; then' \
r'echo "running lbrynet-daemon..."' \ r'echo "running lbrynet-daemon"' \
r'$DIR / lbrynet - daemon &' \ r'$DIR / lbrynet - daemon &' \
r'sleep 3 # let the daemon load before connecting' \ r'sleep 3 # let the daemon load before connecting' \
r'fi' r'fi'
@ -49,7 +49,8 @@ class LBRYURIHandler(object):
def check_daemon(self): def check_daemon(self):
try: try:
self.started_daemon = self.daemon.is_running() status = self.daemon.call('status')
self.started_daemon = status['is_running']
except: except:
self.started_daemon = False self.started_daemon = False

View file

@ -944,7 +944,7 @@ class TestTransfer(TestCase):
self.assertEqual(hashsum.hexdigest(), "4ca2aafb4101c1e42235aad24fbb83be") self.assertEqual(hashsum.hexdigest(), "4ca2aafb4101c1e42235aad24fbb83be")
def delete_lbry_file(): def delete_lbry_file():
logging.debug("deleting the file...") logging.debug("deleting the file")
d = self.lbry_file_manager.delete_lbry_file(downloaders[0]) d = self.lbry_file_manager.delete_lbry_file(downloaders[0])
d.addCallback(lambda _: self.lbry_file_manager.get_count_for_stream_hash(downloaders[0].stream_hash)) d.addCallback(lambda _: self.lbry_file_manager.get_count_for_stream_hash(downloaders[0].stream_hash))
d.addCallback( d.addCallback(