Mercurial > code > home > repos > environment
comparison environment.py @ 3:e7f33fa31883
port to starlette/asyncio
author | drewp@bigasterisk.com |
---|---|
date | Sun, 24 Apr 2022 14:46:32 -0700 |
parents | 0f532eb91364 |
children | b5bfd0dd69d6 |
comparison
equal
deleted
inserted
replaced
2:a547c300bd6e | 3:e7f33fa31883 |
---|---|
2 """ | 2 """ |
3 return some rdf about the environment, e.g. the current time, | 3 return some rdf about the environment, e.g. the current time, |
4 daytime/night, overall modes like 'maintenance mode', etc | 4 daytime/night, overall modes like 'maintenance mode', etc |
5 | 5 |
6 """ | 6 """ |
7 import asyncio | |
7 import datetime | 8 import datetime |
8 | 9 import logging |
9 import cyclone.web | |
10 from dateutil.relativedelta import FR, relativedelta | 10 from dateutil.relativedelta import FR, relativedelta |
11 from dateutil.tz import tzlocal | 11 from dateutil.tz import tzlocal |
12 from docopt import docopt | 12 from prometheus_client import Gauge, Summary |
13 from rdflib import Literal, Namespace | 13 from rdflib import Literal, Namespace |
14 from twisted.internet import defer, reactor, task | 14 from starlette.applications import Starlette |
15 from starlette.routing import Route | |
16 from starlette.staticfiles import StaticFiles | |
17 from starlette_exporter import PrometheusMiddleware, handle_metrics | |
15 | 18 |
16 from standardservice.logsetup import log, verboseLogging | 19 import background_loop |
17 from patchablegraph import (CycloneGraphEventsHandler, CycloneGraphHandler, PatchableGraph) | 20 from patchablegraph import PatchableGraph |
18 | 21 from patchablegraph.handler import StaticGraph, GraphEvents |
19 from patch_cyclone import patch_sse | 22 # from rdfdoc import Doc |
20 from rdfdoc import Doc | |
21 from twilight import isWithinTwilight | 23 from twilight import isWithinTwilight |
22 | |
23 patch_sse() | |
24 | 24 |
25 ROOM = Namespace("http://projects.bigasterisk.com/room/") | 25 ROOM = Namespace("http://projects.bigasterisk.com/room/") |
26 DEV = Namespace("http://projects.bigasterisk.com/device/") | 26 DEV = Namespace("http://projects.bigasterisk.com/device/") |
27 | 27 |
28 # STATS = scales.collection( | 28 logging.basicConfig(level=logging.INFO) |
29 # '/root', | 29 |
30 # scales.PmfStat('update'), | 30 STAT_UPDATE_UP = Gauge('background_loop_up', 'not erroring') |
31 # ) | 31 STAT_UPDATE_CALLS = Summary('background_loop_calls', 'calls') |
32 | 32 |
33 | 33 |
34 # see pending fix in patchablegraph.py | 34 def update(masterGraph): |
35 class CycloneGraphEventsHandlerWithCors(CycloneGraphEventsHandler): | |
36 | 35 |
37 def __init__(self, application, request, masterGraph, allowOrigins=None): | 36 def stmt(s, p, o): |
38 super().__init__(application, request, masterGraph) | 37 masterGraph.patchObject(ROOM.environment, s, p, o) |
39 self.allowOrigins = allowOrigins or [] | |
40 | |
41 def flush(self): | |
42 origin = self.request.headers.get('origin', None) | |
43 if origin and origin in self.allowOrigins: | |
44 self.set_header(b"Access-Control-Allow-Origin", origin.encode('utf8')) | |
45 self.set_header(b"Access-Control-Allow-Credentials", b"true") | |
46 return CycloneGraphEventsHandler.flush(self) | |
47 | |
48 | |
49 # @STATS.update.time() | |
50 def update(masterGraph): | |
51 stmt = lambda s, p, o: masterGraph.patchObject(ROOM.environment, s, p, o) | |
52 | 38 |
53 now = datetime.datetime.now(tzlocal()) | 39 now = datetime.datetime.now(tzlocal()) |
54 | 40 |
55 stmt(DEV.environment, ROOM.localHour, Literal(now.hour)) | 41 stmt(DEV.environment, ROOM.localHour, Literal(now.hour)) |
56 stmt(DEV.environment, ROOM.localTimeToMinute, Literal(now.strftime("%H:%M"))) | 42 stmt(DEV.environment, ROOM.localTimeToMinute, Literal(now.strftime("%H:%M"))) |
68 | 54 |
69 stmt(DEV.calendar, ROOM.twilight, ROOM['withinTwilight'] if isWithinTwilight(now) else ROOM['daytime']) | 55 stmt(DEV.calendar, ROOM.twilight, ROOM['withinTwilight'] if isWithinTwilight(now) else ROOM['daytime']) |
70 | 56 |
71 | 57 |
72 def main(): | 58 def main(): |
73 arg = docopt(""" | |
74 Usage: environment.py [options] | |
75 | |
76 -v Verbose | |
77 """) | |
78 verboseLogging(arg['-v']) | |
79 | |
80 masterGraph = PatchableGraph() | 59 masterGraph = PatchableGraph() |
81 | 60 |
82 class Application(cyclone.web.Application): | 61 asyncio.create_task(background_loop.loop_forever(lambda first: update(masterGraph), 1, STAT_UPDATE_UP, STAT_UPDATE_CALLS)) |
83 | 62 |
84 def __init__(self): | 63 app = Starlette( |
85 handlers = [ | 64 debug=True, |
86 (r"/()", cyclone.web.StaticFileHandler, { | 65 routes=[ |
87 "path": ".", | 66 Route('/', StaticFiles(directory='.', html=True)), |
88 "default_filename": "index.html" | 67 Route('/graph/environment', StaticGraph(masterGraph)), |
89 }), | 68 Route('/graph/environment/events', GraphEvents(masterGraph)), |
90 (r'/graph/environment', CycloneGraphHandler, { | 69 # Route('/doc', Doc), |
91 'masterGraph': masterGraph | 70 ]) |
92 }), | |
93 (r'/graph/environment/events', CycloneGraphEventsHandlerWithCors, { | |
94 'masterGraph': masterGraph, | |
95 'allowOrigins': ['http://localhost:8001'], | |
96 }), | |
97 (r'/doc', Doc), # to be shared | |
98 # (r'/stats/(.*)', StatsHandler, { | |
99 # 'serverName': 'environment' | |
100 # }), | |
101 ] | |
102 cyclone.web.Application.__init__(self, handlers, masterGraph=masterGraph) | |
103 | 71 |
104 task.LoopingCall(update, masterGraph).start(1) | 72 app.add_middleware(PrometheusMiddleware, app_name='environment') |
105 reactor.listenTCP(8000, Application()) | 73 app.add_route("/metrics", handle_metrics) |
106 reactor.run() | 74 return app |
107 | 75 |
108 | 76 |
109 if __name__ == '__main__': | 77 app = main() |
110 main() |