tinyweb/app.py
lichenblankie bfb8acf946 disabled share_instance for reliable announces
With share_instance = Yes, announces weren't being sent over TCP
in Docker environments. Setting it to No ensures each TinyWeb
instance manages its own Reticulum interfaces directly.
2026-06-05 05:29:35 +00:00

111 lines
3.1 KiB
Python

import os
import time
import threading
import RNS
from http.server import HTTPServer
from db import init_db, set_setting
from handlers import dispatch_request
from gateway import GatewayState, GatewayHandler, GATEWAY_PORT
APP_NAME = "tinyweb"
ASPECTS = ["server"]
IDENTITY_FILE = "tinyweb_identity"
DEFAULT_TRANSPORT_HOST = "reticulum.derickphan.com"
DEFAULT_TRANSPORT_PORT = 4242
def load_or_create_identity():
if os.path.isfile(IDENTITY_FILE):
# Ensure identity file is only readable by owner
current = os.stat(IDENTITY_FILE).st_mode & 0o777
if current != 0o600:
os.chmod(IDENTITY_FILE, 0o600)
return RNS.Identity.from_file(IDENTITY_FILE)
identity = RNS.Identity()
identity.to_file(IDENTITY_FILE)
os.chmod(IDENTITY_FILE, 0o600)
return identity
def rns_request_handler(path, data, request_id, link_id, remote_identity, requested_at):
if data is None:
data = {"method": "GET", "path": "/", "query": {}, "body": {}, "gateway_host": ""}
return dispatch_request(data)
def start_gateway(reticulum):
GatewayState.reticulum = reticulum
GatewayState.local_dispatch = dispatch_request
server = HTTPServer(("0.0.0.0", GATEWAY_PORT), GatewayHandler)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
def ensure_rns_config(config_dir):
"""Generate a default Reticulum config with internet transport if none exists."""
if config_dir is None:
config_dir = os.path.expanduser("~/.reticulum")
config_file = os.path.join(config_dir, "config")
if os.path.exists(config_file):
return
os.makedirs(config_dir, exist_ok=True)
with open(config_file, "w") as f:
f.write(f"""[reticulum]
enable_transport = False
share_instance = No
[logging]
loglevel = 4
[interfaces]
[[Default Interface]]
type = AutoInterface
enabled = Yes
[[TCP Transport]]
type = TCPClientInterface
enabled = yes
target_host = {DEFAULT_TRANSPORT_HOST}
target_port = {DEFAULT_TRANSPORT_PORT}
""")
print(f"Created Reticulum config at {config_file}")
def main():
init_db()
config_dir = os.environ.get("RNS_CONFIG_DIR")
ensure_rns_config(config_dir)
reticulum = RNS.Reticulum(configdir=config_dir)
identity = load_or_create_identity()
destination = RNS.Destination(
identity,
RNS.Destination.IN,
RNS.Destination.SINGLE,
APP_NAME,
*ASPECTS,
)
destination.register_request_handler(
"/tinyweb",
response_generator=rns_request_handler,
allow=RNS.Destination.ALLOW_ALL,
)
# Brief delay to ensure all interfaces (especially TCP) are fully ready
time.sleep(2)
destination.announce()
set_setting("dest_hash", destination.hash.hex())
start_gateway(reticulum)
print(f"TinyWeb running!")
print(f"Open http://localhost:{GATEWAY_PORT} in your browser")
print(f"Destination hash: {RNS.prettyhexrep(destination.hash)} (share this so friends can subscribe)")
while True:
time.sleep(1)
if __name__ == "__main__":
main()