JunkVision/message.py

182 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()