changeset 1:f66df122f18d

get the skeleton of a webserver up?
author Paul Fisher <paul@pfish.zone>
date Sun, 29 Sep 2019 00:52:13 -0400
parents efe7a1eff167
children cda47993a193
files weather_server/locations.py weather_server/server.py weather_server/static/favicon.ico weather_server/templates/location.html
diffstat 3 files changed, 137 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/weather_server/locations.py	Sun Sep 29 00:52:13 2019 -0400
@@ -0,0 +1,54 @@
+"""Manages the directory containing the various logs."""
+
+import configparser
+import pathlib
+import typing as t
+
+import attr
+import pytz
+
+from . import logfile
+from . import types
+
+
+CONFIG_FILE = 'config.ini'
+LOG = 'log.bson'
+
+
+@attr.s(frozen=True, slots=True)
+class LocationInfo:
+    name = attr.ib(type=str)
+    tz_name = attr.ib(type=str)
+    password = attr.ib(type=str)
+
+    def timezone(self):
+        try:
+            return pytz.timezone(self.tz_name)
+        except pytz.UnknownTimeZoneError:
+            return pytz.UTC
+
+    @classmethod
+    def load(cls, config_file: pathlib.Path) -> 'LocationInfo':
+        parser = configparser.ConfigParser(interpolation=None)
+        parser.read(config_file)
+        return LocationInfo(
+            name=parser.get('location', 'name', fallback='Weather station'),
+            tz_name=parser.get('location', 'timezone', fallback='UTC'),
+            password=parser.get('location', 'password'))
+
+
+class Locations:
+    def __init__(self, base: str):
+        self._path = pathlib.Path(base)
+
+    def paths(self) -> t.Tuple[str, ...]:
+        return tuple(sorted(f.name for f in self._path.iterdir()))
+
+    def get(self, name) -> t.Tuple[LocationInfo, logfile.Logger]:
+        try:
+            directory = self._path / name
+            return (
+                LocationInfo.load(directory / CONFIG_FILE),
+                logfile.Logger.create(str(directory / LOG)))
+        except OSError:
+            raise KeyError(name)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/weather_server/server.py	Sun Sep 29 00:52:13 2019 -0400
@@ -0,0 +1,69 @@
+import bson
+import flask
+
+from . import common
+from . import locations
+from . import types
+
+
+def build_app(root_directory: str) -> flask.Flask:
+    locs = locations.Locations(root_directory)
+    app = flask.Flask(__name__)
+
+    @app.route('/favicon.ico')
+    def favicon():
+        return flask.send_file('static/favicon.ico')
+
+    @app.route('/')
+    def home():
+        return 'Weather server'
+
+    @app.route('/_submit', methods=['POST'])
+    def submit():
+        req = flask.request
+        target = req.args.get('location')
+        if not target:
+            flask.abort(404)
+        try:
+            target_loc = locs.get(target)
+        except KeyError:
+            flask.abort(404)
+
+        password = req.args.get('password')
+        if password != target_loc.password:
+            flask.abort(401)
+
+        reader = bson.decode_file_iter(
+            req.stream, codec_options=common.BSON_OPTIONS)
+        entries = [
+            types.Reading.from_now(
+                sample_time=item['sample_time'],
+                temp_c=item['temp_c'],
+                rh_pct=item['rh_pct'],
+            )
+            for item in reader
+        ]
+        target_loc.logger.write_rows(entries)
+        return {'status': 'OK'}
+
+    @app.route('/<location>')
+    def show(location):
+        try:
+            loc, logger = locs.get(location)
+        except KeyError:
+            flask.abort(404)
+        data = logger.data
+        if data:
+            last_reading = data[-1]
+            tz = loc.timezone
+            date = tz.normalize(last_reading.sample_time.astimezone(tz))
+        else:
+            last_reading = None
+            date = None
+        return flask.render_template(
+            'location.html',
+            location=loc,
+            last_reading=last_reading,
+            date=date)
+
+    return app
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/weather_server/templates/location.html	Sun Sep 29 00:52:13 2019 -0400
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+    <head>
+        <title>Weather for {{ location.name }}</title>
+    </head>
+    <body>
+        {% if last_reading %}
+            Temperature: {{ last_reading.temp_f }}<br>
+            Dew point: {{ last_reading.dew_point_f }}
+        {% else %}
+            No weather yet
+        {% endif %}
+    </body>
+</html>