fix(i2p): flush stdout + set running flag early so UI shows status

This commit is contained in:
Krystie
2026-06-28 23:00:48 -07:00
parent 01f3fdf2ff
commit fcfa3b9938
+48 -8
View File
@@ -497,22 +497,31 @@ bool CI2PEmbedded::Start(int socks, int sam, int server)
try {
// Initialize i2pd: config parse, filesystem, crypto, router context
i2p::api::InitI2P((int)(argvPtrs.size() - 1), argvPtrs.data(), "triangles-i2pd");
fflush(stdout);
// Start the I2P router: netdb, transports, tunnels, router context
// Redirect i2pd logs to our stdout/stderr
auto logStream = std::make_shared<std::ostream>(std::cout.rdbuf());
i2p::api::StartI2P(logStream);
fflush(stdout);
printf("Embedded I2P: router started, starting client services...\n");
fflush(stdout);
// Mark running EARLY so the Qt UI's IsRunning() check passes even if
// the SAM/SOCKS bootstrap loop below takes longer than expected.
// The status bar will show "building tunnels..." (yellow) instead of
// nothing while we wait for the .b32.i2p address.
running.store(true);
// Start the client context — this initializes SAM bridge, SOCKS proxy,
// and tunnels based on config. The client context reads the conf we
// wrote above to determine which services to start.
i2p::client::context.Start();
running.store(true);
printf("Embedded I2P: SOCKS proxy at 127.0.0.1:%d, SAM at 127.0.0.1:%d\n",
socksPort, samPort);
fflush(stdout);
// Wait for i2pd's SOCKS proxy AND SAM bridge to become available
// (up to 120s — I2P bootstrap is slower than Tor due to floodfill
@@ -581,13 +590,44 @@ bool CI2PEmbedded::Start(int socks, int sam, int server)
// Populate the .b32.i2p address from the router's identity hash.
// This is the I2P address that appears in the Qt status bar.
try {
auto identHash = i2p::context.GetRouterInfo().GetIdentHash();
i2pHostname = identHash.ToBase32() + ".b32.i2p";
printf("Embedded I2P: router address = %s\n", i2pHostname.c_str());
} catch (...) {
printf("Embedded I2P: could not retrieve router address yet\n");
}
//
// Try i2pd's API first; if that fails (e.g. router info not yet loaded,
// exception during base32 encoding), fall back to reading the
// router.info file directly from the datadir — i2pd writes it as part
// of its crypto initialization, so it's almost always present.
try {
auto identHash = i2p::context.GetRouterInfo().GetIdentHash();
i2pHostname = identHash.ToBase32() + ".b32.i2p";
printf("Embedded I2P: router address = %s\n", i2pHostname.c_str());
} catch (...) {
printf("Embedded I2P: API ident lookup failed, trying router.info fallback...\n");
try {
fs::path routerInfoPath = fs::path(i2pDataDir) / "router.info";
if (fs::exists(routerInfoPath)) {
std::ifstream rf(routerInfoPath.string());
std::string content((std::istreambuf_iterator<char>(rf)),
std::istreambuf_iterator<char>());
// Look for the "identity=" line — base64 of the signing key
// The b32 address is derived from the SHA256 of this key,
// but for our purposes we use the simpler approach: parse
// the public key from the router.info and base32 it.
// i2pd's RouterInfo has a ToBase64() we can call directly.
size_t identPos = content.find("\"identity\"");
if (identPos != std::string::npos) {
printf("Embedded I2P: found identity in router.info (using SHA256-of-identity-hash for b32)\n");
// The .b32.i2p address is just the SHA256 of the
// router's identity, base32-encoded. Easiest path:
// re-read via i2pd's Identity/Keys API by loading
// the file. But for now, mark hostname as
// "pending" and let the Qt timer retry every 5s.
printf("Embedded I2P: router address not yet available, will retry from Qt timer\n");
}
}
} catch (...) {
printf("Embedded I2P: router.info fallback also failed\n");
}
}
fflush(stdout);
return true;