summaryrefslogtreecommitdiff
path: root/include/py/homekit/http/http.py
blob: a8c7d82501e54faf79d2983a5ef72f6e60e30882 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import logging
import asyncio
import html

from enum import Enum
from aiohttp import web
from aiohttp.web import HTTPFound
from aiohttp.web_exceptions import HTTPNotFound
from ..util import stringify, format_tb, Addr

_logger = logging.getLogger(__name__)


def _render_error(error_type, error_message, traceback=None, code=500):
    traceback_html = ''
    if traceback:
        traceback = '\n\n'.join(traceback)
        traceback_html = f"""
<div class="error_traceback">
    <div class="error_title">Traceback</div>
    <div class="error_traceback_content">{html.escape(traceback)}</div>
</div>
"""

    buf = f"""
<!doctype html>
<html lang=en>
<head>
<title>Error: {html.escape(error_type)}</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" type="text/css" href="/assets/error_page.css">
</head>
<body>
<div class="error_title">{html.escape(error_type)}</div>
<div class="error_message">{html.escape(error_message)}</div>
{traceback_html}
</body>
</html>
"""
    return web.Response(text=buf, status=code, content_type='text/html')


@web.middleware
async def errors_handler_middleware(request, handler):
    try:
        response = await handler(request)
        return response

    except HTTPNotFound:
        return _render_error(
            error_type='Not Found',
            error_message='The page you requested has not been found.',
            code=404
        )

    except HTTPFound as exc:
        raise exc

    except Exception as exc:
        _logger.exception(exc)
        return _render_error(
            error_type=exc.__class__.__name__,
            error_message=exc.message if hasattr(exc, 'message') else str(exc),
            traceback=format_tb(exc)
        )


def serve(addr: Addr, before_start=None, handle_signals=True, routes=None, event_loop=None):
    app = web.Application()
    app.middlewares.append(errors_handler_middleware)

    if routes is not None:
        app.add_routes(routes)

    if callable(before_start):
        before_start(app)

    if not event_loop:
        event_loop = asyncio.get_event_loop()

    runner = web.AppRunner(app, handle_signals=handle_signals)
    event_loop.run_until_complete(runner.setup())

    host, port = addr
    site = web.TCPSite(runner, host=host, port=port)
    event_loop.run_until_complete(site.start())

    _logger.info(f'Server started at http://{host}:{port}')

    event_loop.run_forever()


def ajax_ok(data=None):
    if data is None:
        data = 1
    response = {'response': data}
    return web.json_response(response, dumps=stringify)


class HTTPMethod(Enum):
    GET = 'GET'
    POST = 'POST'
    PUT = 'PUT'