74 lines
2.6 KiB
Python
74 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Simple HTTP server with save API for Mission Control."""
|
|
import http.server
|
|
import json
|
|
import os
|
|
import shutil
|
|
from datetime import datetime
|
|
|
|
PORT = 8091
|
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
class MissionControlHandler(http.server.SimpleHTTPRequestHandler):
|
|
def end_headers(self):
|
|
self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
|
self.send_header('Pragma', 'no-cache')
|
|
self.send_header('Expires', '0')
|
|
self.send_header('Access-Control-Allow-Origin', '*')
|
|
self.send_header('Access-Control-Allow-Methods', 'GET, PUT, OPTIONS')
|
|
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
|
|
super().end_headers()
|
|
|
|
def do_OPTIONS(self):
|
|
self.send_response(200)
|
|
self.end_headers()
|
|
|
|
def do_PUT(self):
|
|
path = self.path.lstrip('/')
|
|
if not path.startswith('data/') or not path.endswith('.json'):
|
|
self.send_response(403)
|
|
self.end_headers()
|
|
self.wfile.write(b'{"error":"Only data/*.json writes allowed"}')
|
|
return
|
|
|
|
content_length = int(self.headers.get('Content-Length', 0))
|
|
body = self.rfile.read(content_length)
|
|
|
|
try:
|
|
data = json.loads(body)
|
|
except json.JSONDecodeError as e:
|
|
self.send_response(400)
|
|
self.end_headers()
|
|
self.wfile.write(json.dumps({"error": f"Invalid JSON: {e}"}).encode())
|
|
return
|
|
|
|
filepath = os.path.join(os.getcwd(), path)
|
|
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
|
|
|
if os.path.exists(filepath):
|
|
backup = filepath + f'.bak-{datetime.now().strftime("%Y%m%d-%H%M%S")}'
|
|
shutil.copy2(filepath, backup)
|
|
bak_dir = os.path.dirname(filepath)
|
|
bak_base = os.path.basename(filepath)
|
|
baks = sorted([f for f in os.listdir(bak_dir) if f.startswith(bak_base + '.bak-')])
|
|
for old in baks[:-10]:
|
|
os.remove(os.path.join(bak_dir, old))
|
|
|
|
with open(filepath, 'w') as f:
|
|
json.dump(data, f, indent=2)
|
|
|
|
self.send_response(200)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write(json.dumps({"ok": True, "saved": path}).encode())
|
|
|
|
def log_message(self, format, *args):
|
|
pass
|
|
|
|
if __name__ == '__main__':
|
|
class ThreadedServer(http.server.ThreadingHTTPServer):
|
|
allow_reuse_address = True
|
|
server = ThreadedServer(('0.0.0.0', PORT), MissionControlHandler)
|
|
print(f'Atomizer HQ Mission Control serving on port {PORT}')
|
|
server.serve_forever()
|