2016-10-07 20:01:59 +02:00
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import shutil
|
|
|
|
import json
|
2017-07-03 17:09:59 +02:00
|
|
|
import sys
|
2016-10-07 20:01:59 +02:00
|
|
|
import tempfile
|
|
|
|
|
|
|
|
|
2017-07-03 17:09:59 +02:00
|
|
|
from appdirs import user_data_dir
|
2016-10-07 20:01:59 +02:00
|
|
|
from twisted.web import server, static, resource
|
|
|
|
from twisted.internet import defer, error
|
|
|
|
|
2016-12-21 20:55:43 +01:00
|
|
|
from lbrynet import conf
|
2017-06-26 03:04:33 +02:00
|
|
|
from lbrynet.daemon.FileStreamer import EncryptedFileStreamer
|
2016-10-07 20:01:59 +02:00
|
|
|
|
2017-07-03 17:09:59 +02:00
|
|
|
# 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)
|
2016-10-07 20:01:59 +02:00
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class NoCacheStaticFile(static.File):
|
2016-10-07 20:28:38 +02:00
|
|
|
def _set_no_cache(self, request):
|
2016-10-07 20:01:59 +02:00
|
|
|
request.setHeader('cache-control', 'no-cache, no-store, must-revalidate')
|
|
|
|
request.setHeader('expires', '0')
|
|
|
|
|
2016-10-07 20:28:38 +02:00
|
|
|
def render_GET(self, request):
|
|
|
|
self._set_no_cache(request)
|
|
|
|
return static.File.render_GET(self, request)
|
2016-10-07 20:01:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2016-11-30 21:20:45 +01:00
|
|
|
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())
|
|
|
|
|
2016-10-07 20:01:59 +02:00
|
|
|
def render_GET(self, request):
|
|
|
|
request.setHeader("Content-Security-Policy", "sandbox")
|
|
|
|
if 'name' in request.args.keys():
|
2016-11-30 21:20:45 +01:00
|
|
|
if self.is_valid_request_name(request):
|
2017-01-04 01:08:31 +01:00
|
|
|
name = request.args['name'][0]
|
2017-02-02 05:40:03 +01:00
|
|
|
d = self._api.jsonrpc_get(name=name)
|
2017-01-18 02:26:09 +01:00
|
|
|
d.addCallback(lambda response: response['stream_hash'])
|
2017-01-04 01:08:31 +01:00
|
|
|
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))
|
2016-10-07 20:01:59 +02:00
|
|
|
elif request.args['name'][0] in self._api.waiting_on.keys():
|
2017-01-17 18:31:48 +01:00
|
|
|
request.redirect(
|
|
|
|
conf.settings.get_ui_address() + "/?watch=" + request.args['name'][0]
|
|
|
|
)
|
2016-10-07 20:01:59 +02:00
|
|
|
request.finish()
|
|
|
|
else:
|
2017-01-17 04:23:20 +01:00
|
|
|
request.redirect(conf.settings.get_ui_address())
|
2016-10-07 20:01:59 +02:00
|
|
|
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]
|
2016-11-04 19:15:57 +01:00
|
|
|
# Temp file created by request
|
|
|
|
uploaded_file = request.args['file'][0]
|
|
|
|
newpath = move_to_temp_dir_and_restore_filename(uploaded_file, origfilename)
|
2016-10-07 20:01:59 +02:00
|
|
|
self._api.uploaded_temp_files.append(newpath)
|
|
|
|
return json.dumps(newpath)
|
2016-11-04 19:15:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
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
|