Source

araldo / araldo / server.py

Full commit
#!/usr/bin/env python
""" Launches WSGI server process hosting WebSocketApp
"""
from __future__ import print_function
from optparse import OptionParser, OptionError
import os.path
import logging
import signal
import sys
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
from araldo.app import WebSocketApp
from araldo.sender import Sender
from araldo.config import Config
from araldo.plugin_manager import PluginManager

_log_level_map = {
    "debug": logging.DEBUG,
    "info": logging.INFO,
    "warning": logging.WARNING,
    "error": logging.ERROR,
    "critical": logging.CRITICAL
}


def start_server(
        config,
        port,
        queue,
        plugin_manager,
        start_method=lambda x: x.serve_forever()):
    """ Launches WSGI server that will listen forever
    """
    logger = logging.getLogger("araldo")
    logger.info("Starting server on port %d", port)
    server = pywsgi.WSGIServer(
        ("", port),
        WebSocketApp(config, queue, plugin_manager),
        handler_class=WebSocketHandler)
    start_method(server)


def setup_logging(config):
    """ Configure logger, log level, etc.
    """
    logging.basicConfig(
        level=logging.DEBUG)
    logger = logging.getLogger("araldo")
    log_level = config.settings()["global"].get("log-level", "debug")
    logger.setLevel(_log_level_map[log_level])
    #logger.addHandler(logging.StreamHandler())
    return logger


def setup_sending(config, queue, plugin_manager):
    """ Set up sending of outbound messages
    """
    sender = Sender(config, plugin_manager, queue)
    sender.start()
    return sender


def sig_handler(signum, frame):
    """ Handles abortion; e.g. by pressing CTRL+C
    """
    print("sig_handler: %s %s" % (signum, frame))
    sys.exit(1)


def setup_signals():
    """ Setup OS signals for graceful termination of server
    """
    signal.signal(signal.SIGTERM, sig_handler)
    signal.signal(signal.SIGQUIT, sig_handler)


def setup_plugins(logger, config):
    """ Load and instantiate plugins
    """
    plugin_manager = PluginManager(config)
    plugin_instances = plugin_manager.plugin_instances()
    endpoint_handlers = plugin_instances["araldo.endpoints.endpoint"]
    logger.debug("Starting %d endpoint handlers", len(endpoint_handlers))
    for handler in endpoint_handlers.values():
        handler.start()
    return plugin_manager


def parse_args(args):
    """ Get parser for command line parameters
    """
    parser = OptionParser()
    conf_file_opt = parser.add_option(
        "-c", "--config", action="store",
        dest="config",
        default="araldo.yaml",
        help="Configuration path")
    options, args = parser.parse_args(args)

    if not os.path.exists(options.config):
        raise OptionError(
            "Configuration file %s not found\n" % options.config,
            conf_file_opt
        )
    return parser, options, args


def main():
    """ Server main method
    """
    try:
        parser, options, args = parse_args(sys.argv[1:])
    except OptionError as error:
        sys.stderr.write(str(error))
        sys.stderr.write(parser.usage)
        sys.exit(1)

    config = Config.create(options.config)
    logger = setup_logging(config)

    setup_signals()
    plugin_manager = setup_plugins(logger, config)

    queue = plugin_manager.gevent_queue()
    setup_sending(config, queue, plugin_manager)
    start_server(
        config,
        config.settings()["global"]["server-port"],
        queue,
        plugin_manager)


if __name__ == '__main__':
    main()