forked from ahixon/jvc-remote
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver.py
166 lines (128 loc) · 4.55 KB
/
server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import json
from functools import wraps
from traceback import format_tb
from sys import exc_info
from wsgiref.simple_server import make_server
from wsgiref.util import shift_path_info
from projector import Button, InputSource, RS40, ProjectorCommunicationError
projector = None
class WebException(Exception):
def __init__(self, code, msg=None):
self.code = code
default_msgs = {
"404 Not Found": "The requested resource could not be found.",
"503 Service Unavailable": "The underlying service is not available.",
"500 Internal Server Error": "An internal exception occurred.",
}
if not msg:
if code in default_msgs:
self.msg = default_msgs[code]
else:
self.msg = ""
else:
self.msg = msg
def __repr__(self):
if not self.msg:
return self.code
return "%s: %s" % (self.code, self.msg)
def __str__(self):
return "<h1>%s</h1><p>%s</p>" % (self.code, self.msg)
def projector_command(f):
@wraps(f)
def decorated(*args, **kwargs):
try:
return f(*args, **kwargs)
except ProjectorCommunicationError:
raise WebException(
"503 Service Unavailable",
"Could not "
'communicate with projector "%s". Is it connected and '
"powered on?" % projector.url,
)
return decorated
# information only (this may change if we
# implement an auto-instanciated projector class)
def view_buttons():
return json.dumps({"names": projector.valid_buttons})
def view_inputs():
sources = {k: v for k, v in sorted(projector.valid_sources.items(), key=lambda x: x[1])}
return json.dumps(sources)
@projector_command
def press(button):
button = button.lower()
if button not in Button.CODES:
raise WebException("404 Not Found", "No such button " + button)
return json.dumps({"success": projector.press_button(button)})
@projector_command
def projector_status():
return json.dumps(
{"mode": projector.mode, "input": projector.input, "model": projector.model}
)
@projector_command
def set_input(source):
# source = source.lower()
if source not in projector.valid_sources:
raise WebException("404 Not Found", "Invalid source " + source)
return json.dumps({"success": projector.set_input(source)})
@projector_command
def on():
return json.dumps({"success": projector.turn_on()})
@projector_command
def off():
return json.dumps({"success": projector.turn_off()})
def index():
return open("index.html", "rt").read()
def remote_webapp(environ, start_response):
routes = {
"buttons": view_buttons,
"inputs": view_inputs,
"press": lambda: press(shift_path_info(environ)),
"status": projector_status,
"input": lambda: set_input(shift_path_info(environ)),
"on": on,
"off": off,
"": index,
}
result = None
base_path = shift_path_info(environ)
if base_path not in routes:
status = "404 Not Found"
headers = [("Content-type", "text/html")]
result = str(WebException(status))
else:
try:
handler = routes[base_path]
result = handler()
status = "200 OK" # HTTP Status
if handler == index:
headers = [("Content-type", "text/html")]
else:
headers = [("Content-type", "application/json")]
except WebException as ex:
status = ex.code
headers = [("Content-type", "text/html")]
result = str(ex)
except:
status = "500 Internal Server Error"
headers = [("Content-type", "text/html")]
e_type, e_value, tb = exc_info()
print(e_type, e_value)
html = (
"An internal exception occured. The stacktrace was: "
"</p><pre>%s\n%s</pre><p>"
% ("".join(format_tb(tb)), "%s: %s" % (e_type.__name__, e_value))
)
result = str(WebException(status, html))
start_response(status, headers)
result = result.encode("utf8")
return [result]
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
sys.stderr.write("Usage: %s [serial device]\n" % sys.argv[0])
else:
projector = RS40(sys.argv[1], timeout=0.4)
httpd = make_server("", 8000, remote_webapp)
print("Serving on port 8000...")
# Serve until process is killed
httpd.serve_forever()