From 1a25c050cec714ee5056d656f5e09ee880d7d57f Mon Sep 17 00:00:00 2001 From: johannes walcher <johannes.walcher@stusta.de> Date: Sat, 4 Aug 2018 16:53:18 +0200 Subject: [PATCH] added haspa_web as module for deployment on nibbler --- haspa_web/.gitignore | 1 + haspa_web/__init__.py | 0 haspa_web/__main__.py | 19 +++++ haspa_web/haspa.py | 59 +++++++++++++++ haspa_web/html/.keep | 0 haspa_web/templates/current.json.tpl | 4 + haspa_web/templates/index.html.tpl | 105 +++++++++++++++++++++++++++ haspa_web/test.py | 32 ++++++++ 8 files changed, 220 insertions(+) create mode 100644 haspa_web/.gitignore create mode 100644 haspa_web/__init__.py create mode 100644 haspa_web/__main__.py create mode 100644 haspa_web/haspa.py create mode 100644 haspa_web/html/.keep create mode 100644 haspa_web/templates/current.json.tpl create mode 100644 haspa_web/templates/index.html.tpl create mode 100644 haspa_web/test.py diff --git a/haspa_web/.gitignore b/haspa_web/.gitignore new file mode 100644 index 0000000..35b5e99 --- /dev/null +++ b/haspa_web/.gitignore @@ -0,0 +1 @@ +/html diff --git a/haspa_web/__init__.py b/haspa_web/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/haspa_web/__main__.py b/haspa_web/__main__.py new file mode 100644 index 0000000..6d7a99d --- /dev/null +++ b/haspa_web/__main__.py @@ -0,0 +1,19 @@ +import asyncio +from haspa_web.haspa import HaspaWeb + +def main(): + """ + Actually start the shit + """ + loop = asyncio.get_event_loop() + haspaweb = HaspaWeb() + loop.set_debug(True) + try: + loop.run_forever() + except KeyboardInterrupt: + pass + + loop.run_until_complete(haspaweb.teardown()) + +if __name__ == "__main__": + main() diff --git a/haspa_web/haspa.py b/haspa_web/haspa.py new file mode 100644 index 0000000..e2bf9cf --- /dev/null +++ b/haspa_web/haspa.py @@ -0,0 +1,59 @@ +import asyncio +import time +from pathlib import Path + +from hauptbahnhof import Hauptbahnhof + +class HaspaWeb: + """ + Recreate the haspa website to represent the current haspa state + """ + + def __init__(self, loop=None): + if not loop: + loop = asyncio.get_event_loop() + + self.loop = loop + self.hbf = Hauptbahnhof(loop) + self.hbf.subscribe('/haspa/status', self.command_state) + + prism_path = Path(__file__).resolve().parent + self.config = {} + self.config['TEMPLATE_PATH'] = prism_path / "templates" + self.config['OUTPUT_PATH'] = prism_path / "html" + + async def teardown(self): + """ Clean it up """ + await self.hbf.teardown() + + async def command_state(self, client, message, _): + """ After the state has changed, do something! """ + del client + print(message) + if 'haspa' in message: + if message['haspa'] in ['open', 'offen', 'auf']: + self.set_state(message['haspa'], True) + elif message['haspa'] in ['close', 'zu', 'closed']: + self.set_state(message['haspa'], False) + else: + print("Haspa state undetermined: ", message['haspa']) + + def set_state(self, state, is_open): + """ + Export the current haspa state to the website + + The templates and the update procedure have been designed by pt, I do not want to + Change any old and glorious routines! + """ + for template in self.config['TEMPLATE_PATH'].glob('*.tpl'): + print("Updating templates") + outfile = self.config['OUTPUT_PATH'] / template.stem + + with open(str(template), 'r') as orig: + content = orig.read() + content = content.replace('#state#', + "offen" if is_open else "geschlossen") + content = content.replace('#last_update#', + time.strftime("%a, %d %b %Y %H:%M:%S")) + with open(str(outfile), 'w') as new: + new.write(content) diff --git a/haspa_web/html/.keep b/haspa_web/html/.keep new file mode 100644 index 0000000..e69de29 diff --git a/haspa_web/templates/current.json.tpl b/haspa_web/templates/current.json.tpl new file mode 100644 index 0000000..b1b01ce --- /dev/null +++ b/haspa_web/templates/current.json.tpl @@ -0,0 +1,4 @@ +{ +"state": "#state#", +"last_update": "#last_update#" +} diff --git a/haspa_web/templates/index.html.tpl b/haspa_web/templates/index.html.tpl new file mode 100644 index 0000000..1c027f0 --- /dev/null +++ b/haspa_web/templates/index.html.tpl @@ -0,0 +1,105 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Hackerspace: #state#</title> + <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <style> + /* latin */ + @font-face { + font-family: 'Josefin Slab'; + font-style: normal; + font-weight: 100; + src: local('Josefin Slab Thin'), local('JosefinSlab-Thin'), url(css/josefinslab-thin.woff2) format('woff2'), url(css/josefinslab-thin.woff) format('woff'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; + } + /* latin */ + @font-face { + font-family: 'Josefin Slab'; + font-style: normal; + font-weight: 400; + src: local('Josefin Slab'), local('JosefinSlab'), url(css/josefinslab.woff2) format('woff2'), url(css/josefinslab.woff) format('woff'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; + } + + * { + transition: all 0.3s ease; + } + + html, body { + height: 100%; + width: 100%; + margin: 0; + padding: 0; + font-family: "Josefin Slab", serif; + font-weight: 100; + } + + body { + position: relative; + } + + body.offen { + background: #55ee33; + } + body.geschlossen { + background: #ee5555; + } + + div { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + + .offen div:before { + content: "Offen"; + font-size: 25vw; + } + .geschlossen div:before { + content: "Geschlossen"; + font-size: 15vw; + } + + span { + position: absolute; + bottom: 0.5em; + left: 0; + right: 0; + text-align: center; + font-weight: 500; + } + </style> + </head> + <body class="#state#"> + <div> + </div> + <span id="last_update"> + Letzte Aktualisierung: #last_update# + </span> + + <script> + function fetchJSONFile(path, callback) { + var httpRequest = new XMLHttpRequest(); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === 4) { + if (httpRequest.status === 200) { + var data = JSON.parse(httpRequest.responseText); + if (callback) callback(data); + } + } + }; + httpRequest.open('GET', path); + httpRequest.send(); + } + + setInterval(function() { + fetchJSONFile('current.json?time=' + Math.floor(Date.now() / 1000), function(data){ + document.body.className = data.state; + document.getElementById('last_update').innerHTML = 'Letzte Aktualisierung: ' + data.last_update; + }); + }, 4200); + </script> + </body> +</html> diff --git a/haspa_web/test.py b/haspa_web/test.py new file mode 100644 index 0000000..635dd0b --- /dev/null +++ b/haspa_web/test.py @@ -0,0 +1,32 @@ +import asyncio +from hauptbahnhof import Hauptbahnhof + +from haspa_web.haspa import HaspaWeb + +async def test(loop): + testbf = Hauptbahnhof(loop=loop) + await asyncio.sleep(2) + # Now everythin should be set up + + await testbf.publish("/haspa/status", {'haspa':"offen"}) + + # The module is not sending any status back + try: + await testbf.teardown() + except asyncio.CancelledError: + pass + +def main(): + loop = asyncio.get_event_loop() + lib = HaspaWeb(loop=loop) + + result = loop.run_until_complete(test(loop)) + loop.run_until_complete(lib.teardown()) + + if result: + exit(0) + else: + exit(1) + +if __name__=="__main__": + main() -- GitLab