brain backup 2026-09-14
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Private loopback demo server for the Grade 3 curriculum showcase."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import zipfile
|
||||
from http import HTTPStatus
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
DEFAULT_DOWNLOADS = Path.home() / 'Downloads' / 'CoreKnowledge_Grades_1-5_EN_ES'
|
||||
sys.path.insert(0, str(ROOT / 'src'))
|
||||
from server_catalog import lookup_material, material_index
|
||||
|
||||
|
||||
class ShowcaseHandler(SimpleHTTPRequestHandler):
|
||||
def __init__(self, *args, downloads_dir=None, **kwargs):
|
||||
self.downloads_dir = Path(downloads_dir or DEFAULT_DOWNLOADS).resolve()
|
||||
super().__init__(*args, directory=str(ROOT), **kwargs)
|
||||
|
||||
def catalog(self):
|
||||
return json.loads((ROOT / 'data' / 'grade3_catalog.json').read_text())
|
||||
|
||||
def send_json(self, data):
|
||||
body = json.dumps(data).encode('utf-8')
|
||||
self.send_response(HTTPStatus.OK)
|
||||
self.send_header('Content-Type', 'application/json; charset=utf-8')
|
||||
self.send_header('Content-Length', str(len(body)))
|
||||
self.send_header('Cache-Control', 'no-store')
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def send_pdf(self, material_id):
|
||||
if not re.fullmatch(r'[0-9a-f]{20}', material_id):
|
||||
self.send_error(HTTPStatus.NOT_FOUND)
|
||||
return
|
||||
pair = lookup_material(material_index(self.catalog()), material_id)
|
||||
if pair is None:
|
||||
self.send_error(HTTPStatus.NOT_FOUND)
|
||||
return
|
||||
archive_name, internal_path = pair
|
||||
archive_path = (self.downloads_dir / archive_name).resolve()
|
||||
if archive_path.parent != self.downloads_dir:
|
||||
self.send_error(HTTPStatus.NOT_FOUND)
|
||||
return
|
||||
try:
|
||||
with zipfile.ZipFile(archive_path) as archive:
|
||||
content = archive.read(internal_path)
|
||||
except (FileNotFoundError, KeyError, zipfile.BadZipFile):
|
||||
self.send_error(HTTPStatus.NOT_FOUND)
|
||||
return
|
||||
filename = Path(internal_path).name
|
||||
self.send_response(HTTPStatus.OK)
|
||||
self.send_header('Content-Type', mimetypes.guess_type(filename)[0] or 'application/pdf')
|
||||
self.send_header('Content-Length', str(len(content)))
|
||||
self.send_header('Content-Disposition', 'inline; filename="%s"' % filename.replace('"', ''))
|
||||
self.send_header('Cache-Control', 'private, no-store')
|
||||
self.end_headers()
|
||||
self.wfile.write(content)
|
||||
|
||||
def do_GET(self):
|
||||
path = urlparse(self.path).path
|
||||
if path == '/api/catalog':
|
||||
self.send_json(self.catalog())
|
||||
return
|
||||
if path.startswith('/api/pdf/'):
|
||||
self.send_pdf(unquote(path[len('/api/pdf/'):]))
|
||||
return
|
||||
super().do_GET()
|
||||
|
||||
|
||||
def run(port, downloads_dir):
|
||||
def handler(*args, **kwargs):
|
||||
return ShowcaseHandler(*args, downloads_dir=downloads_dir, **kwargs)
|
||||
server = ThreadingHTTPServer(('127.0.0.1', port), handler)
|
||||
print('Serving Grade 3 showcase at http://127.0.0.1:%s' % port)
|
||||
server.serve_forever()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--port', type=int, default=8899)
|
||||
parser.add_argument('--downloads-dir', type=Path, default=DEFAULT_DOWNLOADS)
|
||||
args = parser.parse_args()
|
||||
run(args.port, args.downloads_dir)
|
||||
Reference in New Issue
Block a user