add LBRYFileProducer

-Add LBRYFileProducer, to host the contents of a download without
having to keep re-opening it as it is added to

-included sd hash in ManagedLBRYFileDownloader, to make comparing the
contents of the file manager against name claims easier

-add get_lbry_file function, which returns information about a LBRY
file found by sd_hash, file name, or lbry uri
This commit is contained in:
Jack 2016-04-24 04:42:42 -04:00
parent 3e7c09bb44
commit c2ec066c85
4 changed files with 180 additions and 38 deletions

View file

@ -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

View file

@ -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

View file

@ -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 '<html><body><form method="POST">' \
'<br>Please describe the problem you experienced and any information you think might be useful to us. Links to screenshots are great!</br>' \
'<textarea cols="50" rows="10" name="message" type="text"></textarea>' \
'<button>Submit</button>' \
'</form></body></html>'
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, "<html><body>Your bug report is greatly appreciated! <a href='lbry://lbry'>Click here to return to LBRY</a></body></html>"))
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)

View file

@ -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,