diff --git a/scripts/autoserve.py b/scripts/autoserve.py new file mode 100644 index 0000000..a9eb997 --- /dev/null +++ b/scripts/autoserve.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +import sys +import http.server +import socketserver +import threading +import os +import time +import select + +import inotify.adapters + +PORT = 8000 + +MONITORED_EVENT_TYPES = ( + 'IN_CREATE', + # 'IN_MODIFY', + 'IN_CLOSE_WRITE', + 'IN_DELETE', + 'IN_MOVED_FROM', + 'IN_MOVED_TO', + 'IN_DELETE_SELF', + 'IN_MOVE_SELF', +) + +WAITING_RESPONSES = [] +SLEEP_TIME = 0.5 +COUNTER = 0 +MAX_WAITS = 100 + +class Server(http.server.SimpleHTTPRequestHandler): + def do_GET(self): + if self.path.strip('/') == '__wait_for_changes': + WAITING_RESPONSES.append(self) + print(len(WAITING_RESPONSES), "waiting responses") + global COUNTER + ticket, COUNTER = COUNTER, COUNTER + 1 + + while self in WAITING_RESPONSES: + # This is an horribe way to wait! ... but it may work for quick tests 🤷 + + if COUNTER - ticket > MAX_WAITS: + # Connection closed by the other side + print("Manually closed for cleanup") + WAITING_RESPONSES.remove(self) + # send 502 response, timeout + self.send_response(502) + # send response headers + self.end_headers() + + return + + time.sleep(SLEEP_TIME) + return + + # send 200 response + self.send_response(200) + # send response headers + self.end_headers() + + with open(self.path.strip('/'), 'rb') as f: + # send the body of the response + self.wfile.write(f.read()) + + if not self.path.endswith('.html'): + return + else: + # Append update waiter + with open('wait_for_update.js', 'rb') as f: + new_data = b'' + self.wfile.write(new_data) + new_data_len = len(new_data) + + return + +def notify_reloads(): + while len(WAITING_RESPONSES) > 0: + # Close opened connections + res = WAITING_RESPONSES.pop(0) + + try: + # send 200 response + res.send_response(200) + # send response headers + res.end_headers() + except Exception as e: + print("ERROR:", e) + + global COUNTER + COUNTER = 0 + + +def start_notifier(): + notifier = inotify.adapters.InotifyTree(os.getcwd()) + for event in notifier.event_gen(yield_nones=False): + (ev, types, directory, file) = event + if any([type in MONITORED_EVENT_TYPES for type in types]): + notify_reloads() + +def serve(): + Handler = Server + notifier_thread = threading.Thread(target=start_notifier) + + with http.server.ThreadingHTTPServer(("127.0.0.1", PORT), Handler) as httpd: + print("serving at port", PORT) + notifier_thread.start() + httpd.serve_forever() + + +if __name__ == '__main__': + serve() diff --git a/wait_for_update.js b/wait_for_update.js new file mode 100644 index 0000000..d53b9fd --- /dev/null +++ b/wait_for_update.js @@ -0,0 +1,19 @@ +(function (){ + var wait_for_update = function() { + console.debug("Waiting for changes..."); + + fetch('/__wait_for_changes').then(r => { + if (r.status !== 200) { + setTimeout( + wait_for_update, + 1000, + ); + } + else { + // Reload + window.location = window.location; + } + }); + }; + wait_for_update(); +})();