# -*- coding: utf-8 -
#
# This file is part of gaffer. See the NOTICE for more information.
import copy
import socket
# patch tornado IOLoop
from .tornado_pyuv import IOLoop, install
install()
import six
from tornado import netutil
from tornado.web import Application
from tornado.httpserver import HTTPServer
from .util import parse_address, is_ipv6
from . import http
DEFAULT_HANDLERS = [
(r'/', http.WelcomeHandler),
(r'/ping', http.PingHandler),
(r'/processes', http.ProcessesHandler),
(r'/processes/([0-9^/]+)', http.ProcessIdHandler),
(r'/processes/([^/]+)', http.ProcessHandler),
(r'/processes/([0-9^/]+)/(_[^/]+)$', http.ProcessIdManageHandler),
(r'/processes/([^/]+)/(_[^/]+)$', http.ProcessManagerHandler),
(r'/processes/([0-9^/]+)/(_[^/]+)/(.*)$', http.ProcessIdManageHandler),
(r'/processes/([^/]+)/(_[^/]+)/(.*)$', http.ProcessManagerHandler),
(r'/status/([^/]+)', http.StatusHandler),
(r'/watch', http.WatcherHandler),
(r'/watch/([^/]+)$', http.WatcherHandler),
(r'/watch/([^/]+)/([^/]+)$', http.WatcherHandler),
(r'/watch/([^/]+)/([^/]+)/([^/]+)$', http.WatcherHandler),
(r'/stats', http.StatsHandler),
(r'/stats/([^/]+)', http.StatsHandler),
(r'/stats/([^/]+)/([0-9^/]+)$', http.StatsHandler),
(r'/streams/([0-9^/]+)/([^/]+)$', http.StreamHandler),
(r'/wstreams/([0-9^/]+)$', http.WStreamHandler),
(r'/groups', http.GroupsHandler),
(r'/groups/([^/]+)$', http.GroupHandler),
(r'/groups/([^/]+)/(_[^/]+)$', http.GroupHandler),
]
[docs]class HttpEndpoint(object):
def __init__(self, uri='127.0.0.1:5000', backlog=128,
ssl_options=None):
# uri should be a list
if isinstance(uri, six.string_types):
self.uri = uri.split(",")
else:
self.uri = uri
self.backlog = backlog
self.ssl_options = ssl_options
self.server = None
self.loop = None
self.io_loop = None
def __str__(self):
return ",".join(self.uri)
[docs] def start(self, loop, app):
self.loop = loop
self.app = app
self.io_loop = IOLoop(_loop=loop)
self._start_server()
def _start_server(self):
self.server = HTTPServer(self.app, io_loop=self.io_loop,
ssl_options=self.ssl_options)
# bind the handler to needed interface
for uri in self.uri:
addr = parse_address(uri)
if isinstance(addr, six.string_types):
sock = netutil.bind_unix_socket(addr)
elif is_ipv6(addr[0]):
sock = netutil.bind_sockets(addr[1], address=addr[0],
family=socket.AF_INET6, backlog=self.backlog)
else:
sock = netutil.bind_sockets(addr[1], backlog=self.backlog)
if isinstance(sock, list):
for s in sock:
self.server.add_socket(s)
else:
self.server.add_socket(sock)
# start the server
self.server.start()
[docs] def stop(self):
self.server.stop()
self.io_loop.close(True)
[docs] def restart(self):
self.server.stop()
self._start_server()
[docs]class HttpHandler(object):
""" simple gaffer application that gives an HTTP API access to gaffer.
This application can listen on multiple endpoints (tcp or unix
sockets) with different options. Each endpoint can also listen on
different interfaces """
def __init__(self, endpoints=[], handlers=None, **settings):
self.endpoints = endpoints or []
if not endpoints: # if no endpoints passed add a default
self.endpoints.append(HttpEndpoint())
# set http handlers
self.handlers = copy.copy(DEFAULT_HANDLERS)
self.handlers.extend(handlers or [])
# custom settings
if 'manager' in settings:
del settings['manager']
self.settings = settings
[docs] def start(self, loop, manager):
self.loop = loop
self.manager = manager
self.app = Application(self.handlers, manager=self.manager,
**self.settings)
# start endpoints
for endpoint in self.endpoints:
endpoint.start(self.loop, self.app)
[docs] def stop(self):
for endpoint in self.endpoints:
endpoint.stop()
[docs] def restart(self):
for endpoint in self.endpoints:
endpoint.restart()