2016-07-07 15:39:48 +02:00
|
|
|
# Copyright: Damien Elmes <anki@ichi2.net>
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
|
|
|
|
from aqt.qt import *
|
|
|
|
from http import HTTPStatus
|
|
|
|
import http.server
|
2017-07-28 08:19:06 +02:00
|
|
|
import socketserver
|
2016-07-07 15:39:48 +02:00
|
|
|
import errno
|
2017-08-01 06:28:13 +02:00
|
|
|
from anki.utils import devMode
|
2016-07-07 15:39:48 +02:00
|
|
|
|
2017-07-27 04:28:44 +02:00
|
|
|
# locate web folder in source/binary distribution
|
|
|
|
def _getExportFolder():
|
|
|
|
# running from source?
|
|
|
|
srcFolder = os.path.join(os.path.dirname(__file__), "..")
|
|
|
|
webInSrcFolder = os.path.abspath(os.path.join(srcFolder, "web"))
|
|
|
|
if os.path.exists(webInSrcFolder):
|
|
|
|
return webInSrcFolder
|
|
|
|
elif isMac:
|
|
|
|
dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
return os.path.abspath(dir + "/../../Resources/web")
|
|
|
|
else:
|
|
|
|
raise Exception("couldn't find web folder")
|
|
|
|
|
|
|
|
_exportFolder = _getExportFolder()
|
|
|
|
|
2017-07-28 08:19:06 +02:00
|
|
|
# webengine on windows sometimes opens a connection and fails to send a request,
|
|
|
|
# which will hang the server if unthreaded
|
|
|
|
class ThreadedHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
|
|
|
|
pass
|
|
|
|
|
2016-07-07 15:39:48 +02:00
|
|
|
class MediaServer(QThread):
|
|
|
|
|
|
|
|
def run(self):
|
2016-07-08 05:22:36 +02:00
|
|
|
self.port = 10000
|
2016-07-07 15:39:48 +02:00
|
|
|
self.server = None
|
|
|
|
while not self.server:
|
|
|
|
try:
|
2017-07-28 08:19:06 +02:00
|
|
|
self.server = ThreadedHTTPServer(
|
2016-07-07 15:39:48 +02:00
|
|
|
("localhost", self.port), RequestHandler)
|
|
|
|
except OSError as e:
|
|
|
|
if e.errno == errno.EADDRINUSE:
|
|
|
|
self.port += 1
|
|
|
|
continue
|
|
|
|
raise
|
|
|
|
break
|
|
|
|
self.server.serve_forever()
|
|
|
|
|
|
|
|
class RequestHandler(http.server.SimpleHTTPRequestHandler):
|
|
|
|
|
2016-07-08 05:22:36 +02:00
|
|
|
def do_GET(self):
|
|
|
|
f = self.send_head()
|
|
|
|
if f:
|
|
|
|
try:
|
|
|
|
self.copyfile(f, self.wfile)
|
|
|
|
except Exception as e:
|
2017-08-01 06:28:13 +02:00
|
|
|
if devMode:
|
2016-07-08 05:22:36 +02:00
|
|
|
print("http server caught exception:", e)
|
|
|
|
else:
|
|
|
|
# swallow it - user likely surfed away from
|
|
|
|
# review screen before an image had finished
|
|
|
|
# downloading
|
|
|
|
pass
|
|
|
|
finally:
|
|
|
|
f.close()
|
|
|
|
|
2016-07-07 15:39:48 +02:00
|
|
|
def send_head(self):
|
|
|
|
path = self.translate_path(self.path)
|
2017-07-27 04:28:44 +02:00
|
|
|
path = self._redirectWebExports(path)
|
2016-07-07 15:39:48 +02:00
|
|
|
if os.path.isdir(path):
|
|
|
|
self.send_error(HTTPStatus.NOT_FOUND, "File not found")
|
|
|
|
return None
|
|
|
|
ctype = self.guess_type(path)
|
|
|
|
try:
|
|
|
|
f = open(path, 'rb')
|
|
|
|
except OSError:
|
|
|
|
self.send_error(HTTPStatus.NOT_FOUND, "File not found")
|
|
|
|
return None
|
|
|
|
try:
|
|
|
|
self.send_response(HTTPStatus.OK)
|
|
|
|
self.send_header("Content-type", ctype)
|
|
|
|
fs = os.fstat(f.fileno())
|
|
|
|
self.send_header("Content-Length", str(fs[6]))
|
|
|
|
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
|
2017-02-21 04:27:29 +01:00
|
|
|
self.send_header("Access-Control-Allow-Origin", "*")
|
2016-07-07 15:39:48 +02:00
|
|
|
self.end_headers()
|
|
|
|
return f
|
|
|
|
except:
|
|
|
|
f.close()
|
|
|
|
raise
|
|
|
|
|
|
|
|
def log_message(self, format, *args):
|
2017-08-01 06:28:13 +02:00
|
|
|
if not devMode:
|
2016-07-07 15:39:48 +02:00
|
|
|
return
|
|
|
|
print("%s - - [%s] %s" %
|
|
|
|
(self.address_string(),
|
|
|
|
self.log_date_time_string(),
|
|
|
|
format%args))
|
2017-07-27 04:28:44 +02:00
|
|
|
|
|
|
|
# catch /_anki references and rewrite them to web export folder
|
|
|
|
def _redirectWebExports(self, path):
|
|
|
|
targetPath = os.path.join(os.getcwd(), "_anki")
|
|
|
|
if path.startswith(targetPath):
|
|
|
|
newPath = os.path.join(_exportFolder, path[len(targetPath)+1:])
|
|
|
|
return newPath
|
|
|
|
return path
|