tinyweb/site_server.py

104 lines
3 KiB
Python

import os
import sys
import time
import mimetypes
SITE_DIR = os.path.expanduser("~/apps/tinyweb-site")
DATA_DIR = os.environ.get("TINYWEB_DATA_DIR") or os.path.expanduser("~/.tinyweb")
IDENTITY_FILE = "tinyweb-site_identity"
APP_NAME = "tinyweb"
ASPECTS = ["server"]
RNS_REQUEST_PATH = "/tinyweb"
import RNS
def load_or_create_identity():
identity_path = os.path.join(DATA_DIR, IDENTITY_FILE)
if os.path.isfile(identity_path):
return RNS.Identity.from_file(identity_path)
identity = RNS.Identity()
os.makedirs(DATA_DIR, exist_ok=True)
identity.to_file(identity_path)
os.chmod(identity_path, 0o600)
return identity
def main():
configdir = os.environ.get("RNS_CONFIG_DIR")
reticulum = RNS.Reticulum(configdir=configdir)
identity = load_or_create_identity()
destination = RNS.Destination(
identity,
RNS.Destination.IN,
RNS.Destination.SINGLE,
APP_NAME,
*ASPECTS,
)
destination.register_request_handler(
RNS_REQUEST_PATH,
response_generator=request_handler,
allow=RNS.Destination.ALLOW_ALL,
)
destination.announce()
dest_hash = destination.hash.hex()
print(f"tinyweb-site server running!")
print(f"Destination hash: <{dest_hash}>")
print(f"Add this hash to a TinyWeb instance as a mesh site to browse.")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\nShutting down...")
destination.unregister_request_handler()
def request_handler(path, data, request_id, link_id, remote_identity, requested_at):
if data is None:
data = {"method": "GET", "path": "/", "query": {}, "body": {}, "gateway_host": ""}
req_path = data.get("path", "/")
if req_path in ("/", "/index.html") or not req_path.strip("/"):
fs_path = os.path.join(SITE_DIR, "index.html")
else:
fs_path = os.path.join(SITE_DIR, req_path.lstrip("/"))
real_path = os.path.realpath(fs_path)
site_real = os.path.realpath(SITE_DIR)
if not real_path.startswith(site_real + os.sep) and real_path != site_real:
body = f"<html><body><h1>404 Not Found</h1><p>{req_path}</p></body></html>"
return {"status": 404, "content_type": "text/html; charset=utf-8", "body": body, "headers": {}}
if not os.path.isfile(real_path):
real_path = os.path.join(SITE_DIR, "index.html")
if not os.path.isfile(real_path):
body = f"<html><body><h1>404 Not Found</h1></body></html>"
return {"status": 404, "content_type": "text/html; charset=utf-8", "body": body, "headers": {}}
with open(real_path, "rb") as f:
content = f.read()
content_type, _ = mimetypes.guess_type(real_path)
if not content_type:
content_type = "text/html; charset=utf-8"
elif content_type.startswith("text/"):
content_type += "; charset=utf-8"
return {
"status": 200,
"content_type": content_type,
"body": content.decode("utf-8", errors="replace"),
"headers": {},
}
if __name__ == "__main__":
main()