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)