Skip to content

Commit 40711f6

Browse files
committed
server routing cleanups
1 parent 52addd9 commit 40711f6

File tree

5 files changed

+101
-72
lines changed

5 files changed

+101
-72
lines changed

src/ghhops-server-py/examples/app.py

+12-10
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def BinaryMultiply(a: float, b: float):
4444
hs.HopsNumber("A", "A", "First number"),
4545
hs.HopsNumber("B", "B", "Second number"),
4646
],
47-
outputs=[hs.HopsNumber("Sum", "S", "A + B")]
47+
outputs=[hs.HopsNumber("Sum", "S", "A + B")],
4848
)
4949
def add(a: float, b: float):
5050
return a + b
@@ -58,9 +58,9 @@ def add(a: float, b: float):
5858
icon="pointat.png",
5959
inputs=[
6060
hs.HopsCurve("Curve", "C", "Curve to evaluate"),
61-
hs.HopsNumber("t", "t", "Parameter on Curve to evaluate")
61+
hs.HopsNumber("t", "t", "Parameter on Curve to evaluate"),
6262
],
63-
outputs=[hs.HopsPoint("P", "P", "Point on curve at t")]
63+
outputs=[hs.HopsPoint("P", "P", "Point on curve at t")],
6464
)
6565
def pointat(curve: rhino3dm.Curve, t=0.0):
6666
return curve.PointAt(t)
@@ -75,18 +75,20 @@ def pointat(curve: rhino3dm.Curve, t=0.0):
7575
hs.HopsPoint("Corner A", "A", "First corner"),
7676
hs.HopsPoint("Corner B", "B", "Second corner"),
7777
hs.HopsPoint("Corner C", "C", "Third corner"),
78-
hs.HopsPoint("Corner D", "D", "Fourth corner")
78+
hs.HopsPoint("Corner D", "D", "Fourth corner"),
7979
],
80-
outputs=[hs.HopsSurface("Surface", "S", "Resulting surface")]
80+
outputs=[hs.HopsSurface("Surface", "S", "Resulting surface")],
8181
)
82-
def ruled_surface(a: rhino3dm.Point3d,
83-
b: rhino3dm.Point3d,
84-
c: rhino3dm.Point3d,
85-
d: rhino3dm.Point3d):
82+
def ruled_surface(
83+
a: rhino3dm.Point3d,
84+
b: rhino3dm.Point3d,
85+
c: rhino3dm.Point3d,
86+
d: rhino3dm.Point3d,
87+
):
8688
edge1 = rhino3dm.LineCurve(a, b)
8789
edge2 = rhino3dm.LineCurve(c, d)
8890
return rhino3dm.NurbsSurface.CreateRuledSurface(edge1, edge2)
8991

9092

9193
if __name__ == "__main__":
92-
app.run(debug=True)
94+
app.run()

src/ghhops-server-py/examples/app_http.py

+17-10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55
hops = hs.Hops()
66

77

