summaryrefslogblamecommitdiff
path: root/plugins/restapi.py
blob: 5b1d0eb247f9ea06e00494e9e542b293ed91b98f (plain) (tree)




















































































































































                                                                              
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)