diff --git a/lbrynet/lbryfilemanager/LBRYFileDownloader.py b/lbrynet/lbryfilemanager/LBRYFileDownloader.py index 2afc17588..8bb1ada42 100644 --- a/lbrynet/lbryfilemanager/LBRYFileDownloader.py +++ b/lbrynet/lbryfilemanager/LBRYFileDownloader.py @@ -24,12 +24,21 @@ class ManagedLBRYFileDownloader(LBRYFileSaver): LBRYFileSaver.__init__(self, stream_hash, peer_finder, rate_limiter, blob_manager, stream_info_manager, payment_rate_manager, wallet, download_directory, upload_allowed, file_name) + self.sd_hash = None self.rowid = rowid self.lbry_file_manager = lbry_file_manager self.saving_status = False def restore(self): - d = self.lbry_file_manager.get_lbry_file_status(self) + d = self.stream_info_manager._get_sd_blob_hashes_for_stream(self.stream_hash) + + def _save_sd_hash(sd_hash): + self.sd_hash = sd_hash[0] + return defer.succeed(None) + + d.addCallback(_save_sd_hash) + + d.addCallback(lambda _: self.lbry_file_manager.get_lbry_file_status(self)) def restore_status(status): if status == ManagedLBRYFileDownloader.STATUS_RUNNING: @@ -87,6 +96,14 @@ class ManagedLBRYFileDownloader(LBRYFileSaver): d = LBRYFileSaver._start(self) + d.addCallback(lambda _: self.stream_info_manager._get_sd_blob_hashes_for_stream(self.stream_hash)) + + def _save_sd_hash(sd_hash): + self.sd_hash = sd_hash[0] + return defer.succeed(None) + + d.addCallback(_save_sd_hash) + d.addCallback(lambda _: self._save_status()) return d diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index 555e1deff..c0c487b42 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -68,7 +68,6 @@ handler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=2097152, b log.addHandler(handler) log.setLevel(logging.INFO) - INITIALIZING_CODE = 'initializing' LOADING_DB_CODE = 'loading_db' LOADING_WALLET_CODE = 'loading_wallet' @@ -875,7 +874,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): def _disp_file(f): file_path = os.path.join(self.download_directory, f.file_name) log.info("[" + str(datetime.now()) + "] Already downloaded: " + str(f.stream_hash) + " --> " + file_path) - return {'stream_hash': f.stream_hash, 'path': file_path} + return f def _get_stream(name): def _disp(stream): @@ -886,13 +885,14 @@ class LBRYDaemon(jsonrpc.JSONRPC): log.info("[" + str(datetime.now()) + "] Start stream: " + stream_hash) return stream - d = self.session.wallet.get_stream_info_for_name(name) - stream = GetStream(self.sd_identifier, self.session, self.session.wallet, self.lbry_file_manager, + stream = GetStream(self.sd_identifier, self.session, self.session.wallet, + self.lbry_file_manager, max_key_fee=self.max_key_fee, data_rate=self.data_rate, timeout=timeout, download_directory=download_directory) + d = self.session.wallet.get_stream_info_for_name(name) d.addCallback(_disp) d.addCallback(lambda stream_info: stream.start(stream_info, name)) - d.addCallback(lambda r: {'stream_hash': r[0], 'path': r[1]} if r else server.failure) + d.addCallback(lambda _: stream.downloader) return d @@ -1028,17 +1028,60 @@ class LBRYDaemon(jsonrpc.JSONRPC): t = {'completed': f.completed, 'file_name': f.file_name, 'key': binascii.b2a_hex(f.key), 'points_paid': f.points_paid, 'stopped': f.stopped, 'stream_hash': f.stream_hash, 'stream_name': f.stream_name, 'suggested_file_name': f.suggested_file_name, - 'upload_allowed': f.upload_allowed} + 'upload_allowed': f.upload_allowed, 'sd_hash': f.sd_hash} else: t = {'completed': f.completed, 'file_name': f.file_name, 'key': None, 'points_paid': f.points_paid, 'stopped': f.stopped, 'stream_hash': f.stream_hash, 'stream_name': f.stream_name, - 'suggested_file_name': f.suggested_file_name, 'upload_allowed': f.upload_allowed} + 'suggested_file_name': f.suggested_file_name, 'upload_allowed': f.upload_allowed, + 'sd_hash': f.sd_hash} r.append(t) return r + def _get_lbry_file_by_uri(self, name): + d = self.session.wallet.get_stream_info_for_name(name) + d.addCallback(lambda info: info['stream_hash']) + d.addCallback(lambda sd_hash: next(l for l in self.lbry_file_manager.lbry_files if l.sd_hash == sd_hash)) + return d + + def _get_lbry_file_by_sd_hash(self, sd_hash): + r = next(l for l in self.lbry_file_manager.lbry_files if l.sd_hash == sd_hash) + return defer.succeed(r) + + def _get_lbry_file_by_file_name(self, file_name): + r = next(l for l in self.lbry_file_manager.lbry_files if l.file_name == file_name) + return defer.succeed(r) + + def _get_lbry_file(self, search_by, val): + def _show_file(f): + if f: + if f.key: + t = {'completed': f.completed, 'file_name': f.file_name, 'key': binascii.b2a_hex(f.key), + 'points_paid': f.points_paid, 'stopped': f.stopped, 'stream_hash': f.stream_hash, + 'stream_name': f.stream_name, 'suggested_file_name': f.suggested_file_name, + 'upload_allowed': f.upload_allowed, 'sd_hash': f.sd_hash} + + else: + t = {'completed': f.completed, 'file_name': f.file_name, 'key': None, + 'points_paid': f.points_paid, + 'stopped': f.stopped, 'stream_hash': f.stream_hash, 'stream_name': f.stream_name, + 'suggested_file_name': f.suggested_file_name, 'upload_allowed': f.upload_allowed, + 'sd_hash': f.sd_hash} + return t + else: + return False + + if search_by == "name": + d = self._get_lbry_file_by_uri(val) + elif search_by == "sd_hash": + d = self._get_lbry_file_by_sd_hash(val) + elif search_by == "file_name": + d = self._get_lbry_file_by_file_name(val) + d.addCallback(_show_file) + return d + def _log_to_slack(self, msg): URL = "https://hooks.slack.com/services/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" msg = platform.platform() + ": " + base58.b58encode(self.lbryid)[:20] + ", " + msg @@ -1330,12 +1373,42 @@ class LBRYDaemon(jsonrpc.JSONRPC): 'stream_name': string 'suggested_file_name': string 'upload_allowed': bool + 'sd_hash': string """ r = self._get_lbry_files() log.info("[" + str(datetime.now()) + "] Get LBRY files") return self._render_response(r, OK_CODE) + def jsonrpc_get_lbry_file(self, p): + """ + Get lbry file + + Args: + 'name': get file by lbry uri, + 'sd_hash': get file by the hash in the name claim, + 'file_name': get file by its name in the downloads folder, + Returns: + 'completed': bool + 'file_name': string + 'key': hex string + 'points_paid': float + 'stopped': bool + 'stream_hash': base 58 string + 'stream_name': string + 'suggested_file_name': string + 'upload_allowed': bool + 'sd_hash': string + """ + + if p.keys()[0] in ['name', 'sd_hash', 'file_name']: + search_type = p.keys()[0] + d = self._get_lbry_file(search_type, p[search_type]) + else: + d = defer.fail() + d.addCallback(lambda r: self._render_response(r, OK_CODE)) + return d + def jsonrpc_resolve_name(self, p): """ Resolve stream info from a LBRY uri @@ -1391,6 +1464,7 @@ class LBRYDaemon(jsonrpc.JSONRPC): name = p['name'] if p['name'] not in self.waiting_on.keys(): d = self._download_name(name=name, timeout=timeout, download_directory=download_directory) + d.addCallback(lambda l: {'stream_hash': l.sd_hash, 'path': os.path.join(self.download_directory, l.file_name)}) d.addCallback(lambda message: self._render_response(message, OK_CODE)) else: d = server.failure diff --git a/lbrynet/lbrynet_daemon/LBRYDaemonServer.py b/lbrynet/lbrynet_daemon/LBRYDaemonServer.py index 04ad5f561..e68479bbe 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemonServer.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemonServer.py @@ -2,6 +2,8 @@ import logging import subprocess import os import shutil + +from twisted.internet.task import LoopingCall from txjsonrpc.web import jsonrpc import json @@ -12,6 +14,7 @@ from datetime import datetime from appdirs import user_data_dir from twisted.web import server, static, resource from twisted.internet import defer +from twisted.web.static import StaticProducer from lbrynet.lbrynet_daemon.LBRYDaemon import LBRYDaemon from lbrynet.conf import API_CONNECTION_STRING, API_ADDRESS, DEFAULT_WALLET, UI_ADDRESS @@ -50,9 +53,77 @@ class LBRYindex(resource.Resource): return static.File(os.path.join(self.ui_dir, "index.html")).render_GET(request) -class HostedLBRYFile(static.File): - def __init__(self, path): - static.File.__init__(self, path=path) +class LBRYFileProducer(StaticProducer): + def __init__(self, request, lbry_stream): + self.stream = lbry_stream + self.updater = LoopingCall(self._check_for_data) + StaticProducer.__init__(self, request, fileObject=file(lbry_stream.file_written_to)) + + def start(self): + d = self._set_size() + self.updater.start(5) + + def _set_size(self): + def _set(size): + self.request.setHeader('content-length', str(size)) + self.request.setHeader('content-type', ' application/octet-stream') + return defer.succeed(None) + + d = self.stream.get_total_bytes() + d.addCallback(_set) + return d + + def _check_for_data(self): + self.fileObject.seek(self.fileObject.tell()) + data = self.fileObject.read() + if data: + self.request.write(data) + + def _check_status(stream_status): + if stream_status.running_status == "completed": + self.stopProducing() + return defer.succeed(None) + + d = self.stream.status() + d.addCallback(_check_status) + + def resumeProducing(self): + self.updater.start(1) + + def stopProducing(self): + self.updater.stop() + self.fileObject.close() + self.stream.stop() + self.request.finish() + + +class HostedLBRYFile(resource.Resource): + def __init__(self, api): + self._api = api + self.stream = None + self.streaming_file = None + resource.Resource.__init__(self) + + def _set_stream(self, stream): + self.stream = stream + + def makeProducer(self, request, stream): + return LBRYFileProducer(request, stream) + + def render_GET(self, request): + if 'name' in request.args.keys(): + if request.args['name'][0] != 'lbry': + if request.args['name'][0] != self.streaming_file: + self.streaming_file = request.args['name'][0] + d = self._api._download_name(request.args['name'][0]) + d.addCallback(self._set_stream) + else: + d = defer.succeed(None) + d.addCallback(lambda _: self.makeProducer(request, self.stream).start()) + else: + request.redirect(UI_ADDRESS) + request.finish() + return server.NOT_DONE_YET class LBRYFileRender(resource.Resource): @@ -63,7 +134,7 @@ class LBRYFileRender(resource.Resource): api = jsonrpc.Proxy(API_CONNECTION_STRING) if request.args['name'][0] != 'lbry': d = api.callRemote("get", {'name': request.args['name'][0]}) - d.addCallback(lambda results: HostedLBRYFile(results['path'])) + d.addCallback(lambda results: static.File(results['path'], defaultType='video/octet-stream')) d.addCallback(lambda static_file: static_file.render_GET(request) if static_file.getFileSize() > 0 else server.failure) else: @@ -74,29 +145,6 @@ class LBRYFileRender(resource.Resource): return server.failure -class LBRYBugReport(resource.Resource): - isLeaf = False - - def _delayed_render(self, request, results): - request.write(results) - request.finish() - - def render_GET(self, request): - return '
' \ - '
Please describe the problem you experienced and any information you think might be useful to us. Links to screenshots are great!
' \ - '' \ - '' \ - '
' - - def render_POST(self, request): - msg = request.args["message"][0] - api = jsonrpc.Proxy(API_CONNECTION_STRING) - d = api.callRemote("upload_log", {'name_prefix': 'report', 'exclude_previous': False, 'force': True, 'message': str(msg)}) - d.addCallback(lambda _: self._delayed_render(request, "Your bug report is greatly appreciated! Click here to return to LBRY")) - - return server.NOT_DONE_YET - - class LBRYDaemonServer(object): def __init__(self): self.data_dir = user_data_dir("LBRY") @@ -207,8 +255,8 @@ class LBRYDaemonServer(object): self.root.putChild("font", static.File(os.path.join(self.ui_dir, "font"))) self.root.putChild("img", static.File(os.path.join(self.ui_dir, "img"))) self.root.putChild("js", static.File(os.path.join(self.ui_dir, "js"))) - self.root.putChild("view", LBRYFileRender()) - self.root.putChild("report", LBRYBugReport()) + # self.root.putChild("view", LBRYFileRender()) + self.root.putChild("view", HostedLBRYFile(self._api)) self.root.putChild(API_ADDRESS, self._api) return defer.succeed(True) diff --git a/lbrynet/lbrynet_daemon/LBRYDownloader.py b/lbrynet/lbrynet_daemon/LBRYDownloader.py index c8cdc7fbb..b52c8c92a 100644 --- a/lbrynet/lbrynet_daemon/LBRYDownloader.py +++ b/lbrynet/lbrynet_daemon/LBRYDownloader.py @@ -40,6 +40,7 @@ class GetStream(object): self.timeout_counter = 0 self.download_directory = download_directory self.download_path = None + self.downloader = None self.finished = defer.Deferred() self.checker = LoopingCall(self.check_status) @@ -120,9 +121,11 @@ class GetStream(object): d = _pay_key_fee() else: d = defer.Deferred() + self.downloader = downloader self.download_path = os.path.join(downloader.download_directory, downloader.file_name) d.addCallback(lambda _: log.info("Downloading " + str(self.stream_hash) + " --> " + str(self.download_path))) - d.addCallback(lambda _: downloader.start()) + d.addCallback(lambda _: self.downloader.start()) + class FetcherDaemon(object): def __init__(self, session, lbry_file_manager, lbry_file_metadata_manager, wallet, sd_identifier, autofetcher_conf,