8+
@hops.component(
9+
"/binmult",
10+
inputs=[hs.HopsNumber("A"), hs.HopsNumber("B")],
11+
outputs=[hs.HopsNumber("Multiply")],
12+
)
13+
def BinaryMultiply(a: float, b: float):
14+
return a * b
15+
16+
817
@hops.component(
918
"/add",
1019
name="Add",
@@ -14,7 +23,7 @@
1423
hs.HopsNumber("A", "A", "First number"),
1524
hs.HopsNumber("B", "B", "Second number"),
1625
],
17-
outputs=[hs.HopsNumber("Sum", "S", "A + B")]
26+
outputs=[hs.HopsNumber("Sum", "S", "A + B")],
1827
)
1928
def add(a, b):
2029
return a + b
@@ -30,9 +39,7 @@ def add(a, b):
3039
hs.HopsCurve("Curve", "C", "Curve to evaluate"),
3140
hs.HopsNumber("t", "t", "Parameter on Curve to evaluate"),
3241
],
33-
outputs=[
34-
hs.HopsPoint("P", "P", "Point on curve at t")
35-
]
42+
outputs=[hs.HopsPoint("P", "P", "Point on curve at t")],
3643
)
3744
def pointat(curve, t=0.0):
3845
return curve.PointAt(t)
@@ -48,11 +55,11 @@ def pointat(curve, t=0.0):
4855
icon="pointat.png",
4956
inputs=[
5057
hs.HopsCurve("Curve", "C", "Curve to evaluate"),
51-
hs.HopsNumber("t", "t", "Parameters on Curve to evaluate", hs.HopsParamAccess.LIST),
58+
hs.HopsNumber(
59+
"t", "t", "Parameters on Curve to evaluate", hs.HopsParamAccess.LIST
60+
),
5261
],
53-
outputs=[
54-
hs.HopsPoint("P", "P", "Points on curve at t")
55-
]
62+
outputs=[hs.HopsPoint("P", "P", "Points on curve at t")],
5663
)
5764
def pointsat(curve, t):
5865
points = [curve.PointAt(item) for item in t]
@@ -68,9 +75,9 @@ def pointsat(curve, t):
6875
hs.HopsPoint("Corner A", "A", "First corner"),
6976
hs.HopsPoint("Corner B", "B", "Second corner"),
7077
hs.HopsPoint("Corner C", "C", "Third corner"),
71-
hs.HopsPoint("Corner D", "D", "Fourth corner")
78+
hs.HopsPoint("Corner D", "D", "Fourth corner"),
7279
],
73-
outputs=[hs.HopsSurface("Surface", "S", "Resulting surface")]
80+
outputs=[hs.HopsSurface("Surface", "S", "Resulting surface")],
7481
)
7582
def ruled_surface(a, b, c, d):
7683
edge1 = rhino3dm.LineCurve(a, b)

src/ghhops-server-py/ghhops_server/base.py

+59-12
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
class HopsBase:
1919
"""Base class for all Hops middleware implementations"""
2020

21-
SOLVE_URI = "/solve"
21+
ROOT_ROUTE = "/"
22+
SOLVE_ROUTE = "/solve"
23+
24+
BUILTIN_ROUTES = [ROOT_ROUTE, SOLVE_ROUTE]
2225

