mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Wait for nostr pool before platform lookup
This commit is contained in:
1 parent
908435f476
commit
1c805b053e
3 files changed
+175
-3
No files matched your search
+50
-1
@@ -1731,6 +1731,7 @@ export { convertEventToVideo };
|
||||
class NostrClient {
|
||||
constructor() {
|
||||
this.pool = null;
|
||||
this.poolPromise = null;
|
||||
this.pubkey = null;
|
||||
this.relays = sanitizeRelayList(Array.from(DEFAULT_RELAY_URLS));
|
||||
this.readRelays = Array.from(this.relays);
|
||||
@@ -4096,7 +4097,7 @@ class NostrClient {
|
||||
this.restoreLocalData();
|
||||
|
||||
try {
|
||||
this.pool = new window.NostrTools.SimplePool();
|
||||
await this.ensurePool();
|
||||
const results = await this.connectToRelays();
|
||||
const successfulRelays = results
|
||||
.filter((r) => r.success)
|
||||
@@ -4113,6 +4114,54 @@ class NostrClient {
|
||||
}
|
||||
}
|
||||
|
||||
ensurePool() {
|
||||
if (this.pool) {
|
||||
return Promise.resolve(this.pool);
|
||||
}
|
||||
|
||||
if (this.poolPromise) {
|
||||
return this.poolPromise;
|
||||
}
|
||||
|
||||
const scope =
|
||||
typeof window !== "undefined"
|
||||
? window
|
||||
: typeof globalThis !== "undefined"
|
||||
? globalThis
|
||||
: null;
|
||||
|
||||
const tools =
|
||||
scope?.NostrTools ||
|
||||
scope?.__BITVID_CANONICAL_NOSTR_TOOLS__ ||
|
||||
(typeof globalThis !== "undefined" ? globalThis?.NostrTools : null);
|
||||
|
||||
const SimplePool = tools?.SimplePool;
|
||||
if (typeof SimplePool !== "function") {
|
||||
const error = new Error("NostrTools SimplePool is unavailable.");
|
||||
error.code = "nostr-simplepool-unavailable";
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
const creation = Promise.resolve().then(() => {
|
||||
const instance = new SimplePool();
|
||||
this.pool = instance;
|
||||
return instance;
|
||||
});
|
||||
|
||||
const shared = creation
|
||||
.then((instance) => {
|
||||
this.poolPromise = Promise.resolve(instance);
|
||||
return instance;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.poolPromise = null;
|
||||
throw error;
|
||||
});
|
||||
|
||||
this.poolPromise = shared;
|
||||
return shared;
|
||||
}
|
||||
|
||||
// We subscribe to kind `0` purely as a liveness probe because almost every
|
||||
// relay can answer it quickly. Either an `event` or `eose` signals success,
|
||||
// while the 5s timer guards against relays that never respond. We immediately
|
||||
|
||||
@@ -88,13 +88,28 @@ async function fetchAdminMetadata(adminPubkey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!nostrClient?.pool || !Array.isArray(nostrClient?.relays)) {
|
||||
let pool;
|
||||
try {
|
||||
pool = await nostrClient.ensurePool();
|
||||
} catch (error) {
|
||||
console.warn("[platformAddress] Failed to initialize Nostr pool", error);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!pool) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const relayUrls = Array.isArray(nostrClient?.relays)
|
||||
? nostrClient.relays
|
||||
: [];
|
||||
if (relayUrls.length === 0) {
|
||||
console.warn("[platformAddress] Nostr client is not ready.");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const events = await nostrClient.pool.list(nostrClient.relays, [
|
||||
const events = await pool.list(relayUrls, [
|
||||
{ kinds: [0], authors: [adminPubkey], limit: 1 },
|
||||
]);
|
||||
|
||||
|
||||
@@ -49,6 +49,23 @@ const nostrToolsStub = {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
SimplePool: class {
|
||||
async list() {
|
||||
return [];
|
||||
}
|
||||
sub() {
|
||||
return {
|
||||
on() {},
|
||||
unsub() {},
|
||||
};
|
||||
}
|
||||
async get() {
|
||||
return null;
|
||||
}
|
||||
async ensureRelay() {
|
||||
return { close() {}, url: "" };
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
window.NostrTools = nostrToolsStub;
|
||||
@@ -59,6 +76,9 @@ globalThis.fetch = async () => {
|
||||
};
|
||||
|
||||
const { splitAndZap } = await import("../js/payments/zapSplit.js");
|
||||
const platformAddressModule = await import("../js/payments/platformAddress.js");
|
||||
const { __resetPlatformAddressCache } = platformAddressModule;
|
||||
const { nostrClient } = await import("../js/nostr.js");
|
||||
|
||||
function createDeps({
|
||||
commentAllowed = 120,
|
||||
@@ -180,6 +200,93 @@ async function testSplitMath() {
|
||||
delete globalThis.__BITVID_PLATFORM_FEE_OVERRIDE__;
|
||||
}
|
||||
|
||||
async function testWaitsForPoolBeforePlatformLookup() {
|
||||
const previousOverride = globalThis.__BITVID_PLATFORM_FEE_OVERRIDE__;
|
||||
globalThis.__BITVID_PLATFORM_FEE_OVERRIDE__ = 10;
|
||||
|
||||
__resetPlatformAddressCache();
|
||||
|
||||
const originalEnsurePool = nostrClient.ensurePool;
|
||||
const originalPool = nostrClient.pool;
|
||||
const originalPoolPromise = nostrClient.poolPromise;
|
||||
|
||||
nostrClient.pool = null;
|
||||
nostrClient.poolPromise = null;
|
||||
|
||||
let poolReady = false;
|
||||
let listCalls = 0;
|
||||
let ensureCalls = 0;
|
||||
|
||||
const poolStub = {
|
||||
async list(relays, filters) {
|
||||
assert(poolReady, "should wait for ensurePool to resolve before listing metadata");
|
||||
listCalls += 1;
|
||||
return [
|
||||
{
|
||||
pubkey: "f".repeat(64),
|
||||
content: JSON.stringify({ lud16: "[email protected]" }),
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
nostrClient.ensurePool = () => {
|
||||
ensureCalls += 1;
|
||||
if (nostrClient.poolPromise) {
|
||||
return nostrClient.poolPromise;
|
||||
}
|
||||
const promise = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
poolReady = true;
|
||||
nostrClient.pool = poolStub;
|
||||
nostrClient.poolPromise = Promise.resolve(poolStub);
|
||||
resolve(poolStub);
|
||||
}, 10);
|
||||
});
|
||||
nostrClient.poolPromise = promise;
|
||||
return promise;
|
||||
};
|
||||
|
||||
const { deps: baseDeps } = createDeps();
|
||||
const deps = {
|
||||
lnurl: baseDeps.lnurl,
|
||||
wallet: baseDeps.wallet,
|
||||
platformAddress: platformAddressModule,
|
||||
};
|
||||
|
||||
const videoEvent = {
|
||||
id: "event-id",
|
||||
pubkey: "c".repeat(64),
|
||||
lightningAddress: "[email protected]",
|
||||
tags: [["d", "pointer"]],
|
||||
kind: 30078,
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await splitAndZap(
|
||||
{ videoEvent, amountSats: 1000, comment: "Delayed pool" },
|
||||
deps
|
||||
);
|
||||
|
||||
assert.equal(ensureCalls, 1, "should initialize the pool once");
|
||||
assert.equal(listCalls, 1, "should fetch platform metadata once the pool is ready");
|
||||
assert.equal(result.platformShare, 100);
|
||||
assert.equal(result.receipts.length, 2);
|
||||
} finally {
|
||||
nostrClient.ensurePool = originalEnsurePool;
|
||||
nostrClient.pool = originalPool;
|
||||
nostrClient.poolPromise = originalPoolPromise;
|
||||
__resetPlatformAddressCache();
|
||||
|
||||
if (previousOverride === undefined) {
|
||||
delete globalThis.__BITVID_PLATFORM_FEE_OVERRIDE__;
|
||||
} else {
|
||||
globalThis.__BITVID_PLATFORM_FEE_OVERRIDE__ = previousOverride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function testStringFeeOverride() {
|
||||
const videoEvent = {
|
||||
id: "event-id",
|
||||
@@ -298,6 +405,7 @@ async function testWalletFailure() {
|
||||
}
|
||||
|
||||
await testSplitMath();
|
||||
await testWaitsForPoolBeforePlatformLookup();
|
||||
await testLnurlBounds();
|
||||
await testMissingAddress();
|
||||
await testWalletFailure();
|
||||
|
||||
Reference in new issue
Block a user