
Still WIP, message handler does something at least if started. GUI is somewhat broken though.
181 lines
6.1 KiB
Python
181 lines
6.1 KiB
Python
import requests
|
|
import json
|
|
|
|
import BaseHTTPServer
|
|
|
|
from threading import Thread
|
|
|
|
class MessageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|
access_denied_text = """
|
|
<html>
|
|
<head><title>JunkVision - 403 Forbidden</title></head>
|
|
<base>
|
|
<h1>403 Forbidden</h1>
|
|
<h2>Only LAN is allowed.</h2>
|
|
<p>Contact <a href="mailto:bofh@hackerspace.pl">BOFHs</a> for access.</p>
|
|
</base>
|
|
</html>
|
|
"""
|
|
|
|
not_found_text = """
|
|
<html>
|
|
<head><title>JunkVision - 404 Not Found</title></head>
|
|
<base>
|
|
<h1>404 Not found</h1>
|
|
</base>
|
|
</html>
|
|
"""
|
|
|
|
bad_request_text = """
|
|
<html>
|
|
<head><title>JunkVision - 400 Bad Request</title></head>
|
|
<base>
|
|
<h1>400 Bad Request</h1>
|
|
</base>
|
|
</html>
|
|
"""
|
|
|
|
def do_GET(self):
|
|
self.server_version = "JunkVision/0.5"
|
|
self.sys_version = ""
|
|
self.protocol_version = "HTTP/1.1"
|
|
if not self.client_address[0].startswith("10.8.") and self.client_address[0] != "127.0.0.1":
|
|
self.send_response(403)
|
|
self.send_default_headers()
|
|
self.send_header("Content-Type", "text/html; charset=utf-8")
|
|
self.send_header("Content-Length", "%d" % len(self.access_denied_text))
|
|
self.end_headers()
|
|
self.wfile.write(self.access_denied_text)
|
|
return
|
|
|
|
data = {}
|
|
data['json_response'] = self.server.get_default_data()
|
|
|
|
if self.path.startswith("/image/"):
|
|
try:
|
|
area = int(self.path.split("/")[2])
|
|
except (ValueError, IndexError):
|
|
self.send_bad_request()
|
|
# TODO: logging
|
|
print "Bad request", self.path
|
|
return
|
|
|
|
img_jpg = self.server.engine.get_image(int(area))
|
|
self.send_image(img_jpg)
|
|
return
|
|
|
|
elif self.path.startswith("/status/"):
|
|
data['json_response'].append({'type': 'status'})
|
|
if self.path == "/status/":
|
|
for area_id in xrange(len(self.server.engine.get_areas())):
|
|
data['json_response'].append(self.server.get_status_data(area_id))
|
|
else:
|
|
try:
|
|
area = int(self.path.split("/")[2])
|
|
if area < 0 or area > len(self.server.engine.get_areas()):
|
|
raise IndexError("Area out of range")
|
|
data['json_response'].append(self.server.get_status_data(area))
|
|
except (ValueError, IndexError):
|
|
self.send_bad_request()
|
|
# TODO: logging
|
|
print "Bad request", self.path
|
|
return
|
|
|
|
else:
|
|
self.send_response(404)
|
|
self.send_default_headers()
|
|
self.send_header("Content-Type", "text/html; charset=utf-8")
|
|
self.send_header("Content-Length", "%d" % len(self.not_found_text))
|
|
self.end_headers()
|
|
self.wfile.write(self.not_found_text)
|
|
return
|
|
|
|
self.send_response(200)
|
|
self.send_default_headers()
|
|
self.send_header("Content-Type", "application/json; charset=utf-8")
|
|
json_text = json.dumps(data)
|
|
self.send_header("Content-Length", "%d" % len(json_text))
|
|
self.send_header("Cache-Control", "max-age=60")
|
|
self.end_headers()
|
|
self.wfile.write(json_text)
|
|
|
|
def send_default_headers(self):
|
|
self.send_header("Connection", "close")
|
|
self.send_header("Transfer-Encoding", "identity")
|
|
self.send_header("Allow", "GET")
|
|
|
|
def send_bad_request(self):
|
|
self.send_response(400)
|
|
self.send_default_headers()
|
|
self.send_header("Content-Type", "text/html; charset=utf-8")
|
|
self.send_header("Content-Length", "%d" % len(self.bad_request_text))
|
|
self.end_headers()
|
|
self.wfile.write(self.bad_request_text)
|
|
|
|
def send_image(self, img):
|
|
self.send_response(200)
|
|
self.send_default_headers()
|
|
# XXX: parametrize?
|
|
self.send_header("Content-Type", "image/jpeg")
|
|
self.send_header("Content-Length", "%d" % len(img))
|
|
self.send_header("Cache-Control", "no-store")
|
|
self.end_headers()
|
|
self.wfile.write(img)
|
|
|
|
|
|
|
|
class MessageServer(BaseHTTPServer.HTTPServer):
|
|
def __init__(self, engine):
|
|
BaseHTTPServer.HTTPServer.__init__(self, ("0.0.0.0", 4580), MessageHandler)
|
|
self.engine = engine
|
|
self.camera_id = "Unknown"
|
|
self.enabled = False
|
|
|
|
def set_camera_id(self, camera_id):
|
|
self.camera_id = camera_id
|
|
|
|
def set_status_target(self, status_url):
|
|
self.status_target = status_url
|
|
|
|
def get_default_data(self):
|
|
return [{"camera_id": self.camera_id}]
|
|
|
|
def get_status_data(self, area_id):
|
|
return {
|
|
"area_id": area_id,
|
|
"area_rect": self.engine.get_areas()[area_id],
|
|
"last_movement": self.engine.get_movement_time(area_id),
|
|
"last_percent_mess": self.engine.get_percent_mess(area_id)
|
|
}
|
|
|
|
def send_status(self, area_id=-1):
|
|
data = {}
|
|
data['status'] = self.get_default_data()
|
|
if area_id < 0:
|
|
for area_id in engine.get_areas():
|
|
data['status'].append(self.get_status_data(area_id))
|
|
else:
|
|
data['status'].append(self.get_status_data(area_id))
|
|
|
|
json_text = json.dumps(data)
|
|
headers = [("Content-Type", "application/json; charset=utf-8"),
|
|
("Content-Length", "%d" % len(json_text)),
|
|
("Server", "JunkVision/0.5")]
|
|
resp = requests.post(self.status_target, data=json_text, headers=headers)
|
|
# TODO: logging
|
|
print resp
|
|
|
|
def start(self):
|
|
if self.enabled:
|
|
raise RuntimeError("Message handler is already started!")
|
|
self.thread = Thread(target=self.run, name="JunkVision MessageHandler")
|
|
self.enabled = True
|
|
self.thread.start()
|
|
|
|
def stop(self):
|
|
self.enabled = False
|
|
self.thread.join()
|
|
|
|
def run(self):
|
|
while self.enabled:
|
|
self.handle_request()
|