187 lines
6.4 KiB
Python
Executable File
187 lines
6.4 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
import sys
|
|
import argparse
|
|
import cgi
|
|
import tempfile
|
|
import os
|
|
import urllib
|
|
|
|
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
|
|
|
|
|
|
from boxes.generators import box, box2, box3, drillbox
|
|
from boxes.generators import flexbox, flexbox2, flexbox3, flextest, folder
|
|
from boxes.generators import magazinefile, trayinsert, traylayout, typetray, silverwarebox
|
|
|
|
|
|
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 = {
|
|
"DemoBox" : boxes.DemoBox(),
|
|
"Box" : box.Box(),
|
|
"Box2" : box2.Box(),
|
|
"Box3" : box3.Box(),
|
|
"DrillBox" : drillbox.Box(),
|
|
"FlexBox" : flexbox.FlexBox(),
|
|
"FlexBox2" : flexbox2.FlexBox(),
|
|
"FlexBox3" : flexbox3.FlexBox(),
|
|
"FlexTest": flextest.FlexTest(),
|
|
"Folder": folder.Folder(),
|
|
"MagazinFile" : magazinefile.Box(),
|
|
"TrayInsert" : trayinsert.TrayInsert(),
|
|
"TypeTray" : typetray.TypeTray(),
|
|
"SilverwareBox" : silverwarebox.Silverware(),
|
|
"TrayLayout" : traylayout.LayoutGenerator(),
|
|
"TrayLayout2" : traylayout.Layout(webargs=True),
|
|
}
|
|
def arg2html(self, a):
|
|
name = a.option_strings[0].replace("-", "")
|
|
if isinstance(a, argparse._HelpAction):
|
|
return ""
|
|
if isinstance(a, argparse._StoreTrueAction):
|
|
return """<tr><td>%s</td><td><input name="%s" type="checkbox" value="%s"></td><td>%s</td></tr>\n""" % \
|
|
(name, name, a.default, a.help)
|
|
if a.dest == "layout":
|
|
val = a.default.split("\n")
|
|
return """<tr><td>%s</td><td><textarea name="%s" cols="%s" rows="%s">%s</textarea></td><td>%s</td></tr>\n""" % \
|
|
(name, name, max((len(l) for l in val))+10, len(val)+1,
|
|
a.default, a.help or "")
|
|
return """<tr><td>%s</td><td><input name="%s" type="text" value="%s"></td><td>%s</td></tr>\n""" % \
|
|
(name, name, a.default, a.help)
|
|
|
|
def args2html(self, name, box, action=""):
|
|
result = ["""<html><head><title>Boxes - """, name, """</title></head>
|
|
<body>
|
|
<h1>""", name, """</h1>
|
|
<p>""", box.__doc__, """</p>
|
|
<form action="%s" method="POST" target="_blank">
|
|
<table>
|
|
""" % (action)]
|
|
for a in box.argparser._actions:
|
|
if a.dest in ("input", "output"):
|
|
continue
|
|
result.append(self.arg2html(a))
|
|
if a.dest == "burn":
|
|
result.append("</table>\n<hr>\n<table>\n")
|
|
result.append("""</table>
|
|
<p><button>Generate</button></p>
|
|
</form>
|
|
</body>
|
|
</html>
|
|
""")
|
|
return (s.encode("utf-8") for s in result)
|
|
|
|
def menu(self):
|
|
result = ["""<html>
|
|
<head><title>Boxes.py</title></head>
|
|
<body>
|
|
<h1>Boxes.py</h1>
|
|
<p>
|
|
A Python based generator for laser cut boxes and other things.
|
|
</p>
|
|
<p>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.
|
|
</p>
|
|
<p>These are the available generators:</p>
|
|
<ul>
|
|
""" ]
|
|
for name in sorted(self.boxes):
|
|
if name in ("TrayLayout2", ):
|
|
continue
|
|
box = self.boxes[name]
|
|
docs = ""
|
|
if box.__doc__:
|
|
docs = " - " + box.__doc__
|
|
result.append(""" <li><a href="%s">%s</a>%s</li>""" % (
|
|
name, name, docs))
|
|
result.append("""</ul>
|
|
</body>
|
|
</html>
|
|
""")
|
|
return (s.encode("utf-8") for s in result)
|
|
|
|
|
|
def errorMessage(self, name, e):
|
|
return [
|
|
b"""<html><head><title>Error generating""", name.encode(),
|
|
b"""</title><head>
|
|
<body>
|
|
<h1>An error occurred!</h1>
|
|
<p>""", str(e).encode(), b"""</p>
|
|
</body>
|
|
</html>
|
|
""" ]
|
|
|
|
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()
|
|
|
|
if environ["REQUEST_METHOD"] == "GET":
|
|
start_response(status, headers)
|
|
return self.args2html(name, box)
|
|
elif environ["REQUEST_METHOD"] == "POST":
|
|
try:
|
|
length = int(environ.get('CONTENT_LENGTH', '0'))
|
|
except ValueError:
|
|
length = 0
|
|
body = environ['wsgi.input'].read(length).decode()
|
|
args = ["--"+arg for arg in body.split("&")]
|
|
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:
|
|
print(urllib.parse.unquote_plus(box.layout))
|
|
box.parse(urllib.parse.unquote_plus(box.layout).split("\n"))
|
|
except Exception as e:
|
|
raise
|
|
start_response(status, headers)
|
|
return self.errorMessage(name, e)
|
|
|
|
start_response(status,
|
|
[('Content-type', 'image/svg+xml; 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__":
|
|
boxserver = BServer()
|
|
httpd = make_server('', 8000, boxserver.serve)
|
|
print("Serving on port 8000...")
|
|
httpd.serve_forever()
|