|
@@ -2,40 +2,98 @@ import asyncio
|
2
|
2
|
import aiohttp
|
3
|
3
|
import json
|
4
|
4
|
from aiohttp import web
|
|
5
|
+import marshmallow
|
|
6
|
+from hapic import async as hapic
|
|
7
|
+from hapic.ext.aiohttp.context import AiohttpContext
|
5
|
8
|
|
6
|
9
|
|
7
|
|
-async def uptime_handler(request):
|
8
|
|
- resp = web.StreamResponse(
|
9
|
|
- status=200,
|
10
|
|
- reason='OK',
|
11
|
|
- headers={
|
12
|
|
- 'Content-Type': 'text/csv',
|
13
|
|
- 'Content-Disposition': 'attachment; filename="filename.csv"',
|
14
|
|
- }
|
15
|
|
- )
|
16
|
|
- await resp.prepare(request)
|
|
10
|
+class UptimeHandlerStreamItem(marshmallow.Schema):
|
|
11
|
+ datetime = marshmallow.fields.String(required=True)
|
|
12
|
+ a_bool = marshmallow.fields.Boolean(required=True)
|
|
13
|
+ a_float = marshmallow.fields.Number(required=True)
|
|
14
|
+ an_int = marshmallow.fields.Integer(required=True)
|
|
15
|
+ text = marshmallow.fields.String(required=True)
|
|
16
|
+ server = marshmallow.fields.String(required=True)
|
|
17
|
+ zone = marshmallow.fields.String(required=True)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+class LineModel(object):
|
|
21
|
+ def __init__(
|
|
22
|
+ self,
|
|
23
|
+ *column_values
|
|
24
|
+ ):
|
|
25
|
+ self.datetime = column_values[0]
|
|
26
|
+ self.a_bool = column_values[1]
|
|
27
|
+ self.a_float = column_values[2]
|
|
28
|
+ self.an_int = column_values[3]
|
|
29
|
+ self.text = column_values[4]
|
|
30
|
+ self.server = column_values[5]
|
|
31
|
+ self.zone = column_values[6]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+class AsyncGenerator:
|
|
35
|
+ def __init__(self, session):
|
|
36
|
+ self._session = session
|
|
37
|
+ self._url = 'http://localhost:8086/query?chunk_size=1000&chunked=true'\
|
|
38
|
+ '&db=resourceAux' \
|
|
39
|
+ '&q=SELECT+%2A+FROM+resource_aux'
|
|
40
|
+ self._buffer = []
|
|
41
|
+ self._buffer_iter = iter(self._buffer)
|
|
42
|
+
|
|
43
|
+ async def __aiter__(self):
|
|
44
|
+ response = await self._session.get(self._url)
|
|
45
|
+ self._stream_reader = response.content
|
|
46
|
+ return self
|
|
47
|
+
|
|
48
|
+ async def __anext__(self):
|
|
49
|
+ try:
|
|
50
|
+ try:
|
|
51
|
+ # First, send next item
|
|
52
|
+ return next(self._buffer_iter)
|
|
53
|
+ # If no more item in buffer, or not started
|
|
54
|
+ except StopIteration:
|
|
55
|
+ # Read from incoming data
|
|
56
|
+ line = await self._stream_reader.readline()
|
|
57
|
+ # If end of received lines
|
|
58
|
+ if not line:
|
|
59
|
+ # Break the iteration
|
|
60
|
+ raise StopAsyncIteration()
|
17
|
61
|
|
|
62
|
+ # load values from received package of incomming data
|
|
63
|
+ data = json.loads(line.decode('utf-8'))
|
|
64
|
+ values = data['results'][0]['series'][0]['values']
|
|
65
|
+
|
|
66
|
+ # Prepare new buffer
|
|
67
|
+ self._buffer = [LineModel(*value) for value in values]
|
|
68
|
+ self._buffer_iter = iter(self._buffer)
|
|
69
|
+
|
|
70
|
+ # Send an item
|
|
71
|
+ return next(self._buffer_iter)
|
|
72
|
+
|
|
73
|
+ except StopAsyncIteration:
|
|
74
|
+ await self._session.close()
|
|
75
|
+ raise
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+@hapic.with_api_doc()
|
|
79
|
+@hapic.output_stream(item_schema=UptimeHandlerStreamItem())
|
|
80
|
+async def uptime_handler(request):
|
18
|
81
|
try:
|
19
|
|
- async with aiohttp.ClientSession(loop=loop) as session:
|
20
|
|
- url = 'http://localhost:8086/query?chunk_size=1000&chunked=true&db=resourceAux&q=SELECT+%2A+FROM+resource_aux' # nopep8
|
21
|
|
- async with session.get(url) as response:
|
22
|
|
- async for chunk in response.content:
|
23
|
|
- bytes_to_str = chunk.decode('utf-8')
|
24
|
|
- result = json.loads(bytes_to_str)['results'][0]['series'][0]['values'] # nopep8
|
25
|
|
- for r in result:
|
26
|
|
- await resp.write(str.encode(str(r)+'\n'))
|
|
82
|
+ # NOTE: This session is currently closed in AsyncGenerator code
|
|
83
|
+ # it should be made otherwise in real code
|
|
84
|
+ session = aiohttp.ClientSession(loop=loop)
|
|
85
|
+ return AsyncGenerator(session)
|
27
|
86
|
|
28
|
87
|
except Exception as e:
|
29
|
88
|
# So you can observe on disconnects and such.
|
30
|
89
|
print(repr(e))
|
31
|
90
|
raise
|
32
|
91
|
|
33
|
|
- return resp
|
34
|
|
-
|
35
|
92
|
|
36
|
93
|
async def build_server(loop, address, port):
|
37
|
94
|
app = web.Application(loop=loop)
|
38
|
95
|
app.router.add_route('GET', "/uptime", uptime_handler)
|
|
96
|
+ hapic.set_context(AiohttpContext(app))
|
39
|
97
|
|
40
|
98
|
return await loop.create_server(app.make_handler(), address, port)
|
41
|
99
|
|