2326
ERROR_PAGE_405 = """<!doctype html>
2427
<html lang=en>
@@ -33,13 +36,57 @@ def __init__(self, app):
3336
# it is assumed that uri and solve uri and both unique to the component
3437
self._components: dict[str, HopsComponent] = {}
3538

36-
def handles(self, uri):
37-
return uri == HopsBase.SOLVE_URI or uri in self._components
39+
def handles(self, request):
40+
uri = request.path
41+
return uri in HopsBase.BUILTIN_ROUTES or uri in self._components
42+
43+
def handle_HEAD(self, _):
44+
return self._prep_response(200, "Success")
45+
46+
def handle_GET(self, request):
47+
uri = request.path
48+
49+
# if calling GET /solve, respond 405
50+
if self._is_solve_uri(uri):
51+
return self._return_method_not_allowed()
52+
53+
# if component exists, return component data
54+
res, results = self.query(uri=uri)
55+
if res:
56+
response = self._prep_response()
57+
response.data = results
58+
59+
# otherwise return 404
60+
else:
61+
response = self._prep_response(404, "Unknown URI")
62+
63+
return response
64+
65+
def handle_POST(self, request):
66+
uri = request.path
67+
68+
# if POST on component uri, return 405
69+
if self._is_comp_uri(uri):
70+
return self._return_method_not_allowed()
71+
72+
# otherwise try to solve with payload
73+
data = request.data
74+
res, results = self.solve(uri=uri, payload=data)
75+
if res:
76+
response = self._prep_response()
77+
response.data = results.encode(encoding="utf_8")
78+
79+
# otherwise return 404
80+
else:
81+
response = self._prep_response(404, "Execution Error")
82+
response.data = results.encode(encoding="utf_8")
83+
84+
return response
3885

39-
def is_solve_uri(self, uri):
40-
return uri == HopsBase.SOLVE_URI
86+
def _is_solve_uri(self, uri):
87+
return uri == HopsBase.SOLVE_ROUTE
4188

42-
def is_comp_uri(self, uri):
89+
def _is_comp_uri(self, uri):
4390
return uri in self._components
4491

4592
def query(self, uri) -> Tuple[bool, str]:
@@ -62,16 +109,16 @@ def query(self, uri) -> Tuple[bool, str]:
62109

63110
def solve(self, uri, payload) -> Tuple[bool, str]:
64111
"""Perform Solve on given uri"""
65-
if uri == "/":
112+
if uri == HopsBase.ROOT_ROUTE:
66113
hlogger.debug("Nothing to solve on root")
67114
return False, self._return_with_err("Nothing to solve on root")
68115

69116
# FIXME: remove support for legacy solve behaviour
70-
elif uri == HopsBase.SOLVE_URI:
117+
elif uri == HopsBase.SOLVE_ROUTE:
71118
data = json.loads(payload)
72119
comp_uri = data["pointer"]
73-
if not comp_uri.startswith("/"):
74-
comp_uri = "/" + comp_uri
120+
if not comp_uri.startswith(HopsBase.ROOT_ROUTE):
121+
comp_uri = HopsBase.ROOT_ROUTE + comp_uri
75122
for comp in self._components.values():
76123
if comp_uri == comp.uri:
77124
hlogger.info("Solving using legacy API: %s", comp)
@@ -98,10 +145,10 @@ def _return_with_err(self, err_msg, res_dict=None):
98145

99146
return json.dumps(err_res, cls=_HopsEncoder)
100147

101-
def _return_method_not_allowed(self, environ, start_response):
148+
def _return_method_not_allowed(self):
102149
response = self._prep_response(405, "Method Not Allowed")
103150
response.data = HopsBase.ERROR_PAGE_405.encode(encoding="utf_8")
104-
return response(environ, start_response)
151+
return response
105152

106153
def _get_all_comps_data(self):
107154
# return json formatted string of all components metadata

src/ghhops-server-py/ghhops_server/middlewares/hopsdefault.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ def _prep_response(self, status=200, msg=None):
4747
self.send_header("Content-type", "application/json")
4848
self.end_headers()
4949

50+
def do_HEAD(self):
51+
self._prep_response()
52+
5053
def do_GET(self):
5154
# grab the path before url params
5255
comp_uri = self._get_comp_uri()
@@ -58,9 +61,6 @@ def do_GET(self):
5861
else:
5962
self._prep_response(status=404)
6063

61-
def do_HEAD(self):
62-
self._prep_response()
63-
6464
def do_POST(self):
6565
# read the message and convert it into a python dictionary
6666
comp_uri = self._get_comp_uri()

src/ghhops-server-py/ghhops_server/middlewares/hopsflask.py

+10-37
Original file line numberDiff line numberDiff line change
@@ -27,52 +27,25 @@ def __call__(self, environ, start_response):
2727
request = Request(environ)
2828

2929
method = request.method
30-
comp_uri = request.path
3130

32-
# if uri is registered on the hops app
33-
if self.handles(comp_uri):
34-
if method == "GET":
35-
# if calling GET /solve, respond 405
36-
if self.is_solve_uri(comp_uri):
37-
return self._return_method_not_allowed(
38-
environ,
39-
start_response
40-
)
31+
# if hops app handled this request
32+
if self.handles(request):
33+
response = None
4134

42-
# if component exists, return component data
43-
res, results = self.query(uri=comp_uri)
44-
if res:
45-
response = self._prep_response()
46-
response.data = results
35+
if method == "HEAD":
36+
response = self.handle_HEAD(request)
4737

48-
# otherwise return 404
49-
else:
50-
response = self._prep_response(404, "Unknown URI")
51-
52-
return response(environ, start_response)
38+
elif method == "GET":
39+
response = self.handle_GET(request)
5340

5441
elif method == "POST":
55-
# if POST on component uri, return 405
56-
if self.is_comp_uri(comp_uri):
57-
return self._return_method_not_allowed(
58-
environ,
59-
start_response
60-
)
61-
62-
# otherwise try to solve with payload
63-
data = request.data
64-
res, results = self.solve(uri=comp_uri, payload=data)
65-
if res:
66-
response = self._prep_response()
67-
response.data = results.encode(encoding="utf_8")
68-
else:
69-
response = self._prep_response(404, "Execution Error")
70-
response.data = results.encode(encoding="utf_8")
42+
response = self.handle_POST(request)
7143

44+
if response:
7245
return response(environ, start_response)
7346

7447
# respond with 405 if method is not valid
75-
return self._return_method_not_allowed(environ, start_response)
48+
return self._return_method_not_allowed()
7649

7750
# otherwise ask wapped app to process the call
7851
return self.wsgi_app(environ, start_response)

0 commit comments

Comments
 (0)