mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-20 01:21:41 -06:00
fix(nostr): clear per-relay publish timeout timer to prevent dangling handles (#98720)
(cherry picked from commit a7a444e7ef)
This commit is contained in:
committed by
Dallin Romney
parent
dadc1c3faa
commit
f9fffe241b
@@ -1,5 +1,5 @@
|
||||
// Nostr tests cover nostr profile plugin behavior.
|
||||
import { verifyEvent, getPublicKey } from "nostr-tools";
|
||||
import { verifyEvent, getPublicKey, type SimplePool } from "nostr-tools";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { NostrProfile } from "./config-schema.js";
|
||||
import {
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
contentToProfile,
|
||||
validateProfile,
|
||||
sanitizeProfileForDisplay,
|
||||
publishProfile,
|
||||
type ProfileContent,
|
||||
} from "./nostr-profile.js";
|
||||
import { TEST_HEX_PRIVATE_KEY_BYTES } from "./test-fixtures.js";
|
||||
@@ -414,3 +415,74 @@ describe("edge cases", () => {
|
||||
expect(verifyEvent(event)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Profile Publishing Tests
|
||||
// ============================================================================
|
||||
|
||||
describe("publishProfile", () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
function createFakePool(publishResult: unknown): SimplePool {
|
||||
return {
|
||||
publish: vi.fn(() => [publishResult]),
|
||||
} as unknown as SimplePool;
|
||||
}
|
||||
|
||||
it("clears the per-relay timeout timer after a successful publish", async () => {
|
||||
const clearTimeoutSpy = vi.spyOn(globalThis, "clearTimeout");
|
||||
const profile: NostrProfile = { name: "test" };
|
||||
const pool = createFakePool(Promise.resolve());
|
||||
|
||||
const result = await publishProfile(
|
||||
pool,
|
||||
TEST_HEX_PRIVATE_KEY_BYTES,
|
||||
["wss://relay.example"],
|
||||
profile,
|
||||
);
|
||||
|
||||
expect(result.successes).toEqual(["wss://relay.example"]);
|
||||
expect(clearTimeoutSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("clears the per-relay timeout timer after a publish timeout", async () => {
|
||||
const clearTimeoutSpy = vi.spyOn(globalThis, "clearTimeout");
|
||||
const profile: NostrProfile = { name: "test" };
|
||||
const pool = createFakePool(new Promise(() => {}));
|
||||
|
||||
const promise = publishProfile(
|
||||
pool,
|
||||
TEST_HEX_PRIVATE_KEY_BYTES,
|
||||
["wss://relay.example"],
|
||||
profile,
|
||||
);
|
||||
vi.advanceTimersByTime(6_000);
|
||||
const result = await promise;
|
||||
|
||||
expect(result.failures).toHaveLength(1);
|
||||
expect(result.failures[0]?.error).toContain("timeout");
|
||||
expect(clearTimeoutSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not add dangling timers when publishing to multiple relays", async () => {
|
||||
vi.spyOn(globalThis, "setTimeout").mockClear();
|
||||
const clearTimeoutSpy = vi.spyOn(globalThis, "clearTimeout");
|
||||
const profile: NostrProfile = { name: "test" };
|
||||
const pool = createFakePool(Promise.resolve());
|
||||
|
||||
await publishProfile(
|
||||
pool,
|
||||
TEST_HEX_PRIVATE_KEY_BYTES,
|
||||
["wss://relay.a", "wss://relay.b"],
|
||||
profile,
|
||||
);
|
||||
|
||||
expect(clearTimeoutSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -98,9 +98,10 @@ async function publishProfileEvent(
|
||||
|
||||
// Publish to each relay in parallel with timeout
|
||||
const publishPromises = relays.map(async (relay) => {
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
try {
|
||||
const timeoutPromise = new Promise<never>((_, reject) => {
|
||||
setTimeout(() => reject(new Error("timeout")), RELAY_PUBLISH_TIMEOUT_MS);
|
||||
timer = setTimeout(() => reject(new Error("timeout")), RELAY_PUBLISH_TIMEOUT_MS);
|
||||
});
|
||||
|
||||
await Promise.race([...pool.publish([relay], event), timeoutPromise]);
|
||||
@@ -109,6 +110,10 @@ async function publishProfileEvent(
|
||||
} catch (err) {
|
||||
const errorMessage = formatErrorMessage(err);
|
||||
failures.push({ relay, error: errorMessage });
|
||||
} finally {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user