Single-command startup and fix bookmarklet
app.py now auto-starts the gateway HTTP server in a daemon thread, so users only need `python app.py` to get everything running. The gateway calls dispatch_request directly when co-located (local mode) instead of trying to establish an RNS link to itself. Bookmarklet hardcoded to localhost:8080. gateway.py still works standalone for connecting to remote instances. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9a9b5e0617
commit
4e4cc69e0f
3 changed files with 52 additions and 34 deletions
18
app.py
18
app.py
|
|
@ -1,9 +1,12 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
import threading
|
||||||
import RNS
|
import RNS
|
||||||
|
from http.server import HTTPServer
|
||||||
|
|
||||||
from db import init_db
|
from db import init_db
|
||||||
from handlers import dispatch_request
|
from handlers import dispatch_request
|
||||||
|
from gateway import GatewayState, GatewayHandler, GATEWAY_PORT
|
||||||
|
|
||||||
APP_NAME = "tinyweb"
|
APP_NAME = "tinyweb"
|
||||||
ASPECTS = ["server"]
|
ASPECTS = ["server"]
|
||||||
|
|
@ -24,6 +27,14 @@ def rns_request_handler(path, data, request_id, link_id, remote_identity, reques
|
||||||
return dispatch_request(data)
|
return dispatch_request(data)
|
||||||
|
|
||||||
|
|
||||||
|
def start_gateway(reticulum):
|
||||||
|
GatewayState.reticulum = reticulum
|
||||||
|
GatewayState.local_dispatch = dispatch_request
|
||||||
|
server = HTTPServer(("127.0.0.1", GATEWAY_PORT), GatewayHandler)
|
||||||
|
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
init_db()
|
init_db()
|
||||||
reticulum = RNS.Reticulum()
|
reticulum = RNS.Reticulum()
|
||||||
|
|
@ -44,10 +55,11 @@ def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
destination.announce()
|
destination.announce()
|
||||||
|
start_gateway(reticulum)
|
||||||
|
|
||||||
print(f"TinyWeb Reticulum server running")
|
print(f"TinyWeb running!")
|
||||||
print(f"Destination hash: {RNS.prettyhexrep(destination.hash)}")
|
print(f"Open http://localhost:{GATEWAY_PORT} in your browser")
|
||||||
print(f"Share this hash with clients to connect via gateway.py")
|
print(f"Destination hash: {RNS.prettyhexrep(destination.hash)} (share this so friends can subscribe)")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
|
||||||
61
gateway.py
61
gateway.py
|
|
@ -16,6 +16,7 @@ class GatewayState:
|
||||||
destination = None
|
destination = None
|
||||||
link = None
|
link = None
|
||||||
link_lock = threading.Lock()
|
link_lock = threading.Lock()
|
||||||
|
local_dispatch = None # set when running inside app.py
|
||||||
|
|
||||||
|
|
||||||
def resolve_destination(dest_hash_hex):
|
def resolve_destination(dest_hash_hex):
|
||||||
|
|
@ -83,34 +84,40 @@ class GatewayHandler(BaseHTTPRequestHandler):
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
link = ensure_link()
|
if GatewayState.local_dispatch:
|
||||||
receipt = link.request(
|
resp = GatewayState.local_dispatch(request_data)
|
||||||
"/tinyweb",
|
|
||||||
data=request_data,
|
|
||||||
timeout=REQUEST_TIMEOUT,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Wait for the response
|
|
||||||
elapsed = 0
|
|
||||||
done_statuses = (RNS.RequestReceipt.READY, RNS.RequestReceipt.DELIVERED, RNS.RequestReceipt.FAILED)
|
|
||||||
while receipt.get_status() not in done_statuses and elapsed < REQUEST_TIMEOUT:
|
|
||||||
time.sleep(0.1)
|
|
||||||
elapsed += 0.1
|
|
||||||
|
|
||||||
if receipt.get_status() in (RNS.RequestReceipt.READY, RNS.RequestReceipt.DELIVERED):
|
|
||||||
resp = receipt.get_response()
|
|
||||||
self.send_response(resp["status"])
|
|
||||||
self.send_header("Content-Type", resp.get("content_type", "text/html; charset=utf-8"))
|
|
||||||
for k, v in resp.get("headers", {}).items():
|
|
||||||
self.send_header(k, v)
|
|
||||||
self.end_headers()
|
|
||||||
resp_body = resp.get("body", "")
|
|
||||||
if resp_body:
|
|
||||||
self.wfile.write(resp_body.encode() if isinstance(resp_body, str) else resp_body)
|
|
||||||
elif receipt.get_status() == RNS.RequestReceipt.FAILED:
|
|
||||||
self.send_error(504, "Request to TinyWeb server failed")
|
|
||||||
else:
|
else:
|
||||||
self.send_error(504, "Request to TinyWeb server timed out")
|
link = ensure_link()
|
||||||
|
receipt = link.request(
|
||||||
|
"/tinyweb",
|
||||||
|
data=request_data,
|
||||||
|
timeout=REQUEST_TIMEOUT,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Wait for the response
|
||||||
|
elapsed = 0
|
||||||
|
done_statuses = (RNS.RequestReceipt.READY, RNS.RequestReceipt.DELIVERED, RNS.RequestReceipt.FAILED)
|
||||||
|
while receipt.get_status() not in done_statuses and elapsed < REQUEST_TIMEOUT:
|
||||||
|
time.sleep(0.1)
|
||||||
|
elapsed += 0.1
|
||||||
|
|
||||||
|
if receipt.get_status() in (RNS.RequestReceipt.READY, RNS.RequestReceipt.DELIVERED):
|
||||||
|
resp = receipt.get_response()
|
||||||
|
elif receipt.get_status() == RNS.RequestReceipt.FAILED:
|
||||||
|
self.send_error(504, "Request to TinyWeb server failed")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.send_error(504, "Request to TinyWeb server timed out")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.send_response(resp["status"])
|
||||||
|
self.send_header("Content-Type", resp.get("content_type", "text/html; charset=utf-8"))
|
||||||
|
for k, v in resp.get("headers", {}).items():
|
||||||
|
self.send_header(k, v)
|
||||||
|
self.end_headers()
|
||||||
|
resp_body = resp.get("body", "")
|
||||||
|
if resp_body:
|
||||||
|
self.wfile.write(resp_body.encode() if isinstance(resp_body, str) else resp_body)
|
||||||
|
|
||||||
except ConnectionError as e:
|
except ConnectionError as e:
|
||||||
GatewayState.link = None
|
GatewayState.link = None
|
||||||
|
|
|
||||||
|
|
@ -308,12 +308,11 @@ def handle_import_submit(body):
|
||||||
return handle_import_form(f"Imported {imported} page(s). {errors} error(s).")
|
return handle_import_form(f"Imported {imported} page(s). {errors} error(s).")
|
||||||
|
|
||||||
|
|
||||||
def handle_style_form(msg="", gateway_host=""):
|
def handle_style_form(msg=""):
|
||||||
css = get_setting("custom_css")
|
css = get_setting("custom_css")
|
||||||
name = get_site_name()
|
name = get_site_name()
|
||||||
sharing = get_setting("sharing_enabled", "0")
|
sharing = get_setting("sharing_enabled", "0")
|
||||||
checked = " checked" if sharing == "1" else ""
|
checked = " checked" if sharing == "1" else ""
|
||||||
host = gateway_host or "localhost:8080"
|
|
||||||
return _respond(
|
return _respond(
|
||||||
f"<h1>customize</h1>"
|
f"<h1>customize</h1>"
|
||||||
f"<h2>name your search engine</h2>"
|
f"<h2>name your search engine</h2>"
|
||||||
|
|
@ -340,7 +339,7 @@ def handle_style_form(msg="", gateway_host=""):
|
||||||
f"</form>"
|
f"</form>"
|
||||||
f"<h2>bookmarklet</h2>"
|
f"<h2>bookmarklet</h2>"
|
||||||
f"<p>Drag this link to your bookmarks bar. Click it on any page to index it instantly.</p>"
|
f"<p>Drag this link to your bookmarks bar. Click it on any page to index it instantly.</p>"
|
||||||
f'<p><a href="javascript:void(fetch(\'http://{esc(host)}/bookmark?url=\'+encodeURIComponent(location.href)).then(r=>r.text()).then(t=>alert(t)).catch(()=>alert(\'tinyweb not running\')))">+ save to {esc(name)}</a></p>'
|
f'<p><a href="javascript:void(fetch(\'http://localhost:8080/bookmark?url=\'+encodeURIComponent(location.href)).then(r=>r.text()).then(t=>alert(t)).catch(()=>alert(\'tinyweb not running\')))">+ save to {esc(name)}</a></p>'
|
||||||
f"<p>{msg}</p>"
|
f"<p>{msg}</p>"
|
||||||
f'<a href="/">back</a>'
|
f'<a href="/">back</a>'
|
||||||
)
|
)
|
||||||
|
|
@ -651,7 +650,7 @@ def dispatch_request(data):
|
||||||
elif path == "/bookmark":
|
elif path == "/bookmark":
|
||||||
return handle_bookmark(query)
|
return handle_bookmark(query)
|
||||||
elif path == "/style":
|
elif path == "/style":
|
||||||
return handle_style_form(gateway_host=gateway_host)
|
return handle_style_form()
|
||||||
elif path == "/export":
|
elif path == "/export":
|
||||||
return handle_export()
|
return handle_export()
|
||||||
elif path == "/import":
|
elif path == "/import":
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue