2016-07-25 19:19:19 +02:00
|
|
|
import binascii
|
|
|
|
import logging.handlers
|
2016-06-03 09:45:46 +02:00
|
|
|
import mimetypes
|
2016-02-29 19:25:47 +01:00
|
|
|
import os
|
2016-07-20 17:44:06 +02:00
|
|
|
import re
|
2016-04-07 09:12:09 +02:00
|
|
|
import base58
|
2016-07-25 19:19:19 +02:00
|
|
|
import requests
|
2017-01-02 20:52:24 +01:00
|
|
|
import urllib
|
2016-07-25 19:19:19 +02:00
|
|
|
import simplejson as json
|
2017-01-03 20:13:01 +01:00
|
|
|
import textwrap
|
2017-02-02 16:18:09 +01:00
|
|
|
from requests import exceptions as requests_exceptions
|
2016-07-27 09:54:10 +02:00
|
|
|
from decimal import Decimal
|
2017-02-16 05:38:33 +01:00
|
|
|
import random
|
2016-11-22 21:44:47 +01:00
|
|
|
|
2016-04-21 04:02:52 +02:00
|
|
|
from twisted.web import server
|
2016-08-11 20:41:42 +02:00
|
|
|
from twisted.internet import defer, threads, error, reactor, task
|
2016-04-18 19:21:53 +02:00
|
|
|
from twisted.internet.task import LoopingCall
|
2016-11-30 00:06:16 +01:00
|
|
|
from twisted.python.failure import Failure
|
2016-02-29 19:25:47 +01:00
|
|
|
|
2016-09-29 23:42:31 +02:00
|
|
|
# TODO: importing this when internet is disabled raises a socket.gaierror
|
2017-02-16 19:01:16 +01:00
|
|
|
from lbryum.version import LBRYUM_VERSION
|
|
|
|
from lbrynet import __version__ as LBRYNET_VERSION
|
2017-02-10 16:56:22 +01:00
|
|
|
from lbrynet import conf, analytics
|
2016-11-10 20:26:21 +01:00
|
|
|
from lbrynet.conf import LBRYCRD_WALLET, LBRYUM_WALLET, PTC_WALLET
|
2017-02-10 16:56:22 +01:00
|
|
|
from lbrynet.reflector import reupload
|
|
|
|
from lbrynet.reflector import ServerFactory as reflector_server_factory
|
2016-10-19 06:12:44 +02:00
|
|
|
from lbrynet.metadata.Fee import FeeValidator
|
2017-02-09 22:12:30 +01:00
|
|
|
from lbrynet.metadata.Metadata import verify_name_characters
|
2016-11-30 21:20:45 +01:00
|
|
|
from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileSaverFactory
|
|
|
|
from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileOpenerFactory
|
2016-09-27 20:18:16 +02:00
|
|
|
from lbrynet.lbryfile.client.EncryptedFileOptions import add_lbry_file_to_sd_identifier
|
2017-02-16 05:39:17 +01:00
|
|
|
from lbrynet.lbryfile.StreamDescriptor import save_sd_info
|
2016-10-19 06:12:44 +02:00
|
|
|
from lbrynet.lbryfile.EncryptedFileMetadataManager import DBEncryptedFileMetadataManager
|
2016-11-11 19:42:51 +01:00
|
|
|
from lbrynet.lbryfile.StreamDescriptor import EncryptedFileStreamType
|
|
|
|
from lbrynet.lbryfilemanager.EncryptedFileManager import EncryptedFileManager
|
2016-09-27 20:18:35 +02:00
|
|
|
from lbrynet.lbrynet_daemon.Downloader import GetStream
|
|
|
|
from lbrynet.lbrynet_daemon.Publisher import Publisher
|
|
|
|
from lbrynet.lbrynet_daemon.ExchangeRateManager import ExchangeRateManager
|
2016-09-22 03:36:06 +02:00
|
|
|
from lbrynet.lbrynet_daemon.auth.server import AuthJSONRPCServer
|
2017-02-16 05:39:17 +01:00
|
|
|
from lbrynet.core.PaymentRateManager import OnlyFreePaymentsManager
|
2017-03-08 02:55:44 +01:00
|
|
|
from lbrynet.core import log_support, utils
|
2016-12-10 21:01:29 +01:00
|
|
|
from lbrynet.core import system_info
|
2016-11-30 21:20:45 +01:00
|
|
|
from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier, download_sd_blob
|
2016-10-22 01:12:38 +02:00
|
|
|
from lbrynet.core.Session import Session
|
2017-03-06 23:01:35 +01:00
|
|
|
from lbrynet.core.Wallet import LBRYumWallet, SqliteStorage, ClaimOutpoint
|
2016-11-11 19:42:51 +01:00
|
|
|
from lbrynet.core.looping_call_manager import LoopingCallManager
|
|
|
|
from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory
|
|
|
|
from lbrynet.core.server.ServerProtocol import ServerProtocolFactory
|
2017-02-16 15:12:00 +01:00
|
|
|
from lbrynet.core.Error import InsufficientFundsError, UnknownNameError, NoSuchSDHash
|
2017-02-16 05:39:17 +01:00
|
|
|
from lbrynet.core.Error import NoSuchStreamHash
|
2016-06-07 10:19:51 +02:00
|
|
|
|
2016-07-25 07:40:26 +02:00
|
|
|
log = logging.getLogger(__name__)
|
2016-06-28 20:28:59 +02:00
|
|
|
|
2016-04-18 19:21:53 +02:00
|
|
|
INITIALIZING_CODE = 'initializing'
|
|
|
|
LOADING_DB_CODE = 'loading_db'
|
2017-01-03 20:13:01 +01:00
|
|
|
LOADING_WALLET_CODE = 'loading_wallet'
|
2016-04-18 19:21:53 +02:00
|
|
|
LOADING_FILE_MANAGER_CODE = 'loading_file_manager'
|
|
|
|
LOADING_SERVER_CODE = 'loading_server'
|
|
|
|
STARTED_CODE = 'started'
|
2016-05-11 08:47:33 +02:00
|
|
|
WAITING_FOR_FIRST_RUN_CREDITS = 'waiting_for_credits'
|
2016-04-09 08:09:30 +02:00
|
|
|
STARTUP_STAGES = [
|
2017-01-03 20:13:01 +01:00
|
|
|
(INITIALIZING_CODE, 'Initializing'),
|
|
|
|
(LOADING_DB_CODE, 'Loading databases'),
|
|
|
|
(LOADING_WALLET_CODE, 'Catching up with the blockchain'),
|
|
|
|
(LOADING_FILE_MANAGER_CODE, 'Setting up file manager'),
|
|
|
|
(LOADING_SERVER_CODE, 'Starting lbrynet'),
|
|
|
|
(STARTED_CODE, 'Started lbrynet'),
|
|
|
|
(WAITING_FOR_FIRST_RUN_CREDITS, 'Waiting for first run credits'),
|
|
|
|
]
|
2016-04-09 08:09:30 +02:00
|
|
|
|
2016-12-30 07:12:20 +01:00
|
|
|
# TODO: make this consistent with the stages in Downloader.py
|
2016-04-26 04:35:21 +02:00
|
|
|
DOWNLOAD_METADATA_CODE = 'downloading_metadata'
|
|
|
|
DOWNLOAD_TIMEOUT_CODE = 'timeout'
|
|
|
|
DOWNLOAD_RUNNING_CODE = 'running'
|
|
|
|
DOWNLOAD_STOPPED_CODE = 'stopped'
|
|
|
|
STREAM_STAGES = [
|
2017-01-04 23:10:36 +01:00
|
|
|
(INITIALIZING_CODE, 'Initializing'),
|
2017-01-03 20:13:01 +01:00
|
|
|
(DOWNLOAD_METADATA_CODE, 'Downloading metadata'),
|
|
|
|
(DOWNLOAD_RUNNING_CODE, 'Started %s, got %s/%s blobs, stream status: %s'),
|
|
|
|
(DOWNLOAD_STOPPED_CODE, 'Paused stream'),
|
|
|
|
(DOWNLOAD_TIMEOUT_CODE, 'Stream timed out')
|
|
|
|
]
|
|
|
|
|
|
|
|
CONNECTION_STATUS_CONNECTED = 'connected'
|
|
|
|
CONNECTION_STATUS_NETWORK = 'network_connection'
|
|
|
|
CONNECTION_MESSAGES = {
|
|
|
|
CONNECTION_STATUS_CONNECTED: 'No connection problems detected',
|
|
|
|
CONNECTION_STATUS_NETWORK: "Your internet connection appears to have been interrupted",
|
|
|
|
}
|
2016-04-18 19:21:53 +02:00
|
|
|
|
2016-12-19 19:27:45 +01:00
|
|
|
PENDING_ID = "not set"
|
|
|
|
SHORT_ID_LEN = 20
|
|
|
|
|
2016-10-19 01:09:35 +02:00
|
|
|
|
2017-03-06 23:01:35 +01:00
|
|
|
class IterableContainer(object):
|
|
|
|
def __iter__(self):
|
|
|
|
for attr in dir(self):
|
|
|
|
if not attr.startswith("_"):
|
|
|
|
yield getattr(self, attr)
|
|
|
|
|
|
|
|
def __contains__(self, item):
|
|
|
|
for attr in self:
|
|
|
|
if item == attr:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2016-10-19 01:09:35 +02:00
|
|
|
class Checker:
|
|
|
|
"""The looping calls the daemon runs"""
|
|
|
|
INTERNET_CONNECTION = 'internet_connection_checker'
|
|
|
|
VERSION = 'version_checker'
|
2017-01-03 20:13:01 +01:00
|
|
|
CONNECTION_STATUS = 'connection_status_checker'
|
2016-10-19 01:09:35 +02:00
|
|
|
PENDING_CLAIM = 'pending_claim_checker'
|
|
|
|
|
|
|
|
|
2017-03-06 23:01:35 +01:00
|
|
|
class _FileID(IterableContainer):
|
2016-10-19 01:09:35 +02:00
|
|
|
"""The different ways a file can be identified"""
|
|
|
|
NAME = 'name'
|
|
|
|
SD_HASH = 'sd_hash'
|
|
|
|
FILE_NAME = 'file_name'
|
2017-02-20 01:22:21 +01:00
|
|
|
STREAM_HASH = 'stream_hash'
|
2017-03-06 23:01:35 +01:00
|
|
|
CLAIM_ID = "claim_id"
|
|
|
|
OUTPOINT = "outpoint"
|
|
|
|
ROWID = "rowid"
|
|
|
|
|
|
|
|
|
|
|
|
FileID = _FileID()
|
2016-10-19 01:09:35 +02:00
|
|
|
|
|
|
|
|
2016-02-16 19:39:08 +01:00
|
|
|
# TODO add login credentials in a conf file
|
|
|
|
# TODO alert if your copy of a lbry file is out of date with the name record
|
2016-01-12 00:01:46 +01:00
|
|
|
|
2016-12-19 19:27:45 +01:00
|
|
|
|
2016-10-20 21:52:37 +02:00
|
|
|
class NoValidSearch(Exception):
|
|
|
|
pass
|
|
|
|
|
2016-04-18 19:21:53 +02:00
|
|
|
|
2016-09-29 23:42:31 +02:00
|
|
|
class CheckInternetConnection(object):
|
|
|
|
def __init__(self, daemon):
|
|
|
|
self.daemon = daemon
|
|
|
|
|
|
|
|
def __call__(self):
|
|
|
|
self.daemon.connected_to_internet = utils.check_connection()
|
|
|
|
|
|
|
|
|
2017-02-17 04:25:09 +01:00
|
|
|
class CheckRemoteVersion(object):
|
2017-02-21 16:36:08 +01:00
|
|
|
URL = 'https://api.github.com/repos/lbryio/lbry-electron/releases/latest'
|
2017-02-17 04:25:09 +01:00
|
|
|
def __init__(self):
|
|
|
|
self.version = None
|
2016-09-29 23:42:31 +02:00
|
|
|
|
|
|
|
def __call__(self):
|
2017-02-16 19:01:16 +01:00
|
|
|
d = threads.deferToThread(self._get_lbry_electron_client_version)
|
|
|
|
d.addErrback(self._trap_and_log_error, 'lbry-electron')
|
2017-02-02 16:18:09 +01:00
|
|
|
d.addErrback(log.fail(), 'Failure checking versions on github')
|
|
|
|
|
|
|
|
def _trap_and_log_error(self, err, module_checked):
|
|
|
|
# KeyError is thrown by get_version_from_github
|
|
|
|
# It'd be better to catch the error before trying to parse the response
|
|
|
|
err.trap(requests_exceptions.RequestException, KeyError)
|
2017-02-16 19:01:16 +01:00
|
|
|
log.warning("Failed to check latest %s version from github", module_checked)
|
2016-09-29 23:42:31 +02:00
|
|
|
|
2017-02-16 19:01:16 +01:00
|
|
|
def _get_lbry_electron_client_version(self):
|
2017-02-17 04:25:09 +01:00
|
|
|
# We'll need to ensure the lbry-electron version is in sync
|
2017-02-16 19:01:16 +01:00
|
|
|
# with the lbrynet-daemon version
|
2017-02-17 04:25:09 +01:00
|
|
|
self._set_data_from_github()
|
2017-02-02 16:18:09 +01:00
|
|
|
log.info(
|
|
|
|
"remote lbrynet %s > local lbrynet %s = %s",
|
2017-02-17 04:25:09 +01:00
|
|
|
self.version, LBRYNET_VERSION,
|
|
|
|
utils.version_is_greater_than(self.version, LBRYNET_VERSION)
|
2017-02-02 16:18:09 +01:00
|
|
|
)
|
2016-09-29 23:42:31 +02:00
|
|
|
|
2017-02-17 04:25:09 +01:00
|
|
|
def _set_data_from_github(self):
|
|
|
|
release = self._get_release_data()
|
|
|
|
# githubs documentation claims this should never happen, but we'll check just in case
|
|
|
|
if release['prerelease']:
|
2017-02-21 15:45:12 +01:00
|
|
|
raise Exception('Release {} is a pre-release'.format(release['tag_name']))
|
2017-02-17 04:25:09 +01:00
|
|
|
self.version = self._get_version_from_release(release)
|
|
|
|
|
|
|
|
def _get_release_data(self):
|
|
|
|
response = requests.get(self.URL, timeout=20)
|
|
|
|
release = response.json()
|
|
|
|
return release
|
|
|
|
|
|
|
|
def _get_version_from_release(self, release):
|
|
|
|
"""Return the latest released version from github."""
|
|
|
|
tag = release['tag_name']
|
2017-02-21 16:36:08 +01:00
|
|
|
return get_version_from_tag(tag)
|
2017-02-17 04:25:09 +01:00
|
|
|
|
|
|
|
def is_update_available(self):
|
|
|
|
try:
|
|
|
|
return utils.version_is_greater_than(self.version, LBRYNET_VERSION)
|
|
|
|
except TypeError:
|
|
|
|
return False
|
|
|
|
|
2016-09-29 23:42:31 +02:00
|
|
|
|
2016-10-11 19:50:44 +02:00
|
|
|
class AlwaysSend(object):
|
|
|
|
def __init__(self, value_generator, *args, **kwargs):
|
|
|
|
self.value_generator = value_generator
|
|
|
|
self.args = args
|
|
|
|
self.kwargs = kwargs
|
|
|
|
|
|
|
|
def __call__(self):
|
|
|
|
d = defer.maybeDeferred(self.value_generator, *self.args, **self.kwargs)
|
|
|
|
d.addCallback(lambda v: (True, v))
|
|
|
|
return d
|
|
|
|
|
|
|
|
|
2017-01-20 19:47:53 +01:00
|
|
|
# If an instance has a lot of blobs, this call might get very expensive.
|
|
|
|
# For reflector, with 50k blobs, it definitely has an impact on the first run
|
|
|
|
# But doesn't seem to impact performance after that.
|
2017-01-20 17:54:36 +01:00
|
|
|
@defer.inlineCallbacks
|
2016-10-05 21:45:17 +02:00
|
|
|
def calculate_available_blob_size(blob_manager):
|
2017-01-20 17:54:36 +01:00
|
|
|
blob_hashes = yield blob_manager.get_all_verified_blobs()
|
2017-02-14 20:18:42 +01:00
|
|
|
blobs = yield defer.DeferredList([blob_manager.get_blob(b) for b in blob_hashes])
|
2017-01-20 17:54:36 +01:00
|
|
|
defer.returnValue(sum(b.length for success, b in blobs if success and b.length))
|
2016-09-30 06:35:15 +02:00
|
|
|
|
2016-09-29 23:51:48 +02:00
|
|
|
|
2016-10-07 23:11:43 +02:00
|
|
|
class Daemon(AuthJSONRPCServer):
|
2015-12-06 23:32:17 +01:00
|
|
|
"""
|
2016-03-24 03:27:48 +01:00
|
|
|
LBRYnet daemon, a jsonrpc interface to lbry functions
|
2015-12-06 23:32:17 +01:00
|
|
|
"""
|
2016-04-12 04:28:46 +02:00
|
|
|
|
2017-03-08 16:21:12 +01:00
|
|
|
def __init__(self, root, analytics_manager):
|
2017-01-17 04:23:20 +01:00
|
|
|
AuthJSONRPCServer.__init__(self, conf.settings['use_auth_http'])
|
2016-10-19 06:12:44 +02:00
|
|
|
reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)
|
|
|
|
|
2017-01-09 22:24:47 +01:00
|
|
|
self.allowed_during_startup = [
|
|
|
|
'stop', 'status', 'version',
|
|
|
|
# delete these once they are fully removed:
|
|
|
|
'is_running', 'is_first_run', 'get_time_behind_blockchain', 'daemon_status',
|
|
|
|
'get_start_notice',
|
|
|
|
]
|
2017-02-16 19:01:16 +01:00
|
|
|
last_version = {'last_version': {'lbrynet': LBRYNET_VERSION, 'lbryum': LBRYUM_VERSION}}
|
2016-11-11 19:42:51 +01:00
|
|
|
conf.settings.update(last_version)
|
2017-01-17 04:23:20 +01:00
|
|
|
self.db_dir = conf.settings['data_dir']
|
|
|
|
self.download_directory = conf.settings['download_directory']
|
2016-10-19 06:12:44 +02:00
|
|
|
self.created_data_dir = False
|
|
|
|
if not os.path.exists(self.db_dir):
|
|
|
|
os.mkdir(self.db_dir)
|
|
|
|
self.created_data_dir = True
|
2017-01-17 04:23:20 +01:00
|
|
|
if conf.settings['BLOBFILES_DIR'] == "blobfiles":
|
2016-10-19 06:12:44 +02:00
|
|
|
self.blobfile_dir = os.path.join(self.db_dir, "blobfiles")
|
|
|
|
else:
|
2017-01-17 04:23:20 +01:00
|
|
|
log.info("Using non-default blobfiles directory: %s", conf.settings['BLOBFILES_DIR'])
|
|
|
|
self.blobfile_dir = conf.settings['BLOBFILES_DIR']
|
|
|
|
|
|
|
|
self.run_on_startup = conf.settings['run_on_startup']
|
|
|
|
self.data_rate = conf.settings['data_rate']
|
|
|
|
self.max_key_fee = conf.settings['max_key_fee']
|
|
|
|
self.max_upload = conf.settings['max_upload']
|
|
|
|
self.max_download = conf.settings['max_download']
|
|
|
|
self.search_timeout = conf.settings['search_timeout']
|
|
|
|
self.download_timeout = conf.settings['download_timeout']
|
|
|
|
self.max_search_results = conf.settings['max_search_results']
|
|
|
|
self.run_reflector_server = conf.settings['run_reflector_server']
|
|
|
|
self.wallet_type = conf.settings['wallet']
|
|
|
|
self.delete_blobs_on_remove = conf.settings['delete_blobs_on_remove']
|
|
|
|
self.peer_port = conf.settings['peer_port']
|
|
|
|
self.reflector_port = conf.settings['reflector_port']
|
|
|
|
self.dht_node_port = conf.settings['dht_node_port']
|
|
|
|
self.use_upnp = conf.settings['use_upnp']
|
|
|
|
self.cache_time = conf.settings['cache_time']
|
2016-04-12 04:28:46 +02:00
|
|
|
|
2016-04-12 08:03:57 +02:00
|
|
|
self.startup_status = STARTUP_STAGES[0]
|
2016-04-18 19:21:53 +02:00
|
|
|
self.connected_to_internet = True
|
2017-01-03 20:13:01 +01:00
|
|
|
self.connection_status_code = None
|
2016-11-10 21:49:51 +01:00
|
|
|
self.platform = None
|
2016-04-12 08:03:57 +02:00
|
|
|
self.first_run = None
|
2016-11-11 19:42:51 +01:00
|
|
|
self.log_file = conf.settings.get_log_filename()
|
2016-10-14 08:13:37 +02:00
|
|
|
self.current_db_revision = 2
|
|
|
|
self.db_revision_file = conf.settings.get_db_revision_filename()
|
2016-04-12 04:28:46 +02:00
|
|
|
self.session = None
|
2016-07-20 08:36:55 +02:00
|
|
|
self.uploaded_temp_files = []
|
2017-01-17 04:23:20 +01:00
|
|
|
self._session_id = conf.settings.get_session_id()
|
2016-10-22 01:12:38 +02:00
|
|
|
# TODO: this should probably be passed into the daemon, or
|
|
|
|
# possibly have the entire log upload functionality taken out
|
|
|
|
# of the daemon, but I don't want to deal with that now
|
2016-10-27 17:34:48 +02:00
|
|
|
|
2016-11-22 21:44:47 +01:00
|
|
|
self.analytics_manager = analytics_manager
|
2017-02-02 16:23:17 +01:00
|
|
|
self.lbryid = utils.generate_id()
|
2016-09-16 06:14:25 +02:00
|
|
|
|
2016-05-14 23:36:30 +02:00
|
|
|
self.wallet_user = None
|
|
|
|
self.wallet_password = None
|
2016-10-19 06:12:44 +02:00
|
|
|
self.query_handlers = {}
|
|
|
|
self.waiting_on = {}
|
|
|
|
self.streams = {}
|
|
|
|
self.pending_claims = {}
|
|
|
|
self.name_cache = {}
|
|
|
|
self.exchange_rate_manager = ExchangeRateManager()
|
2017-02-17 04:25:09 +01:00
|
|
|
self._remote_version = CheckRemoteVersion()
|
2016-10-19 01:09:35 +02:00
|
|
|
calls = {
|
|
|
|
Checker.INTERNET_CONNECTION: LoopingCall(CheckInternetConnection(self)),
|
2017-02-17 04:25:09 +01:00
|
|
|
Checker.VERSION: LoopingCall(self._remote_version),
|
2017-01-03 20:13:01 +01:00
|
|
|
Checker.CONNECTION_STATUS: LoopingCall(self._update_connection_status),
|
2016-10-19 01:09:35 +02:00
|
|
|
Checker.PENDING_CLAIM: LoopingCall(self._check_pending_claims),
|
|
|
|
}
|
|
|
|
self.looping_call_manager = LoopingCallManager(calls)
|
2016-05-14 23:36:30 +02:00
|
|
|
self.sd_identifier = StreamDescriptorIdentifier()
|
2017-02-06 19:15:50 +01:00
|
|
|
self.stream_info_manager = DBEncryptedFileMetadataManager(self.db_dir)
|
2016-05-14 23:36:30 +02:00
|
|
|
self.lbry_file_manager = None
|
|
|
|
|
2016-12-28 18:20:04 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-01-03 17:44:29 +01:00
|
|
|
def setup(self, launch_ui):
|
2016-12-18 02:01:06 +01:00
|
|
|
self._modify_loggly_formatter()
|
|
|
|
|
2017-03-08 16:21:12 +01:00
|
|
|
@defer.inlineCallbacks
|
2016-04-07 09:12:09 +02:00
|
|
|
def _announce_startup():
|
2016-04-18 01:54:04 +02:00
|
|
|
def _announce():
|
|
|
|
self.announced_startup = True
|
|
|
|
self.startup_status = STARTUP_STAGES[5]
|
2016-07-16 08:15:58 +02:00
|
|
|
log.info("Started lbrynet-daemon")
|
2017-02-06 00:07:46 +01:00
|
|
|
log.info("%i blobs in manager", len(self.session.blob_manager.blobs))
|
2016-05-30 21:49:25 +02:00
|
|
|
|
2017-03-08 16:21:12 +01:00
|
|
|
yield self.session.blob_manager.get_all_verified_blobs()
|
|
|
|
yield _announce()
|
2016-01-11 21:52:38 +01:00
|
|
|
|
2016-07-16 08:15:58 +02:00
|
|
|
log.info("Starting lbrynet-daemon")
|
2016-02-25 23:17:07 +01:00
|
|
|
|
2016-10-19 01:09:35 +02:00
|
|
|
self.looping_call_manager.start(Checker.INTERNET_CONNECTION, 3600)
|
2017-02-02 16:18:09 +01:00
|
|
|
self.looping_call_manager.start(Checker.VERSION, 1800)
|
|
|
|
self.looping_call_manager.start(Checker.CONNECTION_STATUS, 30)
|
2016-07-28 11:30:13 +02:00
|
|
|
self.exchange_rate_manager.start()
|
|
|
|
|
2016-12-28 18:20:04 +01:00
|
|
|
yield self._initial_setup()
|
|
|
|
yield threads.deferToThread(self._setup_data_directory)
|
|
|
|
yield self._check_db_migration()
|
|
|
|
yield self._load_caches()
|
|
|
|
yield self._get_session()
|
|
|
|
yield self._get_analytics()
|
|
|
|
yield add_lbry_file_to_sd_identifier(self.sd_identifier)
|
|
|
|
yield self._setup_stream_identifier()
|
|
|
|
yield self._setup_lbry_file_manager()
|
|
|
|
yield self._setup_query_handlers()
|
|
|
|
yield self._setup_server()
|
2017-01-12 18:51:44 +01:00
|
|
|
log.info("Starting balance: " + str(self.session.wallet.get_balance()))
|
2016-12-28 18:20:04 +01:00
|
|
|
yield _announce_startup()
|
2016-09-28 18:07:25 +02:00
|
|
|
|
2016-05-30 21:49:25 +02:00
|
|
|
def _get_platform(self):
|
2016-11-10 21:49:51 +01:00
|
|
|
if self.platform is None:
|
2016-12-10 21:01:29 +01:00
|
|
|
self.platform = system_info.get_platform()
|
2016-11-10 21:49:51 +01:00
|
|
|
return self.platform
|
2016-05-30 21:49:25 +02:00
|
|
|
|
2016-03-24 03:27:48 +01:00
|
|
|
def _initial_setup(self):
|
2016-04-07 09:12:09 +02:00
|
|
|
def _log_platform():
|
2016-07-20 19:00:34 +02:00
|
|
|
log.info("Platform: %s", json.dumps(self._get_platform()))
|
2016-04-07 09:12:09 +02:00
|
|
|
return defer.succeed(None)
|
|
|
|
|
|
|
|
d = _log_platform()
|
|
|
|
return d
|
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
def _load_caches(self):
|
2016-12-19 19:27:45 +01:00
|
|
|
name_cache_filename = os.path.join(self.db_dir, "stream_info_cache.json")
|
|
|
|
|
|
|
|
if os.path.isfile(name_cache_filename):
|
|
|
|
with open(name_cache_filename, "r") as name_cache:
|
|
|
|
self.name_cache = json.loads(name_cache.read())
|
2016-10-19 06:12:44 +02:00
|
|
|
log.info("Loaded claim info cache")
|
|
|
|
|
2016-04-18 19:21:53 +02:00
|
|
|
def _check_network_connection(self):
|
2016-10-18 03:00:24 +02:00
|
|
|
self.connected_to_internet = utils.check_connection()
|
2016-01-26 02:28:05 +01:00
|
|
|
|
2016-04-22 08:45:05 +02:00
|
|
|
def _check_lbrynet_connection(self):
|
|
|
|
def _log_success():
|
2016-07-16 08:15:58 +02:00
|
|
|
log.info("lbrynet connectivity test passed")
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2016-04-22 08:45:05 +02:00
|
|
|
def _log_failure():
|
2016-07-16 08:15:58 +02:00
|
|
|
log.info("lbrynet connectivity test failed")
|
2016-04-22 08:45:05 +02:00
|
|
|
|
2016-11-30 21:20:45 +01:00
|
|
|
wonderfullife_sh = ("6f3af0fa3924be98a54766aa2715d22c6c1509c3f7fa32566df4899"
|
|
|
|
"a41f3530a9f97b2ecb817fa1dcbf1b30553aefaa7")
|
2016-04-22 08:45:05 +02:00
|
|
|
d = download_sd_blob(self.session, wonderfullife_sh, self.session.base_payment_rate_manager)
|
|
|
|
d.addCallbacks(lambda _: _log_success, lambda _: _log_failure)
|
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
def _update_connection_status(self):
|
|
|
|
self.connection_status_code = CONNECTION_STATUS_CONNECTED
|
|
|
|
|
2016-04-18 19:21:53 +02:00
|
|
|
if not self.connected_to_internet:
|
2017-01-03 20:13:01 +01:00
|
|
|
self.connection_status_code = CONNECTION_STATUS_NETWORK
|
2016-04-18 19:21:53 +02:00
|
|
|
|
2016-11-28 20:23:10 +01:00
|
|
|
# claim_out is dictionary containing 'txid' and 'nout'
|
2017-02-09 22:12:30 +01:00
|
|
|
def _add_to_pending_claims(self, claim_out, name):
|
2016-10-14 08:13:37 +02:00
|
|
|
txid = claim_out['txid']
|
2016-12-14 00:08:29 +01:00
|
|
|
nout = claim_out['nout']
|
2016-10-14 08:13:37 +02:00
|
|
|
log.info("Adding lbry://%s to pending claims, txid %s nout %d" % (name, txid, nout))
|
2016-11-28 20:23:10 +01:00
|
|
|
self.pending_claims[name] = (txid, nout)
|
2016-10-14 08:13:37 +02:00
|
|
|
return claim_out
|
2016-07-27 09:00:44 +02:00
|
|
|
|
|
|
|
def _check_pending_claims(self):
|
2016-07-28 18:43:47 +02:00
|
|
|
# TODO: this was blatantly copied from jsonrpc_start_lbry_file. Be DRY.
|
|
|
|
def _start_file(f):
|
|
|
|
d = self.lbry_file_manager.toggle_lbry_file_running(f)
|
|
|
|
return defer.succeed("Started LBRY file")
|
|
|
|
|
|
|
|
def _get_and_start_file(name):
|
2016-11-30 21:20:45 +01:00
|
|
|
def start_stopped_file(l):
|
|
|
|
if l.stopped:
|
|
|
|
return _start_file(l)
|
|
|
|
else:
|
|
|
|
return "LBRY file was already running"
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2016-07-27 09:00:44 +02:00
|
|
|
d = defer.succeed(self.pending_claims.pop(name))
|
2016-10-19 01:09:35 +02:00
|
|
|
d.addCallback(lambda _: self._get_lbry_file(FileID.NAME, name, return_json=False))
|
2016-11-30 21:20:45 +01:00
|
|
|
d.addCallback(start_stopped_file)
|
2016-07-27 09:00:44 +02:00
|
|
|
|
2016-07-28 19:16:33 +02:00
|
|
|
def re_add_to_pending_claims(name):
|
2016-10-14 08:13:37 +02:00
|
|
|
log.warning("Re-add %s to pending claims", name)
|
|
|
|
txid, nout = self.pending_claims.pop(name)
|
2017-01-03 20:13:01 +01:00
|
|
|
claim_out = {'txid': txid, 'nout': nout}
|
2017-02-09 22:12:30 +01:00
|
|
|
self._add_to_pending_claims(claim_out, name)
|
2016-07-28 19:16:33 +02:00
|
|
|
|
2016-07-27 20:12:20 +02:00
|
|
|
def _process_lbry_file(name, lbry_file):
|
2016-09-27 20:18:16 +02:00
|
|
|
# lbry_file is an instance of ManagedEncryptedFileDownloader or None
|
2016-07-28 18:43:47 +02:00
|
|
|
# TODO: check for sd_hash in addition to txid
|
2016-07-27 20:12:20 +02:00
|
|
|
ready_to_start = (
|
2016-07-27 20:59:26 +02:00
|
|
|
lbry_file and
|
2016-11-28 20:23:10 +01:00
|
|
|
self.pending_claims[name] == (lbry_file.txid, lbry_file.nout)
|
2016-07-27 20:12:20 +02:00
|
|
|
)
|
|
|
|
if ready_to_start:
|
2016-07-28 19:16:33 +02:00
|
|
|
_get_and_start_file(name)
|
2016-07-27 20:12:20 +02:00
|
|
|
else:
|
|
|
|
re_add_to_pending_claims(name)
|
|
|
|
|
2016-07-27 09:00:44 +02:00
|
|
|
for name in self.pending_claims:
|
|
|
|
log.info("Checking if new claim for lbry://%s is confirmed" % name)
|
|
|
|
d = self._resolve_name(name, force_refresh=True)
|
2017-03-08 17:53:22 +01:00
|
|
|
d.addCallback(lambda _: self._get_lbry_file(FileID.NAME, name, return_json=False))
|
2016-07-27 20:12:20 +02:00
|
|
|
d.addCallbacks(
|
|
|
|
lambda lbry_file: _process_lbry_file(name, lbry_file),
|
|
|
|
lambda _: re_add_to_pending_claims(name)
|
|
|
|
)
|
2016-07-27 09:00:44 +02:00
|
|
|
|
2016-04-18 19:21:53 +02:00
|
|
|
def _start_server(self):
|
2016-01-26 02:28:05 +01:00
|
|
|
if self.peer_port is not None:
|
|
|
|
server_factory = ServerProtocolFactory(self.session.rate_limiter,
|
|
|
|
self.query_handlers,
|
|
|
|
self.session.peer_manager)
|
2016-08-09 18:07:26 +02:00
|
|
|
|
2016-01-26 02:28:05 +01:00
|
|
|
try:
|
|
|
|
self.lbry_server_port = reactor.listenTCP(self.peer_port, server_factory)
|
|
|
|
except error.CannotListenError as e:
|
|
|
|
import traceback
|
|
|
|
log.error("Couldn't bind to port %d. %s", self.peer_port, traceback.format_exc())
|
|
|
|
raise ValueError("%s lbrynet may already be running on your computer.", str(e))
|
|
|
|
return defer.succeed(True)
|
|
|
|
|
2016-08-09 18:07:26 +02:00
|
|
|
def _start_reflector(self):
|
2016-08-09 18:18:46 +02:00
|
|
|
if self.run_reflector_server:
|
2016-08-11 07:11:18 +02:00
|
|
|
log.info("Starting reflector server")
|
2016-08-09 18:18:46 +02:00
|
|
|
if self.reflector_port is not None:
|
2017-02-10 16:56:22 +01:00
|
|
|
reflector_factory = reflector_server_factory(
|
2016-08-10 14:44:41 +02:00
|
|
|
self.session.peer_manager,
|
|
|
|
self.session.blob_manager
|
|
|
|
)
|
2016-08-09 18:18:46 +02:00
|
|
|
try:
|
2017-02-10 16:56:22 +01:00
|
|
|
self.reflector_server_port = reactor.listenTCP(self.reflector_port,
|
|
|
|
reflector_factory)
|
2016-08-11 02:04:03 +02:00
|
|
|
log.info('Started reflector on port %s', self.reflector_port)
|
2016-08-09 18:18:46 +02:00
|
|
|
except error.CannotListenError as e:
|
2016-08-10 14:44:41 +02:00
|
|
|
log.exception("Couldn't bind reflector to port %d", self.reflector_port)
|
2016-11-30 21:20:45 +01:00
|
|
|
raise ValueError(
|
|
|
|
"{} lbrynet may already be running on your computer.".format(e))
|
2016-08-09 18:07:26 +02:00
|
|
|
return defer.succeed(True)
|
|
|
|
|
|
|
|
def _stop_reflector(self):
|
2016-08-09 18:18:46 +02:00
|
|
|
if self.run_reflector_server:
|
2016-08-10 22:51:46 +02:00
|
|
|
log.info("Stopping reflector server")
|
2016-08-09 18:18:46 +02:00
|
|
|
try:
|
|
|
|
if self.reflector_server_port is not None:
|
|
|
|
self.reflector_server_port, p = None, self.reflector_server_port
|
|
|
|
return defer.maybeDeferred(p.stopListening)
|
|
|
|
except AttributeError:
|
2016-08-09 18:07:26 +02:00
|
|
|
return defer.succeed(True)
|
2016-08-09 18:18:46 +02:00
|
|
|
return defer.succeed(True)
|
2016-08-09 18:07:26 +02:00
|
|
|
|
2016-11-10 21:49:51 +01:00
|
|
|
def _stop_file_manager(self):
|
|
|
|
if self.lbry_file_manager:
|
|
|
|
self.lbry_file_manager.stop()
|
|
|
|
return defer.succeed(True)
|
|
|
|
|
2016-01-26 02:28:05 +01:00
|
|
|
def _stop_server(self):
|
2016-05-30 21:49:25 +02:00
|
|
|
try:
|
|
|
|
if self.lbry_server_port is not None:
|
2017-02-02 05:40:03 +01:00
|
|
|
self.lbry_server_port, old_port = None, self.lbry_server_port
|
|
|
|
log.info('Stop listening to %s', old_port)
|
|
|
|
return defer.maybeDeferred(old_port.stopListening)
|
2016-05-30 21:49:25 +02:00
|
|
|
else:
|
|
|
|
return defer.succeed(True)
|
|
|
|
except AttributeError:
|
2016-01-26 02:28:05 +01:00
|
|
|
return defer.succeed(True)
|
|
|
|
|
|
|
|
def _setup_server(self):
|
2016-04-12 04:28:46 +02:00
|
|
|
self.startup_status = STARTUP_STAGES[4]
|
2016-12-18 02:01:06 +01:00
|
|
|
d = self._start_server()
|
|
|
|
d.addCallback(lambda _: self._start_reflector())
|
|
|
|
return d
|
2016-01-26 02:28:05 +01:00
|
|
|
|
|
|
|
def _setup_query_handlers(self):
|
|
|
|
handlers = [
|
2016-10-18 16:40:13 +02:00
|
|
|
BlobRequestHandlerFactory(
|
|
|
|
self.session.blob_manager,
|
|
|
|
self.session.wallet,
|
|
|
|
self.session.payment_rate_manager,
|
|
|
|
self.analytics_manager.track
|
|
|
|
),
|
2016-01-26 02:28:05 +01:00
|
|
|
self.session.wallet.get_wallet_info_query_handler_factory(),
|
|
|
|
]
|
2016-12-18 02:01:06 +01:00
|
|
|
return self._add_query_handlers(handlers)
|
2016-01-26 02:28:05 +01:00
|
|
|
|
|
|
|
def _add_query_handlers(self, query_handlers):
|
|
|
|
for handler in query_handlers:
|
2016-10-22 01:12:38 +02:00
|
|
|
query_id = handler.get_primary_query_identifier()
|
2016-12-18 02:01:06 +01:00
|
|
|
self.query_handlers[query_id] = handler
|
|
|
|
return defer.succeed(None)
|
2016-01-26 02:28:05 +01:00
|
|
|
|
2016-07-20 08:36:55 +02:00
|
|
|
def _clean_up_temp_files(self):
|
|
|
|
for path in self.uploaded_temp_files:
|
|
|
|
try:
|
2016-11-04 19:15:27 +01:00
|
|
|
log.debug('Removing tmp file: %s', path)
|
2016-07-20 08:36:55 +02:00
|
|
|
os.remove(path)
|
|
|
|
except OSError:
|
|
|
|
pass
|
|
|
|
|
2016-01-11 21:52:38 +01:00
|
|
|
def _shutdown(self):
|
2016-03-24 03:27:48 +01:00
|
|
|
log.info("Closing lbrynet session")
|
2016-04-18 01:54:04 +02:00
|
|
|
log.info("Status at time of shutdown: " + self.startup_status[0])
|
2016-09-29 23:42:31 +02:00
|
|
|
self.looping_call_manager.shutdown()
|
2016-10-25 23:48:15 +02:00
|
|
|
if self.analytics_manager:
|
|
|
|
self.analytics_manager.shutdown()
|
2016-04-18 01:54:04 +02:00
|
|
|
|
2016-07-20 08:36:55 +02:00
|
|
|
self._clean_up_temp_files()
|
|
|
|
|
2017-03-08 16:21:12 +01:00
|
|
|
d = self._stop_server()
|
2016-12-10 20:42:57 +01:00
|
|
|
d.addErrback(log.fail(), 'Failure while shutting down')
|
2016-08-09 18:07:26 +02:00
|
|
|
d.addCallback(lambda _: self._stop_reflector())
|
2016-12-10 20:42:57 +01:00
|
|
|
d.addErrback(log.fail(), 'Failure while shutting down')
|
2016-11-10 21:49:51 +01:00
|
|
|
d.addCallback(lambda _: self._stop_file_manager())
|
2016-12-10 20:42:57 +01:00
|
|
|
d.addErrback(log.fail(), 'Failure while shutting down')
|
2016-01-11 21:52:38 +01:00
|
|
|
if self.session is not None:
|
2016-01-26 02:28:05 +01:00
|
|
|
d.addCallback(lambda _: self.session.shut_down())
|
2016-12-10 20:42:57 +01:00
|
|
|
d.addErrback(log.fail(), 'Failure while shutting down')
|
2016-01-11 21:52:38 +01:00
|
|
|
return d
|
|
|
|
|
2016-03-24 03:27:48 +01:00
|
|
|
def _update_settings(self, settings):
|
2016-10-19 06:12:44 +02:00
|
|
|
setting_types = {
|
|
|
|
'run_on_startup': bool,
|
|
|
|
'data_rate': float,
|
|
|
|
'max_key_fee': float,
|
|
|
|
'download_directory': str,
|
|
|
|
'max_upload': float,
|
|
|
|
'max_download': float,
|
|
|
|
'download_timeout': int,
|
|
|
|
'search_timeout': float,
|
|
|
|
'cache_time': int
|
|
|
|
}
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2016-11-30 21:20:45 +01:00
|
|
|
def can_update_key(settings, key, setting_type):
|
|
|
|
return (
|
|
|
|
isinstance(settings[key], setting_type) or
|
|
|
|
(
|
|
|
|
key == "max_key_fee" and
|
|
|
|
isinstance(FeeValidator(settings[key]).amount, setting_type)
|
|
|
|
)
|
|
|
|
)
|
2016-04-22 08:45:05 +02:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
for key, setting_type in setting_types.iteritems():
|
|
|
|
if key in settings:
|
2016-11-30 21:20:45 +01:00
|
|
|
if can_update_key(settings, key, setting_type):
|
2017-01-17 18:29:09 +01:00
|
|
|
conf.settings.update({key: settings[key]},
|
|
|
|
data_types=(conf.TYPE_RUNTIME, conf.TYPE_PERSISTED))
|
2016-10-19 06:12:44 +02:00
|
|
|
else:
|
|
|
|
try:
|
|
|
|
converted = setting_type(settings[key])
|
2017-01-17 18:29:09 +01:00
|
|
|
conf.settings.update({key: converted},
|
|
|
|
data_types=(conf.TYPE_RUNTIME, conf.TYPE_PERSISTED))
|
2016-10-19 06:12:44 +02:00
|
|
|
except Exception as err:
|
|
|
|
log.warning(err.message)
|
|
|
|
log.warning("error converting setting '%s' to type %s", key, setting_type)
|
2017-01-17 04:23:20 +01:00
|
|
|
conf.settings.save_conf_file_settings()
|
|
|
|
|
|
|
|
self.run_on_startup = conf.settings['run_on_startup']
|
|
|
|
self.data_rate = conf.settings['data_rate']
|
|
|
|
self.max_key_fee = conf.settings['max_key_fee']
|
|
|
|
self.download_directory = conf.settings['download_directory']
|
|
|
|
self.max_upload = conf.settings['max_upload']
|
|
|
|
self.max_download = conf.settings['max_download']
|
|
|
|
self.download_timeout = conf.settings['download_timeout']
|
|
|
|
self.search_timeout = conf.settings['search_timeout']
|
|
|
|
self.cache_time = conf.settings['cache_time']
|
2016-03-24 03:27:48 +01:00
|
|
|
|
|
|
|
return defer.succeed(True)
|
2016-01-07 16:24:55 +01:00
|
|
|
|
2016-11-28 20:23:10 +01:00
|
|
|
def _write_db_revision_file(self, version_num):
|
2016-10-14 08:13:37 +02:00
|
|
|
with open(self.db_revision_file, mode='w') as db_revision:
|
|
|
|
db_revision.write(str(version_num))
|
|
|
|
|
2015-12-14 16:22:52 +01:00
|
|
|
def _setup_data_directory(self):
|
2016-10-14 08:13:37 +02:00
|
|
|
old_revision = 1
|
2016-04-09 08:09:30 +02:00
|
|
|
self.startup_status = STARTUP_STAGES[1]
|
2017-01-04 23:10:36 +01:00
|
|
|
log.info("Loading databases")
|
2015-12-14 16:22:52 +01:00
|
|
|
if self.created_data_dir:
|
2016-10-14 08:13:37 +02:00
|
|
|
self._write_db_revision_file(self.current_db_revision)
|
|
|
|
log.debug("Created the db revision file: %s", self.db_revision_file)
|
2015-12-14 16:22:52 +01:00
|
|
|
if not os.path.exists(self.blobfile_dir):
|
|
|
|
os.mkdir(self.blobfile_dir)
|
|
|
|
log.debug("Created the blobfile directory: %s", str(self.blobfile_dir))
|
2016-11-28 20:23:10 +01:00
|
|
|
if not os.path.exists(self.db_revision_file):
|
2016-10-14 08:13:37 +02:00
|
|
|
log.warning("db_revision file not found. Creating it")
|
|
|
|
self._write_db_revision_file(old_revision)
|
2015-12-14 16:22:52 +01:00
|
|
|
|
|
|
|
def _check_db_migration(self):
|
2016-09-01 02:20:07 +02:00
|
|
|
old_revision = 1
|
2016-10-14 08:13:37 +02:00
|
|
|
if os.path.exists(self.db_revision_file):
|
|
|
|
old_revision = int(open(self.db_revision_file).read().strip())
|
|
|
|
|
2016-10-25 23:49:08 +02:00
|
|
|
if old_revision > self.current_db_revision:
|
2016-11-30 21:20:45 +01:00
|
|
|
raise Exception('This version of lbrynet is not compatible with the database')
|
2016-10-14 08:13:37 +02:00
|
|
|
|
|
|
|
def update_version_file_and_print_success():
|
|
|
|
self._write_db_revision_file(self.current_db_revision)
|
|
|
|
log.info("Finished upgrading the databases.")
|
|
|
|
|
2015-12-14 16:22:52 +01:00
|
|
|
if old_revision < self.current_db_revision:
|
|
|
|
from lbrynet.db_migrator import dbmigrator
|
2017-01-04 23:10:36 +01:00
|
|
|
log.info("Upgrading your databases")
|
2016-11-30 21:20:45 +01:00
|
|
|
d = threads.deferToThread(
|
|
|
|
dbmigrator.migrate_db, self.db_dir, old_revision, self.current_db_revision)
|
2016-10-14 08:13:37 +02:00
|
|
|
d.addCallback(lambda _: update_version_file_and_print_success())
|
2015-12-14 16:22:52 +01:00
|
|
|
return d
|
|
|
|
return defer.succeed(True)
|
|
|
|
|
2016-08-08 22:02:36 +02:00
|
|
|
def _modify_loggly_formatter(self):
|
|
|
|
log_support.configure_loggly_handler(
|
2017-02-02 16:23:17 +01:00
|
|
|
installation_id=conf.settings.installation_id,
|
2016-07-20 19:00:34 +02:00
|
|
|
session_id=self._session_id
|
2016-08-08 22:02:36 +02:00
|
|
|
)
|
|
|
|
|
2017-02-14 17:27:16 +01:00
|
|
|
@defer.inlineCallbacks
|
2015-12-06 23:32:17 +01:00
|
|
|
def _setup_lbry_file_manager(self):
|
2017-02-14 17:27:16 +01:00
|
|
|
log.info('Starting to setup up file manager')
|
2016-04-12 04:28:46 +02:00
|
|
|
self.startup_status = STARTUP_STAGES[3]
|
2017-02-14 17:27:16 +01:00
|
|
|
yield self.stream_info_manager.setup()
|
|
|
|
self.lbry_file_manager = EncryptedFileManager(
|
|
|
|
self.session,
|
|
|
|
self.stream_info_manager,
|
|
|
|
self.sd_identifier,
|
|
|
|
download_directory=self.download_directory
|
|
|
|
)
|
|
|
|
yield self.lbry_file_manager.setup()
|
|
|
|
log.info('Done setting up file manager')
|
2015-12-06 23:32:17 +01:00
|
|
|
|
2016-10-05 20:51:26 +02:00
|
|
|
def _get_analytics(self):
|
2016-11-10 21:49:51 +01:00
|
|
|
if not self.analytics_manager.is_started:
|
|
|
|
self.analytics_manager.start()
|
|
|
|
self.analytics_manager.register_repeating_metric(
|
|
|
|
analytics.BLOB_BYTES_AVAILABLE,
|
|
|
|
AlwaysSend(calculate_available_blob_size, self.session.blob_manager),
|
|
|
|
frequency=300
|
|
|
|
)
|
2016-10-05 20:51:26 +02:00
|
|
|
|
2015-12-06 23:32:17 +01:00
|
|
|
def _get_session(self):
|
|
|
|
def get_wallet():
|
2016-11-10 20:26:21 +01:00
|
|
|
if self.wallet_type == LBRYCRD_WALLET:
|
2016-12-01 17:59:36 +01:00
|
|
|
raise ValueError('LBRYcrd Wallet is no longer supported')
|
2016-11-10 20:26:21 +01:00
|
|
|
elif self.wallet_type == LBRYUM_WALLET:
|
2016-07-09 19:31:07 +02:00
|
|
|
log.info("Using lbryum wallet")
|
2016-11-20 01:29:58 +01:00
|
|
|
config = {'auto_connect': True}
|
2017-01-17 04:23:20 +01:00
|
|
|
if conf.settings['lbryum_wallet_dir']:
|
|
|
|
config['lbryum_path'] = conf.settings['lbryum_wallet_dir']
|
2016-12-01 06:28:25 +01:00
|
|
|
storage = SqliteStorage(self.db_dir)
|
|
|
|
wallet = LBRYumWallet(storage, config)
|
|
|
|
return defer.succeed(wallet)
|
2016-11-10 20:26:21 +01:00
|
|
|
elif self.wallet_type == PTC_WALLET:
|
2016-02-25 23:17:07 +01:00
|
|
|
log.info("Using PTC wallet")
|
2016-12-18 02:03:35 +01:00
|
|
|
from lbrynet.core.PTCWallet import PTCWallet
|
2016-12-18 02:01:06 +01:00
|
|
|
return defer.succeed(PTCWallet(self.db_dir))
|
2016-02-23 04:32:07 +01:00
|
|
|
else:
|
2016-10-04 20:59:04 +02:00
|
|
|
raise ValueError('Wallet Type {} is not valid'.format(self.wallet_type))
|
2015-12-06 23:32:17 +01:00
|
|
|
|
2016-12-18 02:01:06 +01:00
|
|
|
d = get_wallet()
|
2015-12-06 23:32:17 +01:00
|
|
|
|
2016-12-18 02:01:06 +01:00
|
|
|
def create_session(wallet):
|
2016-11-30 21:20:45 +01:00
|
|
|
self.session = Session(
|
2017-01-17 04:23:20 +01:00
|
|
|
conf.settings['data_rate'],
|
2016-11-30 21:20:45 +01:00
|
|
|
db_dir=self.db_dir,
|
|
|
|
lbryid=self.lbryid,
|
|
|
|
blob_dir=self.blobfile_dir,
|
|
|
|
dht_node_port=self.dht_node_port,
|
2017-01-17 04:23:20 +01:00
|
|
|
known_dht_nodes=conf.settings['known_dht_nodes'],
|
2016-11-30 21:20:45 +01:00
|
|
|
peer_port=self.peer_port,
|
|
|
|
use_upnp=self.use_upnp,
|
2016-12-18 02:01:06 +01:00
|
|
|
wallet=wallet,
|
2017-01-17 04:23:20 +01:00
|
|
|
is_generous=conf.settings['is_generous_host']
|
2016-11-30 21:20:45 +01:00
|
|
|
)
|
2016-04-12 04:28:46 +02:00
|
|
|
self.startup_status = STARTUP_STAGES[2]
|
2015-12-06 23:32:17 +01:00
|
|
|
|
2016-12-18 02:01:06 +01:00
|
|
|
d.addCallback(create_session)
|
|
|
|
d.addCallback(lambda _: self.session.setup())
|
|
|
|
return d
|
2015-12-06 23:32:17 +01:00
|
|
|
|
|
|
|
def _setup_stream_identifier(self):
|
2016-11-30 21:20:45 +01:00
|
|
|
file_saver_factory = EncryptedFileSaverFactory(
|
|
|
|
self.session.peer_finder,
|
|
|
|
self.session.rate_limiter,
|
|
|
|
self.session.blob_manager,
|
|
|
|
self.stream_info_manager,
|
|
|
|
self.session.wallet,
|
|
|
|
self.download_directory
|
|
|
|
)
|
|
|
|
self.sd_identifier.add_stream_downloader_factory(
|
|
|
|
EncryptedFileStreamType, file_saver_factory)
|
|
|
|
file_opener_factory = EncryptedFileOpenerFactory(
|
|
|
|
self.session.peer_finder,
|
|
|
|
self.session.rate_limiter,
|
|
|
|
self.session.blob_manager,
|
|
|
|
self.stream_info_manager,
|
|
|
|
self.session.wallet
|
|
|
|
)
|
|
|
|
self.sd_identifier.add_stream_downloader_factory(
|
|
|
|
EncryptedFileStreamType, file_opener_factory)
|
2015-12-06 23:32:17 +01:00
|
|
|
return defer.succeed(None)
|
|
|
|
|
2017-02-16 05:39:17 +01:00
|
|
|
def _download_sd_blob(self, sd_blob_hash, rate_manager=None, timeout=None):
|
|
|
|
"""
|
|
|
|
Download a sd blob and register it with the stream info manager
|
|
|
|
Use this when downloading a sd blob as part of a stream download
|
|
|
|
|
|
|
|
:param sd_blob_hash (str): sd blob hash
|
|
|
|
:param rate_manager (PaymentRateManager), optional: the payment rate manager to use,
|
|
|
|
defaults to session.payment_rate_manager
|
|
|
|
:param timeout (int): sd blob timeout
|
|
|
|
|
|
|
|
:return: decoded sd blob
|
|
|
|
"""
|
2017-01-17 04:23:20 +01:00
|
|
|
timeout = timeout if timeout is not None else conf.settings['sd_download_timeout']
|
2017-02-16 05:39:17 +01:00
|
|
|
rate_manager = rate_manager or self.session.payment_rate_manager
|
|
|
|
|
|
|
|
def cb(sd_blob):
|
|
|
|
if not finished_d.called:
|
|
|
|
finished_d.callback(sd_blob)
|
|
|
|
|
|
|
|
def eb():
|
|
|
|
if not finished_d.called:
|
|
|
|
finished_d.errback(Exception("Blob (%s) download timed out" %
|
|
|
|
sd_blob_hash[:SHORT_ID_LEN]))
|
|
|
|
|
|
|
|
def save_sd_blob(sd_blob):
|
|
|
|
d = defer.succeed(read_sd_blob(sd_blob))
|
|
|
|
d.addCallback(lambda decoded: save_sd_info(self.stream_info_manager, decoded))
|
|
|
|
d.addCallback(self.stream_info_manager.save_sd_blob_hash_to_stream, sd_blob_hash)
|
|
|
|
d.addCallback(lambda _: sd_blob)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def read_sd_blob(sd_blob):
|
|
|
|
sd_blob_file = sd_blob.open_for_reading()
|
|
|
|
decoded_sd_blob = json.loads(sd_blob_file.read())
|
|
|
|
sd_blob.close_read_handle(sd_blob_file)
|
|
|
|
return decoded_sd_blob
|
|
|
|
|
|
|
|
finished_d = defer.Deferred()
|
|
|
|
finished_d.addCallback(save_sd_blob)
|
|
|
|
|
|
|
|
reactor.callLater(timeout, eb)
|
|
|
|
d = download_sd_blob(self.session, sd_blob_hash, rate_manager)
|
|
|
|
d.addCallback(cb)
|
|
|
|
return finished_d
|
|
|
|
|
|
|
|
def _download_blob(self, blob_hash, rate_manager=None, timeout=None):
|
|
|
|
"""
|
|
|
|
Download a blob
|
|
|
|
|
|
|
|
:param blob_hash (str): blob hash
|
|
|
|
:param rate_manager (PaymentRateManager), optional: the payment rate manager to use,
|
|
|
|
defaults to session.payment_rate_manager
|
|
|
|
:param timeout (int): blob timeout
|
|
|
|
:return: BlobFile
|
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2017-02-16 05:39:17 +01:00
|
|
|
def cb(blob):
|
|
|
|
if not finished_d.called:
|
|
|
|
finished_d.callback(blob)
|
2016-08-02 08:54:04 +02:00
|
|
|
|
|
|
|
def eb():
|
2017-02-16 05:39:17 +01:00
|
|
|
if not finished_d.called:
|
|
|
|
finished_d.errback(Exception("Blob (%s) download timed out" %
|
|
|
|
blob_hash[:SHORT_ID_LEN]))
|
2016-08-02 08:54:04 +02:00
|
|
|
|
2017-02-16 05:39:17 +01:00
|
|
|
rate_manager = rate_manager or self.session.payment_rate_manager
|
|
|
|
timeout = timeout or 30
|
|
|
|
finished_d = defer.Deferred(None)
|
2016-08-03 23:57:26 +02:00
|
|
|
reactor.callLater(timeout, eb)
|
2017-02-16 05:39:17 +01:00
|
|
|
d = download_sd_blob(self.session, blob_hash, rate_manager)
|
2016-08-02 08:54:04 +02:00
|
|
|
d.addCallback(cb)
|
2017-02-16 05:39:17 +01:00
|
|
|
return finished_d
|
2016-08-02 05:15:32 +02:00
|
|
|
|
2016-12-30 07:12:20 +01:00
|
|
|
@defer.inlineCallbacks
|
2016-12-21 20:55:43 +01:00
|
|
|
def _download_name(self, name, timeout=None, download_directory=None,
|
2016-07-21 17:44:59 +02:00
|
|
|
file_name=None, stream_info=None, wait_for_write=True):
|
2016-04-24 23:51:24 +02:00
|
|
|
"""
|
2016-05-04 11:20:38 +02:00
|
|
|
Add a lbry file to the file manager, start the download, and return the new lbry file.
|
|
|
|
If it already exists in the file manager, return the existing lbry file
|
2016-04-24 23:51:24 +02:00
|
|
|
"""
|
2017-01-17 04:23:20 +01:00
|
|
|
timeout = timeout if timeout is not None else conf.settings['download_timeout']
|
2016-12-30 18:37:11 +01:00
|
|
|
|
2016-01-12 00:01:46 +01:00
|
|
|
|
2017-02-20 01:17:25 +01:00
|
|
|
helper = _DownloadNameHelper(self, name, timeout, download_directory, file_name,
|
|
|
|
wait_for_write)
|
2016-05-05 03:25:46 +02:00
|
|
|
if not stream_info:
|
|
|
|
self.waiting_on[name] = True
|
2016-12-30 07:12:20 +01:00
|
|
|
stream_info = yield self._resolve_name(name)
|
2017-02-20 01:17:25 +01:00
|
|
|
|
2016-12-30 07:12:20 +01:00
|
|
|
lbry_file = yield helper.setup_stream(stream_info)
|
|
|
|
sd_hash, file_path = yield helper.wait_or_get_stream(stream_info, lbry_file)
|
|
|
|
defer.returnValue((sd_hash, file_path))
|
2016-07-21 17:44:59 +02:00
|
|
|
|
2017-02-09 22:12:30 +01:00
|
|
|
@defer.inlineCallbacks
|
|
|
|
def _publish_stream(self, name, bid, metadata, file_path=None, fee=None):
|
|
|
|
publisher = Publisher(self.session, self.lbry_file_manager, self.session.wallet)
|
|
|
|
verify_name_characters(name)
|
|
|
|
if bid <= 0.0:
|
|
|
|
raise Exception("Invalid bid")
|
|
|
|
if fee:
|
|
|
|
metadata = yield publisher.add_fee_to_metadata(metadata, fee)
|
|
|
|
if not file_path:
|
|
|
|
claim_out = yield publisher.update_stream(name, bid, metadata)
|
|
|
|
else:
|
|
|
|
claim_out = yield publisher.publish_stream(name, file_path, bid, metadata)
|
2017-02-13 03:20:54 +01:00
|
|
|
d = reupload.reflect_stream(publisher.lbry_file)
|
|
|
|
d.addCallbacks(lambda _: log.info("Reflected new publication to lbry://%s", name),
|
|
|
|
log.exception)
|
2017-02-09 22:12:30 +01:00
|
|
|
log.info("Success! Published to lbry://%s txid: %s nout: %d", name, claim_out['txid'],
|
|
|
|
claim_out['nout'])
|
|
|
|
yield self._add_to_pending_claims(claim_out, name)
|
|
|
|
self.looping_call_manager.start(Checker.PENDING_CLAIM, 30)
|
|
|
|
defer.returnValue(claim_out)
|
|
|
|
|
2016-07-21 17:44:59 +02:00
|
|
|
def add_stream(self, name, timeout, download_directory, file_name, stream_info):
|
|
|
|
"""Makes, adds and starts a stream"""
|
|
|
|
self.streams[name] = GetStream(self.sd_identifier,
|
|
|
|
self.session,
|
|
|
|
self.session.wallet,
|
|
|
|
self.lbry_file_manager,
|
2016-08-05 12:00:35 +02:00
|
|
|
self.exchange_rate_manager,
|
2016-07-21 17:44:59 +02:00
|
|
|
max_key_fee=self.max_key_fee,
|
|
|
|
data_rate=self.data_rate,
|
|
|
|
timeout=timeout,
|
|
|
|
download_directory=download_directory,
|
|
|
|
file_name=file_name)
|
2017-02-13 02:57:23 +01:00
|
|
|
return self.streams[name].start(stream_info, name)
|
2015-12-15 03:49:01 +01:00
|
|
|
|
2016-04-26 04:35:21 +02:00
|
|
|
def _get_long_count_timestamp(self):
|
2017-01-02 20:52:24 +01:00
|
|
|
dt = utils.utcnow() - utils.datetime_obj(year=2012, month=12, day=21)
|
|
|
|
return int(dt.total_seconds())
|
2016-01-20 03:07:16 +01:00
|
|
|
|
2016-04-26 04:35:21 +02:00
|
|
|
def _update_claim_cache(self):
|
|
|
|
f = open(os.path.join(self.db_dir, "stream_info_cache.json"), "w")
|
|
|
|
f.write(json.dumps(self.name_cache))
|
|
|
|
f.close()
|
|
|
|
return defer.succeed(True)
|
2015-12-15 03:49:01 +01:00
|
|
|
|
2016-05-30 21:49:25 +02:00
|
|
|
def _resolve_name(self, name, force_refresh=False):
|
2016-07-21 17:44:59 +02:00
|
|
|
"""Resolves a name. Checks the cache first before going out to the blockchain.
|
2016-04-26 04:35:21 +02:00
|
|
|
|
2016-07-21 17:44:59 +02:00
|
|
|
Args:
|
|
|
|
name: the lbry://<name> to resolve
|
|
|
|
force_refresh: if True, always go out to the blockchain to resolve.
|
|
|
|
"""
|
|
|
|
if name.startswith('lbry://'):
|
2016-09-25 23:41:44 +02:00
|
|
|
raise ValueError('name {} should not start with lbry://'.format(name))
|
2016-07-21 17:44:59 +02:00
|
|
|
helper = _ResolveNameHelper(self, name, force_refresh)
|
|
|
|
return helper.get_deferred()
|
2016-01-12 00:01:46 +01:00
|
|
|
|
2016-11-30 22:23:48 +01:00
|
|
|
def _get_or_download_sd_blob(self, blob, sd_hash):
|
|
|
|
if blob:
|
2017-01-19 04:08:02 +01:00
|
|
|
return self.session.blob_manager.get_blob(blob[0])
|
2016-11-30 22:23:48 +01:00
|
|
|
|
|
|
|
def _check_est(downloader):
|
|
|
|
if downloader.result is not None:
|
|
|
|
downloader.cancel()
|
|
|
|
|
|
|
|
d = defer.succeed(None)
|
|
|
|
reactor.callLater(self.search_timeout, _check_est, d)
|
2016-12-07 16:10:46 +01:00
|
|
|
d.addCallback(
|
|
|
|
lambda _: download_sd_blob(
|
2016-12-18 02:01:06 +01:00
|
|
|
self.session, sd_hash, self.session.payment_rate_manager))
|
2016-11-30 22:23:48 +01:00
|
|
|
return d
|
|
|
|
|
|
|
|
def get_or_download_sd_blob(self, sd_hash):
|
2016-12-07 16:10:46 +01:00
|
|
|
"""Return previously downloaded sd blob if already in the blob
|
|
|
|
manager, otherwise download and return it
|
2016-11-30 22:23:48 +01:00
|
|
|
"""
|
|
|
|
d = self.session.blob_manager.completed_blobs([sd_hash])
|
|
|
|
d.addCallback(self._get_or_download_sd_blob, sd_hash)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def get_size_from_sd_blob(self, sd_blob):
|
|
|
|
"""
|
|
|
|
Get total stream size in bytes from a sd blob
|
|
|
|
"""
|
|
|
|
|
|
|
|
d = self.sd_identifier.get_metadata_for_sd_blob(sd_blob)
|
|
|
|
d.addCallback(lambda metadata: metadata.validator.info_to_show())
|
|
|
|
d.addCallback(lambda info: int(dict(info)['stream_size']))
|
|
|
|
return d
|
|
|
|
|
2016-12-02 20:39:01 +01:00
|
|
|
def _get_est_cost_from_stream_size(self, size):
|
2016-11-30 22:23:48 +01:00
|
|
|
"""
|
|
|
|
Calculate estimated LBC cost for a stream given its size in bytes
|
|
|
|
"""
|
|
|
|
|
|
|
|
if self.session.payment_rate_manager.generous:
|
|
|
|
return 0.0
|
2017-01-17 04:23:20 +01:00
|
|
|
return size / (10 ** 6) * conf.settings['data_rate']
|
2016-11-30 22:23:48 +01:00
|
|
|
|
2016-12-02 20:39:01 +01:00
|
|
|
def get_est_cost_using_known_size(self, name, size):
|
|
|
|
"""
|
|
|
|
Calculate estimated LBC cost for a stream given its size in bytes
|
|
|
|
"""
|
|
|
|
|
|
|
|
cost = self._get_est_cost_from_stream_size(size)
|
|
|
|
|
|
|
|
d = self._resolve_name(name)
|
|
|
|
d.addCallback(lambda metadata: self._add_key_fee_to_est_data_cost(metadata, cost))
|
|
|
|
return d
|
|
|
|
|
2016-11-30 22:23:48 +01:00
|
|
|
def get_est_cost_from_sd_hash(self, sd_hash):
|
|
|
|
"""
|
|
|
|
Get estimated cost from a sd hash
|
|
|
|
"""
|
|
|
|
|
|
|
|
d = self.get_or_download_sd_blob(sd_hash)
|
|
|
|
d.addCallback(self.get_size_from_sd_blob)
|
2016-12-02 20:39:01 +01:00
|
|
|
d.addCallback(self._get_est_cost_from_stream_size)
|
2016-11-30 00:06:16 +01:00
|
|
|
return d
|
|
|
|
|
|
|
|
def _get_est_cost_from_metadata(self, metadata, name):
|
2016-11-30 22:23:48 +01:00
|
|
|
d = self.get_est_cost_from_sd_hash(metadata['sources']['lbry_sd_hash'])
|
2016-11-30 00:06:16 +01:00
|
|
|
|
|
|
|
def _handle_err(err):
|
|
|
|
if isinstance(err, Failure):
|
2016-12-07 16:10:46 +01:00
|
|
|
log.warning(
|
|
|
|
"Timeout getting blob for cost est for lbry://%s, using only key fee", name)
|
2016-11-30 00:06:16 +01:00
|
|
|
return 0.0
|
|
|
|
raise err
|
|
|
|
|
|
|
|
d.addErrback(_handle_err)
|
2016-12-02 20:39:01 +01:00
|
|
|
d.addCallback(lambda data_cost: self._add_key_fee_to_est_data_cost(metadata, data_cost))
|
2016-11-30 00:06:16 +01:00
|
|
|
return d
|
|
|
|
|
2016-12-02 20:39:01 +01:00
|
|
|
def _add_key_fee_to_est_data_cost(self, metadata, data_cost):
|
|
|
|
fee = self.exchange_rate_manager.to_lbc(metadata.get('fee', None))
|
|
|
|
fee_amount = 0.0 if fee is None else fee.amount
|
|
|
|
return data_cost + fee_amount
|
|
|
|
|
2017-02-11 16:33:06 +01:00
|
|
|
@defer.inlineCallbacks
|
2016-11-30 22:23:48 +01:00
|
|
|
def get_est_cost_from_name(self, name):
|
|
|
|
"""
|
|
|
|
Resolve a name and return the estimated stream cost
|
|
|
|
"""
|
2017-02-11 16:33:06 +01:00
|
|
|
metadata = yield self._resolve_name(name)
|
|
|
|
cost = yield self._get_est_cost_from_metadata(metadata, name)
|
|
|
|
defer.returnValue(cost)
|
2016-11-30 00:06:16 +01:00
|
|
|
|
2016-12-02 20:39:01 +01:00
|
|
|
def get_est_cost(self, name, size=None):
|
2016-12-07 16:10:46 +01:00
|
|
|
"""Get a cost estimate for a lbry stream, if size is not provided the
|
|
|
|
sd blob will be downloaded to determine the stream size
|
|
|
|
|
2016-11-30 22:23:48 +01:00
|
|
|
"""
|
2016-12-02 20:39:01 +01:00
|
|
|
|
2016-11-30 22:23:48 +01:00
|
|
|
if size is not None:
|
2016-12-02 20:39:01 +01:00
|
|
|
return self.get_est_cost_using_known_size(name, size)
|
2016-11-30 22:23:48 +01:00
|
|
|
return self.get_est_cost_from_name(name)
|
2016-11-30 00:06:16 +01:00
|
|
|
|
2017-02-16 15:12:00 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-03-06 23:01:35 +01:00
|
|
|
def _get_lbry_file_dict(self, lbry_file, full_status=False):
|
|
|
|
key = binascii.b2a_hex(lbry_file.key) if lbry_file.key else None
|
|
|
|
full_path = os.path.join(lbry_file.download_directory, lbry_file.file_name)
|
|
|
|
mime_type = mimetypes.guess_type(full_path)[0]
|
|
|
|
if os.path.isfile(full_path):
|
|
|
|
with open(full_path) as written_file:
|
|
|
|
written_file.seek(0, os.SEEK_END)
|
|
|
|
written_bytes = written_file.tell()
|
|
|
|
else:
|
|
|
|
written_bytes = False
|
2016-04-24 10:42:42 +02:00
|
|
|
|
2017-03-06 23:01:35 +01:00
|
|
|
if full_status:
|
|
|
|
size = yield lbry_file.get_total_bytes()
|
|
|
|
file_status = yield lbry_file.status()
|
|
|
|
message = STREAM_STAGES[2][1] % (file_status.name, file_status.num_completed,
|
|
|
|
file_status.num_known, file_status.running_status)
|
|
|
|
else:
|
|
|
|
size = None
|
|
|
|
message = None
|
|
|
|
claim = yield self.session.wallet.get_claim_info(lbry_file.name,
|
|
|
|
lbry_file.txid,
|
|
|
|
lbry_file.nout)
|
|
|
|
try:
|
|
|
|
metadata = claim['value']
|
|
|
|
except:
|
|
|
|
metadata = None
|
|
|
|
try:
|
|
|
|
outpoint = repr(ClaimOutpoint(lbry_file.txid, lbry_file.nout))
|
|
|
|
except TypeError:
|
|
|
|
outpoint = None
|
2016-04-24 10:42:42 +02:00
|
|
|
|
2017-03-06 23:01:35 +01:00
|
|
|
defer.returnValue({
|
|
|
|
'completed': lbry_file.completed,
|
|
|
|
'file_name': lbry_file.file_name,
|
|
|
|
'download_directory': lbry_file.download_directory,
|
|
|
|
'points_paid': lbry_file.points_paid,
|
|
|
|
'stopped': lbry_file.stopped,
|
|
|
|
'stream_hash': lbry_file.stream_hash,
|
|
|
|
'stream_name': lbry_file.stream_name,
|
|
|
|
'suggested_file_name': lbry_file.suggested_file_name,
|
|
|
|
'sd_hash': lbry_file.sd_hash,
|
|
|
|
'name': lbry_file.name,
|
|
|
|
'outpoint': outpoint,
|
|
|
|
'claim_id': lbry_file.claim_id,
|
|
|
|
'download_path': full_path,
|
|
|
|
'mime_type': mime_type,
|
|
|
|
'key': key,
|
|
|
|
'total_bytes': size,
|
|
|
|
'written_bytes': written_bytes,
|
|
|
|
'message': message,
|
|
|
|
'metadata': metadata
|
|
|
|
})
|
2016-04-24 23:51:24 +02:00
|
|
|
|
2017-02-20 01:22:21 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-03-08 17:53:22 +01:00
|
|
|
def _get_lbry_file(self, search_by, val, return_json=False, full_status=False):
|
2017-03-06 23:01:35 +01:00
|
|
|
lbry_file = None
|
|
|
|
if search_by in FileID:
|
|
|
|
for l_f in self.lbry_file_manager.lbry_files:
|
|
|
|
if l_f.__dict__.get(search_by) == val:
|
|
|
|
lbry_file = l_f
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
raise NoValidSearch('{} is not a valid search operation'.format(search_by))
|
|
|
|
if return_json and lbry_file:
|
|
|
|
lbry_file = yield self._get_lbry_file_dict(lbry_file, full_status=full_status)
|
2017-02-20 01:22:21 +01:00
|
|
|
defer.returnValue(lbry_file)
|
|
|
|
|
2017-02-16 15:12:00 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-03-06 23:01:35 +01:00
|
|
|
def _get_lbry_files(self, as_json=False, full_status=False, **kwargs):
|
|
|
|
lbry_files = list(self.lbry_file_manager.lbry_files)
|
|
|
|
if kwargs:
|
|
|
|
for search_type, value in iter_lbry_file_search_values(kwargs):
|
|
|
|
lbry_files = [l_f for l_f in lbry_files if l_f.__dict__[search_type] == value]
|
|
|
|
if as_json:
|
|
|
|
file_dicts = []
|
|
|
|
for lbry_file in lbry_files:
|
|
|
|
lbry_file_dict = yield self._get_lbry_file_dict(lbry_file, full_status=full_status)
|
|
|
|
file_dicts.append(lbry_file_dict)
|
|
|
|
lbry_files = file_dicts
|
|
|
|
defer.returnValue(lbry_files)
|
|
|
|
|
|
|
|
# TODO: do this and get_blobs_for_sd_hash in the stream info manager
|
2017-02-16 05:39:17 +01:00
|
|
|
def get_blobs_for_stream_hash(self, stream_hash):
|
|
|
|
def _iter_blobs(blob_hashes):
|
|
|
|
for blob_hash, blob_num, blob_iv, blob_length in blob_hashes:
|
|
|
|
if blob_hash:
|
|
|
|
yield self.session.blob_manager.get_blob(blob_hash, length=blob_length)
|
|
|
|
|
|
|
|
def _get_blobs(blob_hashes):
|
|
|
|
dl = defer.DeferredList(list(_iter_blobs(blob_hashes)), consumeErrors=True)
|
|
|
|
dl.addCallback(lambda blobs: [blob[1] for blob in blobs if blob[0]])
|
|
|
|
return dl
|
|
|
|
|
|
|
|
d = self.stream_info_manager.get_blobs_for_stream(stream_hash)
|
|
|
|
d.addCallback(_get_blobs)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def get_blobs_for_sd_hash(self, sd_hash):
|
|
|
|
d = self.stream_info_manager.get_stream_hash_for_sd_hash(sd_hash)
|
|
|
|
d.addCallback(self.get_blobs_for_stream_hash)
|
|
|
|
return d
|
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
############################################################################
|
|
|
|
# #
|
|
|
|
# JSON-RPC API methods start here #
|
|
|
|
# #
|
|
|
|
############################################################################
|
|
|
|
|
2017-01-18 16:36:01 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-02-21 18:51:13 +01:00
|
|
|
def jsonrpc_status(self, session_status=False):
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
Return daemon status
|
2016-04-13 20:47:34 +02:00
|
|
|
|
|
|
|
Args:
|
2017-01-03 20:13:01 +01:00
|
|
|
session_status: bool
|
|
|
|
Returns:
|
|
|
|
daemon status
|
|
|
|
"""
|
2017-02-21 22:30:36 +01:00
|
|
|
# on startup, the wallet or network won't be available but we still need this call to work
|
|
|
|
has_wallet = self.session and self.session.wallet and self.session.wallet.network
|
2017-02-21 18:51:13 +01:00
|
|
|
local_height = self.session.wallet.network.get_local_height() if has_wallet else 0
|
|
|
|
remote_height = self.session.wallet.network.get_server_height() if has_wallet else 0
|
|
|
|
best_hash = (yield self.session.wallet.get_best_blockhash()) if has_wallet else None
|
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
response = {
|
|
|
|
'lbry_id': base58.b58encode(self.lbryid)[:SHORT_ID_LEN],
|
2017-02-02 16:23:17 +01:00
|
|
|
'installation_id': conf.settings.get_installation_id()[:SHORT_ID_LEN],
|
2017-01-03 20:13:01 +01:00
|
|
|
'is_running': self.announced_startup,
|
2017-02-13 20:18:09 +01:00
|
|
|
'is_first_run': self.session.wallet.is_first_run if has_wallet else None,
|
2017-01-03 20:13:01 +01:00
|
|
|
'startup_status': {
|
|
|
|
'code': self.startup_status[0],
|
|
|
|
'message': self.startup_status[1],
|
|
|
|
},
|
|
|
|
'connection_status': {
|
|
|
|
'code': self.connection_status_code,
|
|
|
|
'message': (
|
|
|
|
CONNECTION_MESSAGES[self.connection_status_code]
|
|
|
|
if self.connection_status_code is not None
|
|
|
|
else ''
|
|
|
|
),
|
|
|
|
},
|
2017-02-21 18:51:13 +01:00
|
|
|
'blocks_behind': remote_height - local_height, # deprecated. remove from UI, then here
|
|
|
|
'blockchain_status': {
|
|
|
|
'blocks': local_height,
|
|
|
|
'blocks_behind': remote_height - local_height,
|
|
|
|
'best_blockhash': best_hash,
|
|
|
|
}
|
2017-01-03 20:13:01 +01:00
|
|
|
}
|
2017-01-26 02:06:17 +01:00
|
|
|
if session_status:
|
2017-01-18 16:36:01 +01:00
|
|
|
blobs = yield self.session.blob_manager.get_all_verified_blobs()
|
|
|
|
response['session_status'] = {
|
|
|
|
'managed_blobs': len(blobs),
|
|
|
|
'managed_streams': len(self.lbry_file_manager.lbry_files),
|
|
|
|
}
|
|
|
|
defer.returnValue(response)
|
2016-04-07 09:12:09 +02:00
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
def jsonrpc_get_best_blockhash(self):
|
2016-04-09 21:43:10 +02:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `status blockchain_status=True` instead
|
|
|
|
"""
|
2017-02-21 18:51:13 +01:00
|
|
|
d = self.jsonrpc_status()
|
2017-01-05 00:42:02 +01:00
|
|
|
d.addCallback(lambda x: self._render_response(
|
2017-01-12 16:55:38 +01:00
|
|
|
x['blockchain_status']['best_blockhash']))
|
2017-01-05 00:42:02 +01:00
|
|
|
return d
|
2016-04-09 21:43:10 +02:00
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
def jsonrpc_is_running(self):
|
2016-04-13 20:47:34 +02:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `status` instead
|
|
|
|
"""
|
2017-01-18 16:36:01 +01:00
|
|
|
d = self.jsonrpc_status()
|
2017-01-12 16:55:38 +01:00
|
|
|
d.addCallback(lambda x: self._render_response(x['is_running']))
|
2017-01-05 00:42:02 +01:00
|
|
|
return d
|
2016-04-09 22:14:28 +02:00
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
def jsonrpc_daemon_status(self):
|
|
|
|
"""
|
|
|
|
DEPRECATED. Use `status` instead
|
|
|
|
"""
|
2017-01-05 00:42:02 +01:00
|
|
|
|
|
|
|
def _simulate_old_daemon_status(status):
|
2017-01-12 16:55:38 +01:00
|
|
|
message = status['startup_status']['message']
|
2017-01-05 00:42:02 +01:00
|
|
|
problem_code = None
|
|
|
|
progress = None
|
|
|
|
|
|
|
|
if self.connection_status_code != CONNECTION_STATUS_CONNECTED:
|
|
|
|
problem_code = self.connection_status_code
|
|
|
|
message = CONNECTION_MESSAGES[self.connection_status_code]
|
2017-01-12 16:55:38 +01:00
|
|
|
elif status['startup_status']['code'] == LOADING_WALLET_CODE:
|
2017-01-05 00:42:02 +01:00
|
|
|
message = "Catching up with the blockchain."
|
|
|
|
progress = 0
|
2017-02-21 18:51:13 +01:00
|
|
|
if status['blockchain_status']['blocks_behind'] > 0:
|
|
|
|
message += (
|
|
|
|
' ' + str(status['blockchain_status']['blocks_behind']) + " blocks behind."
|
|
|
|
)
|
|
|
|
progress = status['blockchain_status']['blocks_behind']
|
2017-01-05 00:42:02 +01:00
|
|
|
|
|
|
|
return {
|
|
|
|
'message': message,
|
2017-01-12 16:55:38 +01:00
|
|
|
'code': status['startup_status']['code'],
|
2017-01-05 00:42:02 +01:00
|
|
|
'progress': progress,
|
|
|
|
'is_lagging': self.connection_status_code != CONNECTION_STATUS_CONNECTED,
|
|
|
|
'problem_code': problem_code,
|
|
|
|
}
|
|
|
|
|
|
|
|
d = self.jsonrpc_status()
|
|
|
|
d.addCallback(_simulate_old_daemon_status)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda x: self._render_response(x)) # is this necessary?
|
2017-01-05 00:42:02 +01:00
|
|
|
return d
|
2016-04-09 22:14:28 +02:00
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
def jsonrpc_is_first_run(self):
|
|
|
|
"""
|
|
|
|
DEPRECATED. Use `status` instead
|
|
|
|
"""
|
2017-02-21 18:51:13 +01:00
|
|
|
d = self.jsonrpc_status()
|
2017-01-12 16:55:38 +01:00
|
|
|
d.addCallback(lambda x: self._render_response(x['is_first_run']))
|
2017-01-05 00:42:02 +01:00
|
|
|
return d
|
2017-01-03 20:13:01 +01:00
|
|
|
|
|
|
|
def jsonrpc_get_lbry_session_info(self):
|
|
|
|
"""
|
|
|
|
DEPRECATED. Use `status` instead
|
|
|
|
"""
|
2017-01-05 00:42:02 +01:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
d = self.jsonrpc_status(session_status=True)
|
2017-01-05 00:42:02 +01:00
|
|
|
d.addCallback(lambda x: self._render_response({
|
2017-01-12 16:55:38 +01:00
|
|
|
'lbry_id': x['lbry_id'],
|
|
|
|
'managed_blobs': x['session_status']['managed_blobs'],
|
|
|
|
'managed_streams': x['session_status']['managed_streams'],
|
2017-01-07 01:21:25 +01:00
|
|
|
}))
|
2017-01-05 00:42:02 +01:00
|
|
|
return d
|
2017-01-03 20:13:01 +01:00
|
|
|
|
|
|
|
def jsonrpc_get_time_behind_blockchain(self):
|
|
|
|
"""
|
|
|
|
DEPRECATED. Use `status` instead
|
|
|
|
"""
|
2017-02-21 18:51:13 +01:00
|
|
|
d = self.jsonrpc_status()
|
|
|
|
d.addCallback(lambda x: self._render_response(x['blockchain_status']['blocks_behind']))
|
2017-01-05 00:42:02 +01:00
|
|
|
return d
|
2016-04-12 04:28:46 +02:00
|
|
|
|
|
|
|
def jsonrpc_version(self):
|
|
|
|
"""
|
|
|
|
Get lbry version information
|
2016-04-13 20:47:34 +02:00
|
|
|
|
|
|
|
Args:
|
|
|
|
None
|
|
|
|
Returns:
|
2016-04-16 04:31:06 +02:00
|
|
|
"platform": platform string
|
|
|
|
"os_release": os release string
|
|
|
|
"os_system": os name
|
|
|
|
"lbrynet_version: ": lbrynet_version,
|
|
|
|
"lbryum_version: ": lbryum_version,
|
|
|
|
"ui_version": commit hash of ui version being used
|
2016-04-14 04:07:27 +02:00
|
|
|
"remote_lbrynet": most recent lbrynet version available from github
|
|
|
|
"remote_lbryum": most recent lbryum version available from github
|
2016-04-12 04:28:46 +02:00
|
|
|
"""
|
|
|
|
|
2016-05-30 21:49:25 +02:00
|
|
|
platform_info = self._get_platform()
|
2016-04-12 04:28:46 +02:00
|
|
|
msg = {
|
2016-05-30 21:49:25 +02:00
|
|
|
'platform': platform_info['platform'],
|
|
|
|
'os_release': platform_info['os_release'],
|
|
|
|
'os_system': platform_info['os_system'],
|
2017-02-16 19:01:16 +01:00
|
|
|
'lbrynet_version': LBRYNET_VERSION,
|
|
|
|
'lbryum_version': LBRYUM_VERSION,
|
2017-01-02 18:19:28 +01:00
|
|
|
'ui_version': platform_info['ui_version'],
|
2017-02-17 04:25:09 +01:00
|
|
|
'remote_lbrynet': self._remote_version.version,
|
|
|
|
'lbrynet_update_available': self._remote_version.is_update_available(),
|
2016-04-12 04:28:46 +02:00
|
|
|
}
|
2016-04-12 05:13:26 +02:00
|
|
|
|
2016-07-16 08:15:58 +02:00
|
|
|
log.info("Get version info: " + json.dumps(msg))
|
2017-01-07 01:21:25 +01:00
|
|
|
return self._render_response(msg)
|
2016-04-09 10:15:58 +02:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_report_bug(self, message=None):
|
2017-01-02 20:52:24 +01:00
|
|
|
"""
|
|
|
|
Report a bug to slack
|
|
|
|
|
|
|
|
Args:
|
|
|
|
'message': string, message to send
|
|
|
|
Returns:
|
|
|
|
True if successful
|
|
|
|
"""
|
|
|
|
|
|
|
|
platform_name = self._get_platform()['platform']
|
2017-02-02 16:23:17 +01:00
|
|
|
report_bug_to_slack(
|
|
|
|
message,
|
|
|
|
conf.settings.installation_id,
|
|
|
|
platform_name,
|
2017-02-16 19:01:16 +01:00
|
|
|
LBRYNET_VERSION
|
2017-02-02 16:23:17 +01:00
|
|
|
)
|
2017-01-07 01:21:25 +01:00
|
|
|
return self._render_response(True)
|
2017-01-02 20:52:24 +01:00
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
def jsonrpc_get_settings(self):
|
2016-11-28 20:16:21 +01:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `settings_get` instead.
|
2016-11-28 20:16:21 +01:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
return self.jsonrpc_settings_get()
|
2016-11-28 20:16:21 +01:00
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
def jsonrpc_settings_get(self):
|
2016-01-07 16:24:55 +01:00
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
Get daemon settings
|
2016-04-13 20:47:34 +02:00
|
|
|
|
|
|
|
Returns:
|
|
|
|
'run_on_startup': bool,
|
|
|
|
'data_rate': float,
|
|
|
|
'max_key_fee': float,
|
2016-04-22 08:45:05 +02:00
|
|
|
'download_directory': string,
|
2016-04-13 20:47:34 +02:00
|
|
|
'max_upload': float, 0.0 for unlimited
|
|
|
|
'max_download': float, 0.0 for unlimited
|
|
|
|
'search_timeout': float,
|
2016-04-22 08:45:05 +02:00
|
|
|
'download_timeout': int
|
2016-04-13 20:47:34 +02:00
|
|
|
'max_search_results': int,
|
|
|
|
'wallet_type': string,
|
|
|
|
'delete_blobs_on_remove': bool,
|
|
|
|
'peer_port': int,
|
|
|
|
'dht_node_port': int,
|
|
|
|
'use_upnp': bool,
|
2016-01-07 16:24:55 +01:00
|
|
|
"""
|
2016-01-12 18:42:32 +01:00
|
|
|
|
2016-07-16 08:15:58 +02:00
|
|
|
log.info("Get daemon settings")
|
2017-01-17 04:23:20 +01:00
|
|
|
return self._render_response(conf.settings.get_current_settings_dict())
|
2016-01-07 16:24:55 +01:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_set_settings(self, **kwargs):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `settings_set` instead.
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_settings_set(**kwargs)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_settings_set(self, **kwargs):
|
2016-01-24 06:10:22 +01:00
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
Set daemon settings
|
2016-04-13 20:47:34 +02:00
|
|
|
|
|
|
|
Args:
|
|
|
|
'run_on_startup': bool,
|
|
|
|
'data_rate': float,
|
|
|
|
'max_key_fee': float,
|
2016-04-22 08:45:05 +02:00
|
|
|
'download_directory': string,
|
2016-04-13 20:47:34 +02:00
|
|
|
'max_upload': float, 0.0 for unlimited
|
|
|
|
'max_download': float, 0.0 for unlimited
|
2016-04-23 00:18:17 +02:00
|
|
|
'download_timeout': int
|
2016-04-13 20:47:34 +02:00
|
|
|
Returns:
|
|
|
|
settings dict
|
2016-01-24 06:10:22 +01:00
|
|
|
"""
|
|
|
|
|
2016-04-22 08:45:05 +02:00
|
|
|
def _log_settings_change():
|
2016-12-07 16:10:46 +01:00
|
|
|
log.info(
|
|
|
|
"Set daemon settings to %s",
|
|
|
|
json.dumps(conf.settings.get_adjustable_settings_dict()))
|
2016-04-07 09:12:09 +02:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
d = self._update_settings(kwargs)
|
2016-05-31 23:38:00 +02:00
|
|
|
d.addErrback(lambda err: log.info(err.getTraceback()))
|
2016-04-22 08:45:05 +02:00
|
|
|
d.addCallback(lambda _: _log_settings_change())
|
2016-12-07 16:10:46 +01:00
|
|
|
d.addCallback(
|
2017-01-07 01:21:25 +01:00
|
|
|
lambda _: self._render_response(conf.settings.get_adjustable_settings_dict()))
|
2016-01-07 16:24:55 +01:00
|
|
|
|
2016-04-07 09:12:09 +02:00
|
|
|
return d
|
2016-01-07 16:24:55 +01:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_help(self, command=None):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
2017-01-11 21:31:08 +01:00
|
|
|
Return a useful message for an API command
|
2016-04-13 20:47:34 +02:00
|
|
|
|
|
|
|
Args:
|
2017-01-11 21:31:08 +01:00
|
|
|
'command': optional, command to retrieve documentation for
|
2016-04-13 20:47:34 +02:00
|
|
|
Returns:
|
2017-01-11 21:31:08 +01:00
|
|
|
if given a command, returns documentation about that command
|
|
|
|
otherwise returns general help message
|
2016-04-13 20:47:34 +02:00
|
|
|
"""
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
if command is None:
|
2017-01-07 01:21:25 +01:00
|
|
|
return self._render_response(textwrap.dedent(self.jsonrpc_help.__doc__))
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
fn = self.callable_methods.get(command)
|
|
|
|
if fn is None:
|
|
|
|
return self._render_response(
|
|
|
|
"No help available for '{}'. It is not a valid command.".format(command)
|
|
|
|
)
|
|
|
|
return self._render_response(textwrap.dedent(fn.__doc__))
|
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
def jsonrpc_commands(self):
|
|
|
|
"""
|
|
|
|
Return a list of available commands
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
list
|
|
|
|
"""
|
2017-02-20 06:21:13 +01:00
|
|
|
return self._render_response(sorted(
|
|
|
|
[command for command in self.callable_methods.keys()
|
|
|
|
if 'DEPRECATED' not in getattr(self, "jsonrpc_" + command).__doc__]
|
|
|
|
))
|
2016-04-13 20:47:34 +02:00
|
|
|
|
2016-03-24 03:27:48 +01:00
|
|
|
def jsonrpc_get_balance(self):
|
2015-12-06 23:32:17 +01:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `wallet_balance` instead.
|
|
|
|
"""
|
|
|
|
return self.jsonrpc_wallet_balance()
|
|
|
|
|
|
|
|
def jsonrpc_wallet_balance(self):
|
|
|
|
"""
|
|
|
|
Return the balance of the wallet
|
2016-03-24 03:27:48 +01:00
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Returns:
|
|
|
|
balance, float
|
2015-12-06 23:32:17 +01:00
|
|
|
"""
|
2017-01-12 18:51:44 +01:00
|
|
|
return self._render_response(float(self.session.wallet.get_balance()))
|
2015-12-06 23:32:17 +01:00
|
|
|
|
2016-03-24 03:27:48 +01:00
|
|
|
def jsonrpc_stop(self):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `daemon_stop` instead.
|
|
|
|
"""
|
|
|
|
return self.jsonrpc_daemon_stop()
|
|
|
|
|
|
|
|
def jsonrpc_daemon_stop(self):
|
2015-12-06 23:32:17 +01:00
|
|
|
"""
|
2016-01-24 06:10:22 +01:00
|
|
|
Stop lbrynet-daemon
|
2016-03-24 03:27:48 +01:00
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Returns:
|
|
|
|
shutdown message
|
2015-12-06 23:32:17 +01:00
|
|
|
"""
|
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
def _display_shutdown_message():
|
2016-03-24 03:27:48 +01:00
|
|
|
log.info("Shutting down lbrynet daemon")
|
2016-01-11 21:52:38 +01:00
|
|
|
|
|
|
|
d = self._shutdown()
|
2017-01-03 20:13:01 +01:00
|
|
|
d.addCallback(lambda _: _display_shutdown_message())
|
2016-04-20 08:56:29 +02:00
|
|
|
d.addCallback(lambda _: reactor.callLater(0.0, reactor.stop))
|
2017-01-07 01:21:25 +01:00
|
|
|
return self._render_response("Shutting down")
|
2015-12-06 23:32:17 +01:00
|
|
|
|
2017-03-06 23:01:35 +01:00
|
|
|
@defer.inlineCallbacks
|
|
|
|
def jsonrpc_file_list(self, **kwargs):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
2017-03-06 23:01:35 +01:00
|
|
|
List files limited by optional filters
|
2015-12-15 03:49:01 +01:00
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Args:
|
2017-03-06 23:01:35 +01:00
|
|
|
'name' (optional): filter files by lbry name,
|
|
|
|
'sd_hash' (optional): filter files by sd hash,
|
|
|
|
'file_name' (optional): filter files by the name in the downloads folder,
|
|
|
|
'stream_hash' (optional): filter files by stream hash,
|
|
|
|
'claim_id' (optional): filter files by claim id,
|
|
|
|
'outpoint' (optional): filter files by claim outpoint,
|
|
|
|
'rowid' (optional): filter files by internal row id,
|
|
|
|
'full_status': (optional): bool, if true populate the 'message' and 'size' fields
|
2016-04-24 10:42:42 +02:00
|
|
|
|
|
|
|
Returns:
|
2017-03-06 23:01:35 +01:00
|
|
|
[
|
|
|
|
{
|
|
|
|
'completed': bool,
|
|
|
|
'file_name': str,
|
|
|
|
'download_directory': str,
|
|
|
|
'points_paid': float,
|
|
|
|
'stopped': bool,
|
|
|
|
'stream_hash': str (hex),
|
|
|
|
'stream_name': str,
|
|
|
|
'suggested_file_name': str,
|
|
|
|
'sd_hash': str (hex),
|
|
|
|
'name': str,
|
|
|
|
'outpoint': str, (txid:nout)
|
|
|
|
'claim_id': str (hex),
|
|
|
|
'download_path': str,
|
|
|
|
'mime_type': str,
|
|
|
|
'key': str (hex),
|
|
|
|
'total_bytes': int, None if full_status is False
|
|
|
|
'written_bytes': int,
|
|
|
|
'message': str, None if full_status is False
|
|
|
|
'metadata': Metadata dict
|
|
|
|
}
|
|
|
|
]
|
|
|
|
"""
|
|
|
|
|
|
|
|
result = yield self._get_lbry_files(as_json=True, **kwargs)
|
|
|
|
response = yield self._render_response(result)
|
|
|
|
defer.returnValue(response)
|
2016-10-20 21:52:37 +02:00
|
|
|
|
2017-02-11 16:33:06 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_resolve_name(self, name, force=False):
|
2015-12-06 23:32:17 +01:00
|
|
|
"""
|
2017-03-06 23:01:35 +01:00
|
|
|
Resolve stream info from a LBRY name
|
2015-12-15 03:49:01 +01:00
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Args:
|
|
|
|
'name': name to look up, string, do not include lbry:// prefix
|
|
|
|
Returns:
|
2017-02-11 16:33:06 +01:00
|
|
|
metadata from name claim or None if the name is not known
|
2015-12-06 23:32:17 +01:00
|
|
|
"""
|
2016-04-13 20:47:34 +02:00
|
|
|
|
2016-10-20 21:52:37 +02:00
|
|
|
if not name:
|
2017-02-11 16:33:06 +01:00
|
|
|
# TODO: seems like we should raise an error here
|
|
|
|
defer.returnValue(None)
|
2015-12-06 23:32:17 +01:00
|
|
|
|
2017-02-11 16:33:06 +01:00
|
|
|
try:
|
|
|
|
metadata = yield self._resolve_name(name, force_refresh=force)
|
|
|
|
except UnknownNameError:
|
|
|
|
log.info('Name %s is not known', name)
|
|
|
|
defer.returnValue(None)
|
|
|
|
else:
|
|
|
|
defer.returnValue(metadata)
|
2015-12-06 23:32:17 +01:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_get_claim_info(self, **kwargs):
|
2016-09-16 02:15:20 +02:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `claim_show` instead.
|
2016-09-16 02:15:20 +02:00
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_claim_show(**kwargs)
|
2016-09-16 02:15:20 +02:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_claim_show(self, name, txid=None, nout=None):
|
2016-09-16 02:15:20 +02:00
|
|
|
|
2016-07-28 22:12:20 +02:00
|
|
|
"""
|
2017-03-06 23:01:35 +01:00
|
|
|
Resolve claim info from a LBRY name
|
2016-07-28 22:12:20 +02:00
|
|
|
|
|
|
|
Args:
|
|
|
|
'name': name to look up, string, do not include lbry:// prefix
|
2016-10-14 08:13:37 +02:00
|
|
|
'txid': optional, if specified, look for claim with this txid
|
|
|
|
'nout': optional, if specified, look for claim with this nout
|
2016-12-14 00:08:29 +01:00
|
|
|
|
2016-07-28 22:12:20 +02:00
|
|
|
Returns:
|
|
|
|
txid, amount, value, n, height
|
|
|
|
"""
|
|
|
|
|
2016-07-28 20:55:17 +02:00
|
|
|
def _convert_amount_to_float(r):
|
2016-08-09 03:32:39 +02:00
|
|
|
if not r:
|
|
|
|
return False
|
|
|
|
else:
|
2017-01-03 20:13:01 +01:00
|
|
|
r['amount'] = float(r['amount']) / 10 ** 8
|
2016-08-09 03:32:39 +02:00
|
|
|
return r
|
2016-07-28 20:55:17 +02:00
|
|
|
|
2016-10-14 08:13:37 +02:00
|
|
|
d = self.session.wallet.get_claim_info(name, txid, nout)
|
2016-07-28 20:55:17 +02:00
|
|
|
d.addCallback(_convert_amount_to_float)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2016-07-28 20:55:17 +02:00
|
|
|
return d
|
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2016-12-30 07:12:20 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-02-02 05:40:03 +01:00
|
|
|
def jsonrpc_get(
|
|
|
|
self, name, file_name=None, stream_info=None, timeout=None,
|
|
|
|
download_directory=None, wait_for_write=True):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
2017-03-06 23:01:35 +01:00
|
|
|
Download stream from a LBRY name.
|
2015-12-15 03:49:01 +01:00
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Args:
|
|
|
|
'name': name to download, string
|
2016-05-05 03:25:46 +02:00
|
|
|
'file_name': optional, a user specified name for the downloaded file
|
|
|
|
'stream_info': optional, specified stream info overrides name
|
2016-07-21 19:32:50 +02:00
|
|
|
'timeout': optional
|
2017-02-02 05:40:03 +01:00
|
|
|
'download_directory': optional, path to directory where file will be saved, string
|
2016-12-30 07:12:20 +01:00
|
|
|
'wait_for_write': optional, defaults to True. When set, waits for the file to
|
|
|
|
only start to be written before returning any results.
|
2016-04-13 20:47:34 +02:00
|
|
|
Returns:
|
2017-03-06 23:24:13 +01:00
|
|
|
{
|
|
|
|
'completed': bool,
|
|
|
|
'file_name': str,
|
|
|
|
'download_directory': str,
|
|
|
|
'points_paid': float,
|
|
|
|
'stopped': bool,
|
|
|
|
'stream_hash': str (hex),
|
|
|
|
'stream_name': str,
|
|
|
|
'suggested_file_name': str,
|
|
|
|
'sd_hash': str (hex),
|
|
|
|
'name': str,
|
|
|
|
'outpoint': str, (txid:nout)
|
|
|
|
'claim_id': str (hex),
|
|
|
|
'download_path': str,
|
|
|
|
'mime_type': str,
|
|
|
|
'key': str (hex),
|
|
|
|
'total_bytes': int
|
|
|
|
'written_bytes': int,
|
|
|
|
'message': str
|
|
|
|
'metadata': Metadata dict
|
|
|
|
}
|
2015-12-06 23:32:17 +01:00
|
|
|
"""
|
2017-02-20 01:22:21 +01:00
|
|
|
|
2017-02-02 05:40:03 +01:00
|
|
|
timeout = timeout if timeout is not None else self.download_timeout
|
|
|
|
download_directory = download_directory or self.download_directory
|
|
|
|
if name in self.waiting_on:
|
2017-03-06 23:24:13 +01:00
|
|
|
log.info("Already waiting on lbry://%s to start downloading", name)
|
|
|
|
yield self.streams[name].data_downloading_deferred
|
2016-12-30 19:24:52 +01:00
|
|
|
|
|
|
|
lbry_file = yield self._get_lbry_file(FileID.NAME, name, return_json=False)
|
2017-03-06 23:24:13 +01:00
|
|
|
|
2016-12-30 19:24:52 +01:00
|
|
|
if lbry_file:
|
2017-03-06 23:24:13 +01:00
|
|
|
if not os.path.isfile(os.path.join(lbry_file.download_directory, lbry_file.file_name)):
|
|
|
|
log.info("Already have lbry file but missing file in %s, rebuilding it",
|
|
|
|
lbry_file.download_directory)
|
|
|
|
yield lbry_file.start()
|
|
|
|
else:
|
|
|
|
log.info('Already have a file for %s', name)
|
|
|
|
result = yield self._get_lbry_file_dict(lbry_file, full_status=True)
|
|
|
|
else:
|
|
|
|
download_id = utils.random_string()
|
|
|
|
self.analytics_manager.send_download_started(download_id, name, stream_info)
|
2017-01-26 21:09:54 +01:00
|
|
|
try:
|
2017-03-06 23:24:13 +01:00
|
|
|
yield self._download_name(name=name, timeout=timeout,
|
|
|
|
download_directory=download_directory,
|
|
|
|
stream_info=stream_info, file_name=file_name,
|
|
|
|
wait_for_write=wait_for_write)
|
|
|
|
stream = self.streams[name]
|
|
|
|
stream.finished_deferred.addCallback(
|
|
|
|
lambda _: self.analytics_manager.send_download_finished(
|
|
|
|
download_id, name, stream_info)
|
2016-12-30 19:35:17 +01:00
|
|
|
)
|
2017-03-06 23:24:13 +01:00
|
|
|
result = yield self._get_lbry_file_dict(self.streams[name].downloader,
|
|
|
|
full_status=True)
|
2017-01-26 21:09:54 +01:00
|
|
|
except Exception as e:
|
2017-02-13 02:57:23 +01:00
|
|
|
log.warning('Failed to get %s', name)
|
2017-03-06 23:24:13 +01:00
|
|
|
self.analytics_manager.send_download_errored(download_id, name, stream_info)
|
|
|
|
result = e.message
|
|
|
|
response = yield self._render_response(result)
|
2016-12-30 07:12:20 +01:00
|
|
|
defer.returnValue(response)
|
2015-12-08 06:37:49 +01:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_stop_lbry_file(self, **kwargs):
|
2016-04-24 23:51:24 +02:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `file_seed status=stop` instead.
|
2016-04-24 23:51:24 +02:00
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_file_seed(status='stop', **kwargs)
|
2016-04-24 23:51:24 +02:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_start_lbry_file(self, **kwargs):
|
2016-04-24 23:51:24 +02:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `file_seed status=start` instead.
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_file_seed(status='start', **kwargs)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
|
|
|
@AuthJSONRPCServer.auth_required
|
|
|
|
@defer.inlineCallbacks
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_file_seed(self, status, **kwargs):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
Start or stop seeding a file
|
2016-04-24 23:51:24 +02:00
|
|
|
|
|
|
|
Args:
|
2017-01-03 20:13:01 +01:00
|
|
|
'status': "start" or "stop"
|
2017-03-06 23:24:13 +01:00
|
|
|
'name': start file by lbry name,
|
2017-01-03 20:13:01 +01:00
|
|
|
'sd_hash': start file by the hash in the name claim,
|
|
|
|
'file_name': start file by its name in the downloads folder,
|
2016-04-24 23:51:24 +02:00
|
|
|
Returns:
|
|
|
|
confirmation message
|
|
|
|
"""
|
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
if status not in ['start', 'stop']:
|
|
|
|
raise Exception('Status must be "start" or "stop".')
|
2016-04-24 23:51:24 +02:00
|
|
|
|
2017-02-02 05:40:03 +01:00
|
|
|
search_type, value = get_lbry_file_search_value(kwargs)
|
2017-01-03 20:13:01 +01:00
|
|
|
lbry_file = yield self._get_lbry_file(search_type, value, return_json=False)
|
|
|
|
if not lbry_file:
|
|
|
|
raise Exception('Unable to find a file for {}:{}'.format(search_type, value))
|
2016-04-24 23:51:24 +02:00
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
if status == 'start' and lbry_file.stopped or status == 'stop' and not lbry_file.stopped:
|
|
|
|
yield self.lbry_file_manager.toggle_lbry_file_running(lbry_file)
|
|
|
|
msg = "Started seeding file" if status == 'start' else "Stopped seeding file"
|
|
|
|
else:
|
2017-01-10 02:05:27 +01:00
|
|
|
msg = (
|
|
|
|
"File was already being seeded" if status == 'start' else "File was already stopped"
|
|
|
|
)
|
2017-01-11 18:35:01 +01:00
|
|
|
response = yield self._render_response(msg)
|
|
|
|
defer.returnValue(response)
|
2016-01-17 05:06:24 +01:00
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-03-06 23:19:05 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_file_delete(self, delete_target_file=True, **kwargs):
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
|
|
|
Delete a lbry file
|
2016-01-21 04:00:28 +01:00
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Args:
|
2017-03-06 23:19:05 +01:00
|
|
|
'name' (optional): delete files by lbry name,
|
|
|
|
'sd_hash' (optional): delete files by sd hash,
|
|
|
|
'file_name' (optional): delete files by the name in the downloads folder,
|
|
|
|
'stream_hash' (optional): delete files by stream hash,
|
|
|
|
'claim_id' (optional): delete files by claim id,
|
|
|
|
'outpoint' (optional): delete files by claim outpoint,
|
|
|
|
'rowid': (optional): delete file by rowid in the file manager
|
|
|
|
'delete_target_file' (optional): delete file from downloads folder, defaults to True
|
|
|
|
if False only the blobs and db entries will be deleted
|
2016-04-13 20:47:34 +02:00
|
|
|
Returns:
|
2017-03-06 23:19:05 +01:00
|
|
|
True if deletion was successful, otherwise False
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2016-01-21 04:00:28 +01:00
|
|
|
|
2017-03-06 23:19:05 +01:00
|
|
|
searchtype, value = get_lbry_file_search_value(kwargs)
|
2017-03-08 00:18:47 +01:00
|
|
|
lbry_files = yield self._get_lbry_files(searchtype, value, return_json=False)
|
|
|
|
if len(lbry_files) > 1:
|
|
|
|
log.warning("There are %i files to delete, use narrower filters to select one",
|
|
|
|
len(lbry_files))
|
|
|
|
result = False
|
|
|
|
elif not lbry_files:
|
2017-03-06 23:19:05 +01:00
|
|
|
log.warning("There is no file to delete for '%s'", value)
|
|
|
|
result = False
|
2016-10-20 21:52:37 +02:00
|
|
|
else:
|
2017-03-08 00:18:47 +01:00
|
|
|
lbry_file = lbry_files[0]
|
2017-03-06 23:19:05 +01:00
|
|
|
file_name, stream_hash = lbry_file.file_name, lbry_file.stream_hash
|
|
|
|
if lbry_file.claim_id in self.streams:
|
|
|
|
del self.streams[lbry_file.claim_id]
|
|
|
|
yield self.lbry_file_manager.delete_lbry_file(lbry_file,
|
|
|
|
delete_file=delete_target_file)
|
|
|
|
log.info("Deleted %s (%s)", file_name, utils.short_hash(stream_hash))
|
|
|
|
result = True
|
|
|
|
response = yield self._render_response(result)
|
|
|
|
defer.returnValue(response)
|
2016-04-24 23:51:24 +02:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_get_est_cost(self, **kwargs):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `stream_cost_estimate` instead
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_stream_cost_estimate(**kwargs)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2017-02-11 16:33:06 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_stream_cost_estimate(self, name, size=None):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
Get estimated cost for a lbry stream
|
|
|
|
|
|
|
|
Args:
|
2017-03-06 23:01:35 +01:00
|
|
|
'name': lbry name
|
2017-01-03 20:13:01 +01:00
|
|
|
'size': stream size, in bytes. if provided an sd blob won't be downloaded.
|
|
|
|
Returns:
|
|
|
|
estimated cost
|
|
|
|
"""
|
2017-02-11 16:33:06 +01:00
|
|
|
cost = yield self.get_est_cost(name, size)
|
|
|
|
defer.returnValue(cost)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-02-09 22:12:30 +01:00
|
|
|
def jsonrpc_publish(self, name, bid, metadata, file_path=None, fee=None):
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2016-06-27 23:07:59 +02:00
|
|
|
Make a new name claim and publish associated data to lbrynet
|
2016-01-21 04:00:28 +01:00
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Args:
|
2017-02-09 22:12:30 +01:00
|
|
|
'name': str, name to be claimed, string
|
|
|
|
'bid': float, amount of credits to commit in this claim,
|
|
|
|
'metadata': dict, Metadata compliant (can be missing sources if a file is provided)
|
|
|
|
'file_path' (optional): str, path to file to be associated with name, if not given
|
|
|
|
the stream from your existing claim for the name will be used
|
|
|
|
'fee' (optional): dict, FeeValidator compliant
|
2016-04-13 20:47:34 +02:00
|
|
|
Returns:
|
2017-03-08 16:39:31 +01:00
|
|
|
'tx' : hex encoded transaction
|
|
|
|
'txid' : txid of resulting transaction
|
|
|
|
'nout' : nout of the resulting support claim
|
|
|
|
'fee' : fee paid for the claim transaction
|
2017-01-13 18:19:26 +01:00
|
|
|
'claim_id' : claim id of the resulting transaction
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2016-07-25 07:40:26 +02:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
log.info("Publish: %s", {
|
|
|
|
'name': name,
|
|
|
|
'file_path': file_path,
|
|
|
|
'bid': bid,
|
|
|
|
'metadata': metadata,
|
|
|
|
'fee': fee,
|
|
|
|
})
|
|
|
|
|
2017-02-09 22:12:30 +01:00
|
|
|
d = self._publish_stream(name, bid, metadata, file_path, fee)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2016-01-21 04:00:28 +01:00
|
|
|
return d
|
2015-12-06 23:32:17 +01:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_abandon_claim(self, **kwargs):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `claim_abandon` instead
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_claim_abandon(**kwargs)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-02-13 20:17:53 +01:00
|
|
|
@defer.inlineCallbacks
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_claim_abandon(self, txid, nout):
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2016-04-13 20:47:34 +02:00
|
|
|
Abandon a name and reclaim credits from the claim
|
2016-12-09 04:05:31 +01:00
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Args:
|
|
|
|
'txid': txid of claim, string
|
2016-10-14 08:13:37 +02:00
|
|
|
'nout': nout of claim, integer
|
2016-04-13 20:47:34 +02:00
|
|
|
Return:
|
2016-10-14 08:13:37 +02:00
|
|
|
txid : txid of resulting transaction if succesful
|
2016-11-28 20:23:10 +01:00
|
|
|
fee : fee paid for the transaction if succesful
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2016-01-26 02:28:05 +01:00
|
|
|
|
2017-02-13 20:17:53 +01:00
|
|
|
try:
|
|
|
|
abandon_claim_tx = yield self.session.wallet.abandon_claim(txid, nout)
|
|
|
|
response = yield self._render_response(abandon_claim_tx)
|
|
|
|
except Exception as err:
|
|
|
|
log.warning(err)
|
|
|
|
response = yield self._render_response(err)
|
|
|
|
defer.returnValue(response)
|
2016-01-26 02:28:05 +01:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_abandon_name(self, **kwargs):
|
2016-09-15 04:36:18 +02:00
|
|
|
"""
|
|
|
|
DEPRECIATED, use abandon_claim
|
|
|
|
|
|
|
|
Args:
|
|
|
|
'txid': txid of claim, string
|
|
|
|
Return:
|
|
|
|
txid
|
|
|
|
"""
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_abandon_claim(**kwargs)
|
2016-09-15 04:36:18 +02:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_support_claim(self, **kwargs):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `claim_abandon` instead
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_claim_new_support(**kwargs)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_claim_new_support(self, name, claim_id, amount):
|
2016-08-08 08:32:56 +02:00
|
|
|
"""
|
|
|
|
Support a name claim
|
|
|
|
|
|
|
|
Args:
|
|
|
|
'name': name
|
|
|
|
'claim_id': claim id of claim to support
|
|
|
|
'amount': amount to support by
|
|
|
|
Return:
|
2016-10-14 08:13:37 +02:00
|
|
|
txid : txid of resulting transaction if succesful
|
|
|
|
nout : nout of the resulting support claim if succesful
|
2016-11-30 21:20:45 +01:00
|
|
|
fee : fee paid for the transaction if succesful
|
2016-08-08 08:32:56 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
d = self.session.wallet.support_claim(name, claim_id, amount)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2016-08-08 08:32:56 +02:00
|
|
|
return d
|
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
# TODO: merge this into claim_list
|
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_get_my_claim(self, name):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. This method will be removed in a future release.
|
|
|
|
|
|
|
|
Return existing claim for a given name
|
|
|
|
|
|
|
|
Args:
|
|
|
|
'name': name to look up
|
|
|
|
Returns:
|
|
|
|
claim info, False if no such claim exists
|
|
|
|
"""
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
d = self.session.wallet.get_my_claim(name)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2017-01-03 20:13:01 +01:00
|
|
|
return d
|
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2016-03-24 03:27:48 +01:00
|
|
|
def jsonrpc_get_name_claims(self):
|
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `claim_list_mine` instead
|
|
|
|
"""
|
|
|
|
return self.jsonrpc_claim_list_mine()
|
|
|
|
|
|
|
|
# TODO: claim_list_mine should be merged into claim_list, but idk how to authenticate it -Grin
|
|
|
|
@AuthJSONRPCServer.auth_required
|
|
|
|
def jsonrpc_claim_list_mine(self):
|
|
|
|
"""
|
|
|
|
List my name claims
|
2016-03-24 03:27:48 +01:00
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Args:
|
|
|
|
None
|
|
|
|
Returns
|
|
|
|
list of name claims
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2016-04-13 20:47:34 +02:00
|
|
|
|
2016-01-26 02:28:05 +01:00
|
|
|
def _clean(claims):
|
|
|
|
for c in claims:
|
|
|
|
for k in c.keys():
|
2016-02-11 14:32:48 +01:00
|
|
|
if isinstance(c[k], Decimal):
|
2016-01-26 02:28:05 +01:00
|
|
|
c[k] = float(c[k])
|
2016-03-29 22:42:47 +02:00
|
|
|
return defer.succeed(claims)
|
2016-01-26 02:28:05 +01:00
|
|
|
|
|
|
|
d = self.session.wallet.get_name_claims()
|
|
|
|
d.addCallback(_clean)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda claims: self._render_response(claims))
|
2016-01-26 02:28:05 +01:00
|
|
|
return d
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_get_claims_for_name(self, **kwargs):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `claim_list` instead.
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_claim_list(**kwargs)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_get_claims_for_tx(self, **kwargs):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `claim_list` instead.
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_claim_list(**kwargs)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_claim_list(self, name=None, txid=None):
|
2016-08-08 07:43:10 +02:00
|
|
|
"""
|
|
|
|
Get claims for a name
|
|
|
|
|
|
|
|
Args:
|
2017-01-03 20:13:01 +01:00
|
|
|
name: file name
|
|
|
|
txid: transaction id of a name claim transaction
|
2016-08-08 07:43:10 +02:00
|
|
|
Returns
|
|
|
|
list of name claims
|
|
|
|
"""
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
if name is not None:
|
|
|
|
d = self.session.wallet.get_claims_for_name(name)
|
|
|
|
elif txid is not None:
|
|
|
|
d = self.session.wallet.get_claims_from_tx(txid)
|
2017-01-03 20:13:01 +01:00
|
|
|
else:
|
|
|
|
return server.failure
|
|
|
|
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2016-08-08 07:43:10 +02:00
|
|
|
return d
|
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2016-04-18 05:23:20 +02:00
|
|
|
def jsonrpc_get_transaction_history(self):
|
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `transaction_list` instead
|
|
|
|
"""
|
|
|
|
return self.jsonrpc_transaction_list()
|
|
|
|
|
|
|
|
@AuthJSONRPCServer.auth_required
|
|
|
|
def jsonrpc_transaction_list(self):
|
|
|
|
"""
|
|
|
|
List transactions
|
2016-04-18 05:23:20 +02:00
|
|
|
|
|
|
|
Args:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
list of transactions
|
|
|
|
"""
|
|
|
|
|
|
|
|
d = self.session.wallet.get_history()
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2016-04-18 05:23:20 +02:00
|
|
|
return d
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_get_transaction(self, txid):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `transaction_show` instead
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_transaction_show(txid)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_transaction_show(self, txid):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
Get a decoded transaction from a txid
|
|
|
|
|
|
|
|
Args:
|
|
|
|
txid: txid hex string
|
|
|
|
Returns:
|
|
|
|
JSON formatted transaction
|
|
|
|
"""
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
d = self.session.wallet.get_transaction(txid)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2017-01-03 20:13:01 +01:00
|
|
|
return d
|
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_address_is_mine(self, address):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `wallet_is_address_mine` instead
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_wallet_is_address_mine(address)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_wallet_is_address_mine(self, address):
|
2016-09-02 07:27:30 +02:00
|
|
|
"""
|
|
|
|
Checks if an address is associated with the current wallet.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
address: string
|
|
|
|
Returns:
|
|
|
|
is_mine: bool
|
|
|
|
"""
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
d = self.session.wallet.address_is_mine(address)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda is_mine: self._render_response(is_mine))
|
2016-09-02 07:27:30 +02:00
|
|
|
return d
|
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_get_public_key_from_wallet(self, wallet):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `wallet_is_address_mine` instead
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_wallet_public_key(wallet)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_wallet_public_key(self, wallet):
|
2016-04-18 05:23:20 +02:00
|
|
|
"""
|
|
|
|
Get public key from wallet address
|
|
|
|
|
|
|
|
Args:
|
|
|
|
wallet: wallet address, base58
|
|
|
|
Returns:
|
|
|
|
public key
|
|
|
|
"""
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
d = self.session.wallet.get_pub_keys(wallet)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2016-04-18 05:23:20 +02:00
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
@AuthJSONRPCServer.auth_required
|
|
|
|
def jsonrpc_get_new_address(self):
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `wallet_new_address` instead
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
return self.jsonrpc_wallet_new_address()
|
2016-01-26 02:28:05 +01:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-03 20:13:01 +01:00
|
|
|
def jsonrpc_wallet_new_address(self):
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
|
|
|
Generate a new wallet address
|
|
|
|
|
2016-04-13 20:47:34 +02:00
|
|
|
Args:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
new wallet address, base 58 string
|
2016-03-24 03:27:48 +01:00
|
|
|
"""
|
2016-04-13 20:47:34 +02:00
|
|
|
|
2016-02-25 23:17:07 +01:00
|
|
|
def _disp(address):
|
2016-07-16 08:15:58 +02:00
|
|
|
log.info("Got new wallet address: " + address)
|
2016-03-29 22:42:47 +02:00
|
|
|
return defer.succeed(address)
|
2016-02-25 23:17:07 +01:00
|
|
|
|
|
|
|
d = self.session.wallet.get_new_address()
|
|
|
|
d.addCallback(_disp)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda address: self._render_response(address))
|
2016-02-25 23:17:07 +01:00
|
|
|
return d
|
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_send_amount_to_address(self, amount, address):
|
2016-05-04 05:13:31 +02:00
|
|
|
"""
|
|
|
|
Send credits to an address
|
|
|
|
|
|
|
|
Args:
|
|
|
|
amount: the amount to send
|
|
|
|
address: the address of the recipient
|
|
|
|
Returns:
|
|
|
|
True if payment successfully scheduled
|
|
|
|
"""
|
|
|
|
|
|
|
|
reserved_points = self.session.wallet.reserve_points(address, amount)
|
|
|
|
if reserved_points is None:
|
|
|
|
return defer.fail(InsufficientFundsError())
|
|
|
|
d = self.session.wallet.send_points_to_address(reserved_points, amount)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda _: self._render_response(True))
|
2016-05-04 05:13:31 +02:00
|
|
|
return d
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_get_block(self, **kwargs):
|
2016-05-04 05:13:31 +02:00
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `block_show` instead
|
2016-05-04 05:13:31 +02:00
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_block_show(**kwargs)
|
2016-05-04 05:13:31 +02:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_block_show(self, blockhash=None, height=None):
|
2016-05-04 05:13:31 +02:00
|
|
|
"""
|
|
|
|
Get contents of a block
|
|
|
|
|
|
|
|
Args:
|
|
|
|
blockhash: hash of the block to look up
|
|
|
|
Returns:
|
|
|
|
requested block
|
|
|
|
"""
|
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
if blockhash is not None:
|
|
|
|
d = self.session.wallet.get_block(blockhash)
|
|
|
|
elif height is not None:
|
|
|
|
d = self.session.wallet.get_block_info(height)
|
|
|
|
d.addCallback(lambda b: self.session.wallet.get_block(b))
|
2016-05-04 05:13:31 +02:00
|
|
|
else:
|
2016-12-30 07:12:20 +01:00
|
|
|
# TODO: return a useful error message
|
2016-05-04 05:13:31 +02:00
|
|
|
return server.failure
|
2017-01-26 02:06:17 +01:00
|
|
|
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2016-05-04 05:13:31 +02:00
|
|
|
return d
|
|
|
|
|
2017-01-03 20:13:01 +01:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_download_descriptor(self, **kwargs):
|
2016-05-04 05:13:31 +02:00
|
|
|
"""
|
2017-02-16 05:39:17 +01:00
|
|
|
DEPRECATED. Use `descriptor_get` instead
|
2016-05-04 05:13:31 +02:00
|
|
|
"""
|
2017-02-16 05:39:17 +01:00
|
|
|
return self.jsonrpc_descriptor_get(**kwargs)
|
2016-05-04 05:13:31 +02:00
|
|
|
|
2016-10-19 06:12:44 +02:00
|
|
|
@AuthJSONRPCServer.auth_required
|
2017-02-16 05:39:17 +01:00
|
|
|
@defer.inlineCallbacks
|
|
|
|
def jsonrpc_descriptor_get(self, sd_hash, timeout=None, payment_rate_manager=None):
|
2016-08-02 04:31:49 +02:00
|
|
|
"""
|
|
|
|
Download and return a sd blob
|
|
|
|
|
|
|
|
Args:
|
|
|
|
sd_hash
|
2017-01-26 02:06:17 +01:00
|
|
|
timeout (optional)
|
2017-02-16 05:39:17 +01:00
|
|
|
payment_rate_manager (optional): if not given the default payment rate manager
|
|
|
|
will be used. supported alternative rate managers:
|
|
|
|
only-free
|
|
|
|
|
2016-08-02 04:31:49 +02:00
|
|
|
Returns
|
2017-02-16 05:39:17 +01:00
|
|
|
Success/Fail message or decoded data
|
2016-08-02 04:31:49 +02:00
|
|
|
"""
|
2017-02-16 05:39:17 +01:00
|
|
|
|
|
|
|
payment_rate_manager = get_blob_payment_rate_manager(self.session, payment_rate_manager)
|
|
|
|
decoded_sd_blob = yield self._download_sd_blob(sd_hash, payment_rate_manager,
|
|
|
|
timeout=timeout)
|
|
|
|
result = yield self._render_response(decoded_sd_blob)
|
|
|
|
defer.returnValue(result)
|
|
|
|
|
|
|
|
@AuthJSONRPCServer.auth_required
|
|
|
|
@defer.inlineCallbacks
|
|
|
|
def jsonrpc_blob_get(self, blob_hash, timeout=None, encoding=None, payment_rate_manager=None):
|
|
|
|
"""
|
|
|
|
Download and return a blob
|
|
|
|
|
|
|
|
Args:
|
|
|
|
blob_hash
|
|
|
|
timeout (optional)
|
|
|
|
encoding (optional): by default no attempt at decoding is made
|
|
|
|
can be set to one of the following decoders:
|
|
|
|
json
|
|
|
|
payment_rate_manager (optional): if not given the default payment rate manager
|
|
|
|
will be used. supported alternative rate managers:
|
|
|
|
only-free
|
|
|
|
|
|
|
|
Returns
|
|
|
|
Success/Fail message or decoded data
|
|
|
|
"""
|
|
|
|
|
|
|
|
decoders = {
|
|
|
|
'json': json.loads
|
|
|
|
}
|
|
|
|
|
|
|
|
timeout = timeout or 30
|
|
|
|
payment_rate_manager = get_blob_payment_rate_manager(self.session, payment_rate_manager)
|
|
|
|
blob = yield self._download_blob(blob_hash, rate_manager=payment_rate_manager,
|
|
|
|
timeout=timeout)
|
|
|
|
if encoding and encoding in decoders:
|
|
|
|
blob_file = blob.open_for_reading()
|
|
|
|
result = decoders[encoding](blob_file.read())
|
|
|
|
blob.close_read_handle(blob_file)
|
|
|
|
else:
|
|
|
|
result = "Downloaded blob %s" % blob_hash
|
|
|
|
|
|
|
|
response = yield self._render_response(result)
|
|
|
|
defer.returnValue(response)
|
|
|
|
|
|
|
|
@AuthJSONRPCServer.auth_required
|
|
|
|
@defer.inlineCallbacks
|
|
|
|
def jsonrpc_blob_delete(self, blob_hash):
|
|
|
|
"""
|
|
|
|
Delete a blob
|
|
|
|
|
|
|
|
Args:
|
|
|
|
blob_hash
|
|
|
|
Returns:
|
|
|
|
Success/fail message
|
|
|
|
"""
|
|
|
|
|
|
|
|
if blob_hash not in self.session.blob_manager.blobs:
|
|
|
|
response = yield self._render_response("Don't have that blob")
|
|
|
|
defer.returnValue(response)
|
|
|
|
try:
|
|
|
|
stream_hash = yield self.stream_info_manager.get_stream_hash_for_sd_hash(blob_hash)
|
|
|
|
yield self.stream_info_manager.delete_stream(stream_hash)
|
|
|
|
except Exception as err:
|
|
|
|
pass
|
|
|
|
yield self.session.blob_manager.delete_blobs([blob_hash])
|
|
|
|
response = yield self._render_response("Deleted %s" % blob_hash)
|
|
|
|
defer.returnValue(response)
|
2016-05-04 05:13:31 +02:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_get_peers_for_hash(self, blob_hash):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `peer_list` instead
|
|
|
|
"""
|
2017-01-26 02:06:17 +01:00
|
|
|
return self.jsonrpc_peer_list(blob_hash)
|
2017-01-03 20:13:01 +01:00
|
|
|
|
2017-02-16 05:38:33 +01:00
|
|
|
def jsonrpc_peer_list(self, blob_hash, timeout=None):
|
2016-08-03 09:16:06 +02:00
|
|
|
"""
|
|
|
|
Get peers for blob hash
|
|
|
|
|
|
|
|
Args:
|
|
|
|
'blob_hash': blob hash
|
2017-02-16 05:38:33 +01:00
|
|
|
'timeout' (int, optional): peer search timeout
|
2016-08-03 09:16:06 +02:00
|
|
|
Returns:
|
|
|
|
List of contacts
|
|
|
|
"""
|
|
|
|
|
2017-02-16 05:38:33 +01:00
|
|
|
timeout = timeout or conf.settings['peer_search_timeout']
|
|
|
|
|
|
|
|
d = self.session.peer_finder.find_peers_for_blob(blob_hash, timeout=timeout)
|
2016-08-03 09:16:06 +02:00
|
|
|
d.addCallback(lambda r: [[c.host, c.port, c.is_available()] for c in r])
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2016-08-03 09:16:06 +02:00
|
|
|
return d
|
|
|
|
|
2016-08-11 18:36:13 +02:00
|
|
|
def jsonrpc_announce_all_blobs_to_dht(self):
|
|
|
|
"""
|
2017-01-03 20:13:01 +01:00
|
|
|
DEPRECATED. Use `blob_announce_all` instead.
|
|
|
|
"""
|
|
|
|
return self.jsonrpc_blob_announce_all()
|
|
|
|
|
|
|
|
def jsonrpc_blob_announce_all(self):
|
|
|
|
"""
|
|
|
|
Announce all blobs to the DHT
|
2016-08-11 18:36:13 +02:00
|
|
|
|
|
|
|
Args:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
d = self.session.blob_manager.immediate_announce_all_blobs()
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda _: self._render_response("Announced"))
|
2016-08-11 18:36:13 +02:00
|
|
|
return d
|
2016-08-11 18:38:10 +02:00
|
|
|
|
2017-01-26 02:06:17 +01:00
|
|
|
def jsonrpc_reflect(self, sd_hash):
|
2016-08-18 03:33:41 +02:00
|
|
|
"""
|
|
|
|
Reflect a stream
|
|
|
|
|
|
|
|
Args:
|
2016-08-27 01:58:53 +02:00
|
|
|
sd_hash: sd_hash of lbry file
|
2016-08-18 03:33:41 +02:00
|
|
|
Returns:
|
|
|
|
True or traceback
|
|
|
|
"""
|
|
|
|
|
2016-10-20 21:52:37 +02:00
|
|
|
d = self._get_lbry_file(FileID.SD_HASH, sd_hash, return_json=False)
|
2016-08-18 03:33:41 +02:00
|
|
|
d.addCallback(self._reflect)
|
2016-10-27 20:28:56 +02:00
|
|
|
d.addCallbacks(
|
2017-01-07 01:21:25 +01:00
|
|
|
lambda _: self._render_response(True),
|
|
|
|
lambda err: self._render_response(err.getTraceback()))
|
2016-08-18 03:33:41 +02:00
|
|
|
return d
|
|
|
|
|
2016-08-26 06:32:33 +02:00
|
|
|
def jsonrpc_get_blob_hashes(self):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `blob_list` instead
|
|
|
|
"""
|
|
|
|
return self.jsonrpc_blob_list()
|
|
|
|
|
2017-02-16 05:39:17 +01:00
|
|
|
@defer.inlineCallbacks
|
|
|
|
def jsonrpc_blob_list(self, uri=None, stream_hash=None, sd_hash=None, needed=None,
|
|
|
|
finished=None, page_size=None, page=None):
|
2016-08-19 08:41:23 +02:00
|
|
|
"""
|
2017-02-16 05:39:17 +01:00
|
|
|
Returns blob hashes, if not given filters returns all blobs known by the blob manager
|
2016-08-26 06:32:33 +02:00
|
|
|
|
|
|
|
Args:
|
2017-02-16 05:39:17 +01:00
|
|
|
uri (str, optional): filter by blobs in stream for winning claim
|
|
|
|
stream_hash (str, optional): filter by blobs in given stream hash
|
|
|
|
sd_hash (str, optional): filter by blobs in given sd hash
|
|
|
|
needed (bool, optional): only return needed blobs
|
|
|
|
finished (bool, optional): only return finished blobs
|
|
|
|
page_size (int, optional): limit number of results returned
|
|
|
|
page (int, optional): filter to page x of [page_size] results
|
2016-08-26 06:32:33 +02:00
|
|
|
Returns:
|
|
|
|
list of blob hashes
|
2016-08-19 08:41:23 +02:00
|
|
|
"""
|
|
|
|
|
2017-02-16 05:39:17 +01:00
|
|
|
if uri:
|
|
|
|
metadata = yield self._resolve_name(uri)
|
2017-03-06 23:01:35 +01:00
|
|
|
sd_hash = utils.get_sd_hash(metadata)
|
2017-02-16 05:39:17 +01:00
|
|
|
blobs = yield self.get_blobs_for_sd_hash(sd_hash)
|
|
|
|
elif stream_hash:
|
|
|
|
try:
|
|
|
|
blobs = yield self.get_blobs_for_stream_hash(stream_hash)
|
|
|
|
except NoSuchStreamHash:
|
|
|
|
blobs = []
|
|
|
|
elif sd_hash:
|
|
|
|
try:
|
|
|
|
blobs = yield self.get_blobs_for_sd_hash(sd_hash)
|
|
|
|
except NoSuchSDHash:
|
|
|
|
blobs = []
|
|
|
|
else:
|
|
|
|
blobs = self.session.blob_manager.blobs.itervalues()
|
|
|
|
|
|
|
|
if needed:
|
|
|
|
blobs = [blob for blob in blobs if not blob.is_validated()]
|
|
|
|
if finished:
|
|
|
|
blobs = [blob for blob in blobs if blob.is_validated()]
|
|
|
|
|
|
|
|
blob_hashes = [blob.blob_hash for blob in blobs]
|
|
|
|
page_size = page_size or len(blob_hashes)
|
|
|
|
page = page or 0
|
|
|
|
start_index = page * page_size
|
|
|
|
stop_index = start_index + page_size
|
|
|
|
blob_hashes_for_return = blob_hashes[start_index:stop_index]
|
|
|
|
response = yield self._render_response(blob_hashes_for_return)
|
|
|
|
defer.returnValue(response)
|
2016-08-27 01:58:53 +02:00
|
|
|
|
|
|
|
def jsonrpc_reflect_all_blobs(self):
|
2017-01-03 20:13:01 +01:00
|
|
|
"""
|
|
|
|
DEPRECATED. Use `blob_reflect_all` instead
|
|
|
|
"""
|
|
|
|
return self.jsonrpc_blob_reflect_all()
|
|
|
|
|
|
|
|
def jsonrpc_blob_reflect_all(self):
|
2016-08-27 01:58:53 +02:00
|
|
|
"""
|
|
|
|
Reflects all saved blobs
|
|
|
|
|
|
|
|
Args:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
True
|
|
|
|
"""
|
|
|
|
|
|
|
|
d = self.session.blob_manager.get_all_verified_blobs()
|
2017-02-10 16:56:22 +01:00
|
|
|
d.addCallback(reupload.reflect_blob_hashes, self.session.blob_manager)
|
2017-01-07 01:21:25 +01:00
|
|
|
d.addCallback(lambda r: self._render_response(r))
|
2016-08-19 08:41:23 +02:00
|
|
|
return d
|
|
|
|
|
2017-02-16 05:38:33 +01:00
|
|
|
@defer.inlineCallbacks
|
|
|
|
def jsonrpc_get_availability(self, name, sd_timeout=None, peer_timeout=None):
|
2016-09-30 19:28:01 +02:00
|
|
|
"""
|
|
|
|
Get stream availability for a winning claim
|
|
|
|
|
|
|
|
Arg:
|
2017-03-06 23:01:35 +01:00
|
|
|
name (str): lbry name
|
2017-02-16 05:38:33 +01:00
|
|
|
sd_timeout (int, optional): sd blob download timeout
|
|
|
|
peer_timeout (int, optional): how long to look for peers
|
2016-09-30 19:28:01 +02:00
|
|
|
|
|
|
|
Returns:
|
|
|
|
peers per blob / total blobs
|
|
|
|
"""
|
|
|
|
|
|
|
|
def _get_mean(blob_availabilities):
|
|
|
|
peer_counts = []
|
|
|
|
for blob_availability in blob_availabilities:
|
|
|
|
for blob, peers in blob_availability.iteritems():
|
|
|
|
peer_counts.append(peers)
|
2016-09-30 19:35:13 +02:00
|
|
|
if peer_counts:
|
|
|
|
return round(1.0 * sum(peer_counts) / len(peer_counts), 2)
|
|
|
|
else:
|
|
|
|
return 0.0
|
2016-09-30 19:28:01 +02:00
|
|
|
|
2017-02-16 05:38:33 +01:00
|
|
|
def read_sd_blob(sd_blob):
|
|
|
|
sd_blob_file = sd_blob.open_for_reading()
|
|
|
|
decoded_sd_blob = json.loads(sd_blob_file.read())
|
|
|
|
sd_blob.close_read_handle(sd_blob_file)
|
2017-02-16 05:39:17 +01:00
|
|
|
return decoded_sd_blob
|
2016-09-30 19:28:01 +02:00
|
|
|
|
2017-02-16 05:38:33 +01:00
|
|
|
metadata = yield self._resolve_name(name)
|
2017-03-06 23:01:35 +01:00
|
|
|
sd_hash = utils.get_sd_hash(metadata)
|
2017-02-16 05:38:33 +01:00
|
|
|
sd_timeout = sd_timeout or conf.settings['sd_download_timeout']
|
|
|
|
peer_timeout = peer_timeout or conf.settings['peer_search_timeout']
|
|
|
|
blobs = []
|
|
|
|
try:
|
|
|
|
blobs = yield self.get_blobs_for_sd_hash(sd_hash)
|
|
|
|
need_sd_blob = False
|
|
|
|
log.info("Already have sd blob")
|
|
|
|
except NoSuchSDHash:
|
|
|
|
need_sd_blob = True
|
|
|
|
log.info("Need sd blob")
|
|
|
|
blob_hashes = [blob.blob_hash for blob in blobs]
|
|
|
|
if need_sd_blob:
|
|
|
|
# we don't want to use self._download_descriptor here because it would create a stream
|
2017-02-20 01:26:48 +01:00
|
|
|
try:
|
|
|
|
sd_blob = yield self._download_blob(sd_hash, timeout=sd_timeout)
|
|
|
|
except Exception as err:
|
|
|
|
response = yield self._render_response(0.0)
|
|
|
|
defer.returnValue(response)
|
2017-02-16 05:38:33 +01:00
|
|
|
decoded = read_sd_blob(sd_blob)
|
|
|
|
blob_hashes = [blob.get("blob_hash") for blob in decoded['blobs']
|
|
|
|
if blob.get("blob_hash")]
|
|
|
|
sample = random.sample(blob_hashes, min(len(blob_hashes), 5))
|
|
|
|
log.info("check peers for %i of %i blobs in stream", len(sample), len(blob_hashes))
|
|
|
|
availabilities = yield self.session.blob_tracker.get_availability_for_blobs(sample,
|
|
|
|
peer_timeout)
|
|
|
|
mean_availability = _get_mean(availabilities)
|
|
|
|
response = yield self._render_response(mean_availability)
|
|
|
|
defer.returnValue(response)
|
2016-09-30 19:28:01 +02:00
|
|
|
|
2017-01-09 22:24:47 +01:00
|
|
|
def jsonrpc_get_start_notice(self):
|
|
|
|
"""
|
|
|
|
DEPRECATED.
|
|
|
|
|
|
|
|
Get special message to be displayed at startup
|
|
|
|
Args:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Startup message, such as first run notification
|
|
|
|
"""
|
|
|
|
|
2017-01-12 16:55:38 +01:00
|
|
|
def _get_startup_message(status):
|
2017-01-09 22:24:47 +01:00
|
|
|
if status['is_first_run'] and self.session.wallet.wallet_balance:
|
|
|
|
return self._render_response(None)
|
|
|
|
else:
|
|
|
|
return self._render_response(status['startup_status']['message'])
|
|
|
|
|
|
|
|
d = self.jsonrpc_status()
|
|
|
|
d.addCallback(_get_startup_message)
|
|
|
|
return d
|
|
|
|
|
|
|
|
|
2016-07-21 17:44:59 +02:00
|
|
|
def get_sd_hash(stream_info):
|
|
|
|
if not stream_info:
|
|
|
|
return None
|
2017-02-20 01:17:25 +01:00
|
|
|
return stream_info['sources']['lbry_sd_hash']
|
2016-07-21 17:44:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
class _DownloadNameHelper(object):
|
2017-02-13 02:57:23 +01:00
|
|
|
def __init__(self, daemon, name, timeout=None, download_directory=None, file_name=None,
|
2016-11-30 21:20:45 +01:00
|
|
|
wait_for_write=True):
|
2016-07-21 17:44:59 +02:00
|
|
|
self.daemon = daemon
|
|
|
|
self.name = name
|
2017-01-17 04:23:20 +01:00
|
|
|
self.timeout = timeout if timeout is not None else conf.settings['download_timeout']
|
2016-07-21 17:44:59 +02:00
|
|
|
if not download_directory or not os.path.isdir(download_directory):
|
|
|
|
self.download_directory = daemon.download_directory
|
|
|
|
else:
|
|
|
|
self.download_directory = download_directory
|
|
|
|
self.file_name = file_name
|
|
|
|
self.wait_for_write = wait_for_write
|
|
|
|
|
2016-12-30 07:12:20 +01:00
|
|
|
@defer.inlineCallbacks
|
2016-12-30 04:48:12 +01:00
|
|
|
def setup_stream(self, stream_info):
|
2016-12-30 07:12:20 +01:00
|
|
|
sd_hash = get_sd_hash(stream_info)
|
2017-03-08 17:53:22 +01:00
|
|
|
lbry_file = yield self.daemon._get_lbry_file(FileID.SD_HASH, sd_hash, return_json=False)
|
2016-12-30 07:12:20 +01:00
|
|
|
if self._does_lbry_file_exists(lbry_file):
|
|
|
|
defer.returnValue(lbry_file)
|
|
|
|
else:
|
|
|
|
defer.returnValue(None)
|
2016-07-21 17:44:59 +02:00
|
|
|
|
2016-12-30 07:12:20 +01:00
|
|
|
def _does_lbry_file_exists(self, lbry_file):
|
|
|
|
return lbry_file and os.path.isfile(self._full_path(lbry_file))
|
|
|
|
|
|
|
|
def _full_path(self, lbry_file):
|
|
|
|
return os.path.join(self.download_directory, lbry_file.file_name)
|
2016-07-21 18:05:06 +02:00
|
|
|
|
2016-12-30 07:12:20 +01:00
|
|
|
@defer.inlineCallbacks
|
|
|
|
def wait_or_get_stream(self, stream_info, lbry_file):
|
2016-07-21 17:44:59 +02:00
|
|
|
if lbry_file:
|
2016-08-11 20:41:42 +02:00
|
|
|
log.debug('Wait on lbry_file')
|
2016-12-30 07:12:20 +01:00
|
|
|
# returns the lbry_file
|
|
|
|
yield self._wait_on_lbry_file(lbry_file)
|
|
|
|
defer.returnValue((lbry_file.sd_hash, self._full_path(lbry_file)))
|
2016-07-21 18:05:06 +02:00
|
|
|
else:
|
2016-08-11 20:41:42 +02:00
|
|
|
log.debug('No lbry_file, need to get stream')
|
2016-12-30 07:12:20 +01:00
|
|
|
# returns an instance of ManagedEncryptedFileDownloaderFactory
|
|
|
|
sd_hash, file_path = yield self._get_stream(stream_info)
|
|
|
|
defer.returnValue((sd_hash, file_path))
|
2016-07-21 17:44:59 +02:00
|
|
|
|
2016-12-30 07:12:20 +01:00
|
|
|
def _wait_on_lbry_file(self, f):
|
|
|
|
file_path = self._full_path(f)
|
|
|
|
written_bytes = self._get_written_bytes(file_path)
|
|
|
|
if written_bytes:
|
|
|
|
log.info("File has bytes: %s --> %s", f.sd_hash, file_path)
|
|
|
|
return defer.succeed(True)
|
|
|
|
return task.deferLater(reactor, 1, self._wait_on_lbry_file, f)
|
|
|
|
|
|
|
|
@defer.inlineCallbacks
|
2016-07-21 17:44:59 +02:00
|
|
|
def _get_stream(self, stream_info):
|
2017-02-13 02:57:23 +01:00
|
|
|
try:
|
|
|
|
download_path = yield self.daemon.add_stream(
|
|
|
|
self.name, self.timeout, self.download_directory, self.file_name, stream_info)
|
2017-03-06 23:01:35 +01:00
|
|
|
self.remove_from_wait(None)
|
2017-02-13 02:57:23 +01:00
|
|
|
except (InsufficientFundsError, Exception) as err:
|
|
|
|
if Failure(err).check(InsufficientFundsError):
|
|
|
|
log.warning("Insufficient funds to download lbry://%s", self.name)
|
|
|
|
self.remove_from_wait("Insufficient funds")
|
|
|
|
else:
|
|
|
|
log.warning("lbry://%s timed out, removing from streams", self.name)
|
|
|
|
self.remove_from_wait("Timed out")
|
|
|
|
if self.daemon.streams[self.name].downloader is not None:
|
2017-03-06 23:19:05 +01:00
|
|
|
yield self.daemon.lbry_file_manager.delete_lbry_file(
|
|
|
|
self.daemon.streams[self.name].downloader)
|
2016-12-30 07:12:20 +01:00
|
|
|
del self.daemon.streams[self.name]
|
2017-02-13 02:57:23 +01:00
|
|
|
raise err
|
|
|
|
|
2016-07-21 17:44:59 +02:00
|
|
|
if self.wait_for_write:
|
2016-12-30 07:12:20 +01:00
|
|
|
yield self._wait_for_write()
|
2017-02-13 02:57:23 +01:00
|
|
|
defer.returnValue((self.daemon.streams[self.name].sd_hash, download_path))
|
2016-07-21 17:44:59 +02:00
|
|
|
|
|
|
|
def _wait_for_write(self):
|
|
|
|
d = defer.succeed(None)
|
2016-12-30 04:48:12 +01:00
|
|
|
if not self._has_downloader_wrote():
|
2016-07-21 17:44:59 +02:00
|
|
|
d.addCallback(lambda _: reactor.callLater(1, self._wait_for_write))
|
|
|
|
return d
|
|
|
|
|
2016-12-30 04:48:12 +01:00
|
|
|
def _has_downloader_wrote(self):
|
2016-09-12 21:39:19 +02:00
|
|
|
stream = self.daemon.streams.get(self.name, False)
|
|
|
|
if stream:
|
2016-12-30 07:12:20 +01:00
|
|
|
file_path = self._full_path(stream.downloader)
|
|
|
|
return self._get_written_bytes(file_path)
|
2016-09-12 21:39:19 +02:00
|
|
|
else:
|
2016-08-05 12:24:48 +02:00
|
|
|
return False
|
|
|
|
|
2016-12-30 07:12:20 +01:00
|
|
|
def _get_written_bytes(self, file_path):
|
|
|
|
"""Returns the number of bytes written to `file_path`.
|
2016-07-21 17:44:59 +02:00
|
|
|
|
2016-12-30 07:12:20 +01:00
|
|
|
Returns False if there were issues reading `file_path`.
|
2016-08-05 12:24:48 +02:00
|
|
|
"""
|
2016-07-21 17:44:59 +02:00
|
|
|
try:
|
|
|
|
if os.path.isfile(file_path):
|
2016-12-30 07:12:20 +01:00
|
|
|
with open(file_path) as written_file:
|
|
|
|
written_file.seek(0, os.SEEK_END)
|
|
|
|
written_bytes = written_file.tell()
|
2016-07-21 17:44:59 +02:00
|
|
|
else:
|
|
|
|
written_bytes = False
|
|
|
|
except Exception:
|
|
|
|
writen_bytes = False
|
|
|
|
return written_bytes
|
|
|
|
|
2016-12-30 04:48:12 +01:00
|
|
|
def remove_from_wait(self, reason):
|
2016-09-12 21:39:19 +02:00
|
|
|
if self.name in self.daemon.waiting_on:
|
|
|
|
del self.daemon.waiting_on[self.name]
|
2016-12-30 04:48:12 +01:00
|
|
|
return reason
|
2016-07-21 17:44:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
class _ResolveNameHelper(object):
|
|
|
|
def __init__(self, daemon, name, force_refresh):
|
|
|
|
self.daemon = daemon
|
|
|
|
self.name = name
|
|
|
|
self.force_refresh = force_refresh
|
|
|
|
|
|
|
|
def get_deferred(self):
|
|
|
|
if self.need_fresh_stream():
|
|
|
|
log.info("Resolving stream info for lbry://%s", self.name)
|
|
|
|
d = self.wallet.get_stream_info_for_name(self.name)
|
2016-10-27 20:28:56 +02:00
|
|
|
d.addCallback(self._cache_stream_info)
|
2016-07-21 17:44:59 +02:00
|
|
|
else:
|
2016-08-08 20:58:31 +02:00
|
|
|
log.debug("Returning cached stream info for lbry://%s", self.name)
|
2016-07-21 17:44:59 +02:00
|
|
|
d = defer.succeed(self.name_data['claim_metadata'])
|
|
|
|
return d
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name_data(self):
|
|
|
|
return self.daemon.name_cache[self.name]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def wallet(self):
|
|
|
|
return self.daemon.session.wallet
|
|
|
|
|
|
|
|
def now(self):
|
|
|
|
return self.daemon._get_long_count_timestamp()
|
|
|
|
|
|
|
|
def _add_txid(self, txid):
|
|
|
|
self.name_data['txid'] = txid
|
|
|
|
return defer.succeed(None)
|
|
|
|
|
|
|
|
def _cache_stream_info(self, stream_info):
|
|
|
|
self.daemon.name_cache[self.name] = {
|
|
|
|
'claim_metadata': stream_info,
|
|
|
|
'timestamp': self.now()
|
|
|
|
}
|
|
|
|
d = self.wallet.get_txid_for_name(self.name)
|
|
|
|
d.addCallback(self._add_txid)
|
|
|
|
d.addCallback(lambda _: self.daemon._update_claim_cache())
|
|
|
|
d.addCallback(lambda _: self.name_data['claim_metadata'])
|
|
|
|
return d
|
|
|
|
|
|
|
|
def need_fresh_stream(self):
|
|
|
|
return self.force_refresh or not self.is_in_cache() or self.is_cached_name_expired()
|
|
|
|
|
|
|
|
def is_in_cache(self):
|
|
|
|
return self.name in self.daemon.name_cache
|
|
|
|
|
|
|
|
def is_cached_name_expired(self):
|
|
|
|
time_in_cache = self.now() - self.name_data['timestamp']
|
|
|
|
return time_in_cache >= self.daemon.cache_time
|
2016-09-30 02:39:02 +02:00
|
|
|
|
|
|
|
|
2017-01-02 20:52:24 +01:00
|
|
|
def loggly_time_string(dt):
|
|
|
|
formatted_dt = dt.strftime("%Y-%m-%dT%H:%M:%S")
|
2017-01-03 20:13:01 +01:00
|
|
|
milliseconds = str(round(dt.microsecond * (10.0 ** -5), 3))
|
2017-01-02 22:09:28 +01:00
|
|
|
return urllib.quote_plus(formatted_dt + milliseconds + "Z")
|
2017-01-02 20:52:24 +01:00
|
|
|
|
|
|
|
|
2017-02-02 16:23:17 +01:00
|
|
|
def get_loggly_query_string(installation_id):
|
2017-01-02 22:09:28 +01:00
|
|
|
base_loggly_search_url = "https://lbry.loggly.com/search#"
|
2017-01-02 20:52:24 +01:00
|
|
|
now = utils.now()
|
|
|
|
yesterday = now - utils.timedelta(days=1)
|
2017-01-02 22:09:28 +01:00
|
|
|
params = {
|
2017-02-02 16:23:17 +01:00
|
|
|
'terms': 'json.installation_id:{}*'.format(installation_id[:SHORT_ID_LEN]),
|
2017-01-02 22:09:28 +01:00
|
|
|
'from': loggly_time_string(yesterday),
|
|
|
|
'to': loggly_time_string(now)
|
|
|
|
}
|
|
|
|
data = urllib.urlencode(params)
|
|
|
|
return base_loggly_search_url + data
|
2017-01-02 20:52:24 +01:00
|
|
|
|
|
|
|
|
2017-02-02 16:23:17 +01:00
|
|
|
def report_bug_to_slack(message, installation_id, platform_name, app_version):
|
2017-02-09 04:01:56 +01:00
|
|
|
webhook = utils.deobfuscate(conf.settings['SLACK_WEBHOOK'])
|
2017-01-02 20:52:24 +01:00
|
|
|
payload_template = "os: %s\n version: %s\n<%s|loggly>\n%s"
|
|
|
|
payload_params = (
|
|
|
|
platform_name,
|
|
|
|
app_version,
|
2017-02-02 16:23:17 +01:00
|
|
|
get_loggly_query_string(installation_id),
|
2017-01-02 20:52:24 +01:00
|
|
|
message
|
|
|
|
)
|
|
|
|
payload = {
|
|
|
|
"text": payload_template % payload_params
|
|
|
|
}
|
|
|
|
requests.post(webhook, json.dumps(payload))
|
|
|
|
|
|
|
|
|
2017-02-02 05:40:03 +01:00
|
|
|
def get_lbry_file_search_value(search_fields):
|
2017-03-06 23:01:35 +01:00
|
|
|
for searchtype in FileID:
|
|
|
|
value = search_fields.get(searchtype, None)
|
|
|
|
if value is not None:
|
2016-10-20 21:52:37 +02:00
|
|
|
return searchtype, value
|
2017-02-02 05:40:03 +01:00
|
|
|
raise NoValidSearch('{} is missing a valid search type'.format(search_fields))
|
2017-02-16 05:39:17 +01:00
|
|
|
|
|
|
|
|
2017-03-06 23:01:35 +01:00
|
|
|
def iter_lbry_file_search_values(search_fields):
|
|
|
|
for searchtype in FileID:
|
|
|
|
value = search_fields.get(searchtype, None)
|
|
|
|
if value is not None:
|
|
|
|
yield searchtype, value
|
|
|
|
|
|
|
|
|
2017-02-16 05:39:17 +01:00
|
|
|
def get_blob_payment_rate_manager(session, payment_rate_manager=None):
|
|
|
|
if payment_rate_manager:
|
|
|
|
rate_managers = {
|
|
|
|
'only-free': OnlyFreePaymentsManager()
|
|
|
|
}
|
|
|
|
if payment_rate_manager in rate_managers:
|
|
|
|
payment_rate_manager = rate_managers[payment_rate_manager]
|
|
|
|
log.info("Downloading blob with rate manager: %s", payment_rate_manager)
|
|
|
|
return payment_rate_manager or session.payment_rate_manager
|
2017-02-21 16:36:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
def get_version_from_tag(tag):
|
|
|
|
match = re.match('v([\d.]+)', tag)
|
|
|
|
if match:
|
|
|
|
return match.group(1)
|
|
|
|
else:
|
|
|
|
raise Exception('Failed to parse version from tag {}'.format(tag))
|