c2fc15160f
I changed the _download_name return type without realizing that it was also used by the watch endpoint. This switches the endpoint to go through get so that watches can be tracked just like downloads
146 lines
4.8 KiB
Python
146 lines
4.8 KiB
Python
import logging
|
|
import os
|
|
import shutil
|
|
import json
|
|
import sys
|
|
import tempfile
|
|
|
|
|
|
from appdirs import user_data_dir
|
|
from twisted.web import server, static, resource
|
|
from twisted.internet import defer, error
|
|
|
|
from lbrynet import conf
|
|
from lbrynet.lbrynet_daemon.FileStreamer import EncryptedFileStreamer
|
|
|
|
# TODO: omg, this code is essentially duplicated in Daemon
|
|
|
|
if sys.platform != "darwin":
|
|
data_dir = os.path.join(os.path.expanduser("~"), ".lbrynet")
|
|
else:
|
|
data_dir = user_data_dir("LBRY")
|
|
if not os.path.isdir(data_dir):
|
|
os.mkdir(data_dir)
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class NoCacheStaticFile(static.File):
|
|
def _set_no_cache(self, request):
|
|
request.setHeader('cache-control', 'no-cache, no-store, must-revalidate')
|
|
request.setHeader('expires', '0')
|
|
|
|
def render_GET(self, request):
|
|
self._set_no_cache(request)
|
|
return static.File.render_GET(self, request)
|
|
|
|
|
|
class LBRYindex(resource.Resource):
|
|
def __init__(self, ui_dir):
|
|
resource.Resource.__init__(self)
|
|
self.ui_dir = ui_dir
|
|
|
|
isLeaf = False
|
|
|
|
def _delayed_render(self, request, results):
|
|
request.write(str(results))
|
|
request.finish()
|
|
|
|
def getChild(self, name, request):
|
|
request.setHeader('cache-control', 'no-cache, no-store, must-revalidate')
|
|
request.setHeader('expires', '0')
|
|
|
|
if name == '':
|
|
return self
|
|
return resource.Resource.getChild(self, name, request)
|
|
|
|
def render_GET(self, request):
|
|
return NoCacheStaticFile(os.path.join(self.ui_dir, "index.html")).render_GET(request)
|
|
|
|
|
|
class HostedEncryptedFile(resource.Resource):
|
|
def __init__(self, api):
|
|
self._api = api
|
|
resource.Resource.__init__(self)
|
|
|
|
def _make_stream_producer(self, request, stream):
|
|
path = os.path.join(self._api.download_directory, stream.file_name)
|
|
|
|
producer = EncryptedFileStreamer(request, path, stream, self._api.lbry_file_manager)
|
|
request.registerProducer(producer, streaming=True)
|
|
|
|
d = request.notifyFinish()
|
|
d.addErrback(self._responseFailed, d)
|
|
return d
|
|
|
|
def is_valid_request_name(self, request):
|
|
return (
|
|
request.args['name'][0] != 'lbry' and
|
|
request.args['name'][0] not in self._api.waiting_on.keys())
|
|
|
|
def render_GET(self, request):
|
|
request.setHeader("Content-Security-Policy", "sandbox")
|
|
if 'name' in request.args.keys():
|
|
if self.is_valid_request_name(request):
|
|
name = request.args['name'][0]
|
|
d = self._api.jsonrpc_get({'name': name})
|
|
d.addCallback(lambda response: response['result']['stream_hash'])
|
|
d.addCallback(lambda sd_hash: self._api._get_lbry_file_by_sd_hash(sd_hash))
|
|
d.addCallback(lambda lbry_file: self._make_stream_producer(request, lbry_file))
|
|
elif request.args['name'][0] in self._api.waiting_on.keys():
|
|
request.redirect(conf.settings.UI_ADDRESS + "/?watch=" + request.args['name'][0])
|
|
request.finish()
|
|
else:
|
|
request.redirect(conf.settings.UI_ADDRESS)
|
|
request.finish()
|
|
return server.NOT_DONE_YET
|
|
|
|
def _responseFailed(self, err, call):
|
|
call.addErrback(lambda err: err.trap(error.ConnectionDone))
|
|
call.addErrback(lambda err: err.trap(defer.CancelledError))
|
|
call.addErrback(lambda err: log.info("Error: " + str(err)))
|
|
call.cancel()
|
|
|
|
|
|
class EncryptedFileUpload(resource.Resource):
|
|
"""
|
|
Accepts a file sent via the file upload widget in the web UI, saves
|
|
it into a temporary dir, and responds with a JSON string containing
|
|
the path of the newly created file.
|
|
"""
|
|
def __init__(self, api):
|
|
self._api = api
|
|
|
|
def render_POST(self, request):
|
|
origfilename = request.args['file_filename'][0]
|
|
# Temp file created by request
|
|
uploaded_file = request.args['file'][0]
|
|
newpath = move_to_temp_dir_and_restore_filename(uploaded_file, origfilename)
|
|
self._api.uploaded_temp_files.append(newpath)
|
|
return json.dumps(newpath)
|
|
|
|
|
|
def move_to_temp_dir_and_restore_filename(uploaded_file, origfilename):
|
|
newdirpath = tempfile.mkdtemp()
|
|
newpath = os.path.join(newdirpath, origfilename)
|
|
if os.name == "nt":
|
|
# TODO: comment on why shutil.move doesn't work?
|
|
move_win(uploaded_file.name, newpath)
|
|
else:
|
|
shutil.move(uploaded_file.name, newpath)
|
|
return newpath
|
|
|
|
|
|
def move_win(from_path, to_path):
|
|
shutil.copy(from_path, to_path)
|
|
# TODO Still need to remove the file
|
|
# TODO deal with pylint error in cleaner fashion than this
|
|
try:
|
|
from exceptions import WindowsError as win_except
|
|
except ImportError as e:
|
|
log.error("This shouldn't happen")
|
|
win_except = Exception
|
|
try:
|
|
os.remove(from_path)
|
|
except win_except as e:
|
|
pass
|