Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions apps/desktop/extensions/ai-sidebar/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,34 @@ async function disablePit() {
await setPitBadge(false);
}

// The launcher replaces an out-of-date helper in the background right after
// launch (kill, settle, exec). A click in that window reaches the OLD helper,
// which has no /pit/* routes and answers 404 {"error":"not-found"}, or reaches
// nobody at all. Both are transient, so try for a few seconds before giving up,
// and say "stale helper" rather than "couldn't start" when it never catches up.
const PIT_START_ATTEMPTS = 5;
const PIT_START_RETRY_MS = 2000;

function pitHelperIsStale(res) {
return !res || res.error === 'not-found' || (!res.started && typeof res.port !== 'number');
}

async function startPitViaHelper() {
let last = null;
for (let i = 0; i < PIT_START_ATTEMPTS; i++) {
if (i) await new Promise((r) => setTimeout(r, PIT_START_RETRY_MS));
try {
last = await helperJson('/pit/start', 'POST');
} catch (_) {
last = { error: 'unreachable' };
continue;
}
if (!pitHelperIsStale(last)) return last; // a pit-capable helper answered, ok or not
}
if (last && last.error === 'unreachable') return last;
return { started: false, error: 'helper-stale' };
}

async function stopPitViaHelper() {
try {
const ctrl = new AbortController();
Expand All @@ -356,15 +384,9 @@ chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
sendResponse({ enabled: false, error: 'tor-on' });
return;
}
let started;
try {
started = await helperJson('/pit/start', 'POST');
} catch (_) {
sendResponse({ enabled: false, error: 'unreachable' });
return;
}
if (!started || !started.started) {
sendResponse({ enabled: false, error: (started && started.error) || 'pit-failed' });
const started = await startPitViaHelper();
if (!started.started) {
sendResponse({ enabled: false, error: started.error || 'pit-failed' });
return;
}
await enablePit();
Expand Down
4 changes: 3 additions & 1 deletion apps/desktop/extensions/ai-sidebar/sidepanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,10 @@ async function togglePit() {
showNetStatus('warn', 'Couldn’t reach the TronBrowser helper. Restart TronBrowser and try again, or run <code>tron upgrade</code>.');
} else if (err === 'pit-port-busy') {
showNetStatus('warn', `Port ${PIT_SOCKS_PORT} on this machine is taken by another program, so the pit resolver couldn’t start.`);
} else if (err === 'helper-stale') {
showNetStatus('warn', 'TronBrowser’s helper is still the older version, which has no pit resolver. It is normally replaced a few seconds after launch — try 🤘 Pit again; if it keeps failing, quit TronBrowser completely and relaunch it.');
} else {
showNetStatus('warn', 'The pit resolver couldn’t start. See <code>~/.tronbrowser/tor-helper.log</code> for the reason.');
showNetStatus('warn', `The pit resolver couldn’t start (${safeHost(err || 'pit-failed')}). See <code>~/.tronbrowser/tor-helper.log</code> for the reason.`);
}
}
} catch (e) {
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop/launcher/tron-tor-helper
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ BUNDLED_DIR = os.environ.get("TRON_TOR_BIN_DIR", "")
PIDFILE = os.environ.get("TRON_TOR_PIDFILE", "")
# Bumped whenever the helper protocol/behaviour changes; the launcher kills a
# stale helper so the current version always runs.
HELPER_VERSION = "3.3.0"
HELPER_VERSION = "3.3.1"
_lock = threading.Lock()
_proc = None # the running tor subprocess (or None)
_ready = False # True once tor reported Bootstrapped 100%
Expand Down Expand Up @@ -559,6 +559,7 @@ class Handler(BaseHTTPRequestHandler):
elif path == "/pit/status":
self._send(200, pit_status())
else:
log("no such route: %s (helper v%s)" % (path, HELPER_VERSION))
self._send(404, {"error": "not-found"})

def do_GET(self):
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/launcher/tronbrowser
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ if [ "$TOR" != "1" ]; then
# running helper isn't this version — otherwise leave a healthy current
# helper alone (don't drop an active Tor session). All backgrounded so the
# kill+settle never holds up the browser launch.
HELPER_VERSION=3.3.0
HELPER_VERSION=3.3.1
(
_pf="$DATA/tor-helper.pid"
_rv="$(curl -fsS --max-time 1 http://127.0.0.1:9061/status 2>/dev/null | sed -n 's/.*"version"[^"]*"\([^"]*\)".*/\1/p')"
Expand Down
6 changes: 5 additions & 1 deletion docs/moshpit-pit-toggle.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ would leak every lookup outside Tor, so:
- If the DoH resolver did not answer the probe (offline, slow), the pit stays
**on** and says so; names resolve as soon as it is reachable.
- Failures the sidebar explains: the helper is not running (`tron upgrade`,
restart), port 9081 is taken, Tor is on.
restart), port 9081 is taken, Tor is on, or the helper is still an older
version. That last one is a launch race: the launcher replaces an out-of-date
helper in the background a moment after the browser starts, and a click in
that window reaches the old helper's 404. The background retries `/pit/start`
for about ten seconds before reporting it.

## Files

Expand Down
Loading