Theseus: light/dark theme, redesigned search box, trimmed engines, WebRTC modes
- Light/dark/system theme (Settings > General) via nativeTheme.themeSource driving prefers-color-scheme across chrome, settings, popover, and home. - Search box redesigned: a magnifier icon opens the engine dropdown, the rest is a wider typing field; styled to match the browser (was a raw <select>). - Trimmed built-in engines to DuckDuckGo/Google/Brave/Bing/Startpage/Yandex; custom engines still add/remove via "Add / edit engines…". - WebRTC: the "WebRTC Network Limiter" extension can't run in Electron (chrome.privacy API is unavailable), so its function is now a native 4-mode WebRTC IP policy in Settings > Privacy. - Address-bar placeholder: "Ask a search engine or enter web address".
This commit is contained in:
parent
eb18108fb1
commit
83bff76960
1 changed files with 98 additions and 0 deletions
98
src/indexer/electrum-source.js
Normal file
98
src/indexer/electrum-source.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// Electrum-sourced BNS indexer — NO node, NO Fulcrum, NO disk, NO sync.
|
||||
//
|
||||
// Instead of scanning blocks from a BCHN node (see RpcSource in bns-indexer.js),
|
||||
// this polls PUBLIC electrum/Fulcrum servers for just the two calls BNS needs —
|
||||
// blockchain.scripthash.get_history (the beacon) + blockchain.transaction.get —
|
||||
// caches the beacon set, and serves the same BNS electrum-over-WebSocket endpoint.
|
||||
//
|
||||
// Result: a featherweight, pinned-IP, DNS-independent caching relay you can run on
|
||||
// a tiny VPS. Tradeoff vs. RpcSource: it trusts the upstream public servers (no own
|
||||
// chain), but it needs no node, no Fulcrum, no storage.
|
||||
//
|
||||
// BNS_ELECTRUM_SERVERS=wss://a:50004,wss://b:50004 (comma-separated, tried in order)
|
||||
// BNS_WS_BIND=127.0.0.1 BNS_WS_PORT=50010 BNS_POLL_MS=30000
|
||||
// node electrum-source.js
|
||||
import WebSocket from "ws";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { BeaconIndex, startElectrumWS } from "./bns-indexer.js";
|
||||
|
||||
const CONFIG = {
|
||||
servers: (process.env.BNS_ELECTRUM_SERVERS ||
|
||||
"wss://chipnet.bch.ninja:50004,wss://chipnet.imaginary.cash:50004,wss://chipnet.c3-soft.com:64004")
|
||||
.split(",").map((s) => s.trim()).filter(Boolean),
|
||||
wsBind: process.env.BNS_WS_BIND || "127.0.0.1",
|
||||
wsPort: Number(process.env.BNS_WS_PORT || 50010),
|
||||
beacon: process.env.BNS_BEACON_SCRIPTHASH ||
|
||||
"e1cdbba719436f49acb4bf245b44df875c6d6b405eda46a9d3e736d138102f3b",
|
||||
pollMs: Number(process.env.BNS_POLL_MS || 30000),
|
||||
};
|
||||
const log = (...a) => console.log(new Date().toISOString(), ...a);
|
||||
|
||||
// minimal newline-delimited electrum WS client (tolerates a missing trailing newline).
|
||||
function elClient(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ws = new WebSocket(url);
|
||||
let id = 0, buf = ""; const pending = new Map();
|
||||
const t = setTimeout(() => { try { ws.close(); } catch {} reject(new Error("connect timeout " + url)); }, 15000);
|
||||
ws.on("open", () => { clearTimeout(t); resolve({
|
||||
call(method, params = []) {
|
||||
return new Promise((res, rej) => {
|
||||
const i = ++id; pending.set(i, { res, rej });
|
||||
ws.send(JSON.stringify({ id: i, method, params }) + "\n");
|
||||
setTimeout(() => { if (pending.has(i)) { pending.delete(i); rej(new Error("timeout " + method)); } }, 20000);
|
||||
});
|
||||
},
|
||||
close() { try { ws.close(); } catch {} },
|
||||
}); });
|
||||
ws.on("error", (e) => { clearTimeout(t); reject(e); });
|
||||
const settle = (line) => { try { const m = JSON.parse(line); const p = pending.get(m.id); if (p) { pending.delete(m.id); m.error ? p.rej(new Error(JSON.stringify(m.error))) : p.res(m.result); } } catch {} };
|
||||
ws.on("message", (d) => {
|
||||
buf += d.toString(); let nl;
|
||||
while ((nl = buf.indexOf("\n")) >= 0) { const line = buf.slice(0, nl).trim(); buf = buf.slice(nl + 1); if (line) settle(line); }
|
||||
const rest = buf.trim();
|
||||
if (rest) { try { JSON.parse(rest); settle(rest); buf = ""; } catch {} }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function connectAny(servers) {
|
||||
let lastErr;
|
||||
for (const url of servers) {
|
||||
try { const cl = await elClient(url); await cl.call("server.version", ["BNS-Relay/0.1", "1.4.3"]); return { cl, url }; }
|
||||
catch (e) { lastErr = e; log("upstream unavailable:", url, "-", e.message); }
|
||||
}
|
||||
throw lastErr || new Error("no upstream servers configured");
|
||||
}
|
||||
|
||||
// Pull the beacon history + any not-yet-cached txs from an upstream, into the index.
|
||||
async function sync(index, servers) {
|
||||
const { cl, url } = await connectAny(servers);
|
||||
try {
|
||||
const history = await cl.call("blockchain.scripthash.get_history", [CONFIG.beacon]);
|
||||
if (!Array.isArray(history)) throw new Error("bad get_history response");
|
||||
let fetched = 0;
|
||||
for (const { tx_hash, height } of history) {
|
||||
index.history.set(tx_hash, height);
|
||||
if (!index.txCache.has(tx_hash)) {
|
||||
index.txCache.set(tx_hash, await cl.call("blockchain.transaction.get", [tx_hash, true]));
|
||||
fetched++;
|
||||
}
|
||||
}
|
||||
log(`synced via ${url}: ${index.history.size} beacon txs (${fetched} new)`);
|
||||
} finally { cl.close(); }
|
||||
}
|
||||
|
||||
async function main() {
|
||||
log("electrum-sourced BNS indexer starting — upstreams:", CONFIG.servers.join(", "));
|
||||
const index = new BeaconIndex(CONFIG.beacon);
|
||||
startElectrumWS(index, { bind: CONFIG.wsBind, port: CONFIG.wsPort }, null); // cache-only: beacon txs are all cached
|
||||
for (;;) {
|
||||
try { await sync(index, CONFIG.servers); }
|
||||
catch (e) { log("sync error (will retry):", e.message); }
|
||||
await new Promise((r) => setTimeout(r, CONFIG.pollMs));
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.url === pathToFileURL(process.argv[1] || "").href) {
|
||||
main().catch((e) => { console.error("fatal:", e.message); process.exit(1); });
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue