#!/usr/bin/env python3 import sys import argparse import cgi import tempfile import os.path import threading import time csspath = os.path.join(os.path.dirname(__file__), 'self.css') css = (open(csspath).read()) # Python 2 vs Python 3 compat try: from urllib.parse import unquote_plus except ImportError: from urllib import unquote_plus from wsgiref.util import setup_testing_defaults from wsgiref.simple_server import make_server import wsgiref.util try: import boxes.generators except ImportError: sys.path.append(os.path.dirname(__file__) + "/..") import boxes.generators class FileChecker(threading.Thread): def __init__(self, files=[], checkmodules=True): super(FileChecker, self).__init__() self.checkmodules = checkmodules self.timestamps = {} for path in files: self.timestamps[path] = os.stat(path).st_mtime if checkmodules: self._addModules() def _addModules(self): for name, module in sys.modules.items(): path = getattr(module, "__file__", None) if not path: continue if path not in self.timestamps: self.timestamps[path] = os.stat(path).st_mtime def filesOK(self): if self.checkmodules: self._addModules() for path, timestamp in self.timestamps.items(): try: if os.stat(path).st_mtime != timestamp: return False except FileNotFoundError: return False return True def run(self): while True: if not self.filesOK(): os.execv(__file__, sys.argv) time.sleep(1) class ArgumentParserError(Exception): pass class ThrowingArgumentParser(argparse.ArgumentParser): def error(self, message): raise ArgumentParserError(message) boxes.ArgumentParser = ThrowingArgumentParser # Evil hack class BServer: def __init__(self): self.boxes = {b.__name__ : b() for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface} self.groups = boxes.generators.ui_groups self.groups_by_name = boxes.generators.ui_groups_by_name for name, box in self.boxes.items(): self.groups_by_name.get(box.ui_group, self.groups_by_name["Misc"]).add(box) def arg2html(self, a, prefix): name = a.option_strings[0].replace("-", "") if isinstance(a, argparse._HelpAction): return "" viewname = name if prefix and name.startswith(prefix + '_'): viewname = name[len(prefix)+1:] row = """
A Python based generator for laser cut boxes and other things.
It features both finished parametrized generators as well as a Python API for writing your own scripts. It features finger and (flat) dovetail joints, flex cuts, holes and slots for screws and more high level functions.
These are the available generators:
""" ] for nr, group in enumerate(self.groups): result.append('''""", str(e).encode(), b"""
""" ] def serve(self, environ, start_response): status = '200 OK' headers = [('Content-type', 'text/html; charset=utf-8')] d = cgi.parse_qs(environ['QUERY_STRING']) name = environ["PATH_INFO"][1:] box = self.boxes.get(name, None) if not box: start_response(status, headers) return self.menu() args = ["--"+unquote_plus(arg) for arg in environ['QUERY_STRING'].split("&")] if "--render=1" not in args: start_response(status, headers) return self.args2html(name, box) else: args = [a for a in args if a != "--render=1"] try: box.parseArgs(args) except (ArgumentParserError) as e: start_response(status, headers) return self.errorMessage(name, e) if name == "TrayLayout": start_response(status, headers) box.fillDefault(box.x, box.y) self.boxes["TrayLayout2"].argparser.set_defaults(layout=str(box)) return self.args2html( name, self.boxes["TrayLayout2"], action="TrayLayout2") if name == "TrayLayout2": try: box.parse(box.layout.split("\n")) except Exception as e: raise start_response(status, headers) return self.errorMessage(name, e) start_response(status, box.formats.http_headers.get( box.format, [('Content-type', 'application/unknown; charset=utf-8')])) fd, box.output = tempfile.mkstemp() box.render() result = open(box.output).readlines() os.remove(box.output) os.close(fd) return (l.encode("utf-8") for l in result) if __name__=="__main__": fc = FileChecker(files=[csspath]) fc.start() boxserver = BServer() httpd = make_server('', 8000, boxserver.serve) print("Serving on port 8000...") httpd.serve_forever() else: application = BServer().serve