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.
111 lines
3.1 KiB
Python
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()
|