summaryrefslogtreecommitdiff
path: root/plugins/restapi.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/restapi.py')
-rw-r--r--plugins/restapi.py149
1 files changed, 149 insertions, 0 deletions
diff --git a/plugins/restapi.py b/plugins/restapi.py
new file mode 100644
index 0000000..5b1d0eb
--- /dev/null
+++ b/plugins/restapi.py
@@ -0,0 +1,149 @@
+import asyncore
+import asynchat
+import socket
+import logging
+import json
+from collections import deque
+from BaseHTTPServer import BaseHTTPRequestHandler
+
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
+import commands
+
+__all__ = [ 'PLUGIN', 'init' ]
+
+PLUGIN = {
+ 'name': 'restapi',
+ 'requires': (),
+ 'blocks': (),
+ 'default_config' : {
+ 'rest_ip': '127.0.0.1',
+ 'rest_port': '8971',
+ }
+}
+
+last_id = 0
+log_history = deque(maxlen=200)
+
+
+def collect_messages(since_id):
+ ss = []
+ for m_id, m_text in log_history:
+ if m_id >= since_id:
+ ss.append({'id': m_id, 'message': m_text})
+
+ return json.dumps(ss)
+
+
+class RequestHandler(asynchat.async_chat, BaseHTTPRequestHandler):
+
+ protocol_version = "HTTP/1.1"
+
+ def __init__(self, conn, addr, server):
+ asynchat.async_chat.__init__(self, conn)
+ self.client_address = addr
+ self.connection = conn
+ self.server = server
+ self.set_terminator('\r\n\r\n')
+ self.rfile = StringIO()
+ self.wfile = StringIO()
+ self.found_terminator = self.handle_request_line
+
+ def collect_incoming_data(self, data):
+ """Collect the data arriving on the connexion"""
+ self.rfile.write(data)
+
+ def prepare_POST(self):
+ """Prepare to read the request body"""
+ bytesToRead = int(self.headers.getheader('Content-Length'))
+ # set terminator to length (will read bytesToRead bytes)
+ self.set_terminator(bytesToRead)
+ self.rfile = StringIO()
+ # control will be passed to a new found_terminator
+ self.found_terminator = self.handle_post_data
+
+ def handle_post_data(self):
+ """Called when a POST request body has been read"""
+ self.rfile.seek(0)
+ self.do_POST()
+ self.finish()
+
+ def handle_request_line(self):
+ """Called when the http request line and headers have been received"""
+ self.rfile.seek(0)
+ self.raw_requestline = self.rfile.readline()
+ self.parse_request()
+
+ if self.command == 'GET':
+ self.do_GET()
+ self.finish()
+ elif self.command == 'POST':
+ self.prepare_POST()
+ else:
+ self.send_error(501)
+
+ def finish(self):
+ data = self.wfile.getvalue()
+ self.push(data)
+ self.close_when_done()
+
+ def do_GET(self):
+ try:
+ since_id = int(self.path[1:])
+ except ValueError:
+ self.send_error(400)
+ return
+
+ response = collect_messages(since_id)
+ self.send_response(200)
+ self.send_header("Content-type", "application/json")
+ self.end_headers()
+ self.wfile.write(response)
+
+ def do_POST(self):
+ cmd = self.rfile.getvalue()
+ commands.process_line(cmd)
+ self.send_response(200)
+
+
+class Server(asyncore.dispatcher):
+
+ def __init__(self, ip, port, handler):
+ asyncore.dispatcher.__init__(self)
+ self.handler = handler
+ self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.set_reuse_addr()
+ self.bind((ip, port))
+ self.listen(5)
+
+ def handle_accept(self):
+ try:
+ conn, addr = self.accept()
+ except:
+ self.log_info('handle_accept() error', 'warning')
+ return
+
+ self.handler(conn, addr, self)
+
+
+class RestDebugLogHandler(logging.Handler):
+ def emit(self, record):
+ global last_id
+ msg = self.format(record)
+ last_id += 1
+ log_history.append((last_id, msg))
+
+
+def init(config):
+ debuglog = logging.getLogger("ManaChat.Debug")
+ dbgh = RestDebugLogHandler()
+ dbgh.setFormatter(logging.Formatter("[%(asctime)s] %(message)s",
+ datefmt="%H:%M:%S"))
+ debuglog.addHandler(dbgh)
+
+ ip = config.get(PLUGIN['name'], 'rest_ip')
+ port = config.getint(PLUGIN['name'], 'rest_port')
+ Server(ip, port, RequestHandler)