This commit is contained in:
2023-05-18 16:51:21 +01:00
parent 185e089ffd
commit 126a55f3c4
6 changed files with 64 additions and 64 deletions

View File

@ -85,7 +85,7 @@ class UserProfileCache extends FeedCache<MetadataCache> {
await svc.load(); await svc.load();
const p = this.getFromCache(i.pubkey); const p = this.getFromCache(i.pubkey);
if (p) { if (p) {
this.#setItem({ await this.set({
...p, ...p,
zapService: svc.zapperPubkey, zapService: svc.zapperPubkey,
}); });
@ -105,7 +105,7 @@ class UserProfileCache extends FeedCache<MetadataCache> {
const nip5pk = await fetchNip05Pubkey(name, domain); const nip5pk = await fetchNip05Pubkey(name, domain);
const p = this.getFromCache(i.pubkey); const p = this.getFromCache(i.pubkey);
if (p) { if (p) {
this.#setItem({ await this.set({
...p, ...p,
isNostrAddressValid: i.pubkey === nip5pk, isNostrAddressValid: i.pubkey === nip5pk,
}); });

View File

@ -80,7 +80,7 @@ export default function ZapPoolPage() {
const relayConnections = useMemo(() => { const relayConnections = useMemo(() => {
return [...System.Sockets.values()] return [...System.Sockets.values()]
.map(a => { .map(a => {
if (a.Info?.pubkey) { if (a.Info?.pubkey && !a.Ephemeral) {
return { return {
address: a.Address, address: a.Address,
pubkey: a.Info.pubkey, pubkey: a.Info.pubkey,

View File

@ -97,13 +97,15 @@ export function splitByWriteRelays(filter: RawReqFilter): Array<RelayTaggedFilte
}, },
} as RelayTaggedFilter; } as RelayTaggedFilter;
}); });
picked.push({ if (missing.length > 0) {
relay: "", picked.push({
filter: { relay: "",
...filter, filter: {
authors: missing.map(a => a.key), ...filter,
}, authors: missing.map(a => a.key),
}); },
});
}
console.debug("GOSSIP", picked); console.debug("GOSSIP", picked);
return picked; return picked;
} }

View File

@ -1,6 +1,6 @@
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { Connection, RawReqFilter, Nips } from "@snort/nostr"; import { Connection, RawReqFilter, Nips } from "@snort/nostr";
import { unixNowMs } from "Util"; import { unixNowMs, unwrap } from "Util";
import { NoteStore } from "./NoteCollection"; import { NoteStore } from "./NoteCollection";
/** /**
* Tracing for relay query status * Tracing for relay query status
@ -32,6 +32,9 @@ class QueryTrace {
gotEose() { gotEose() {
this.eose = unixNowMs(); this.eose = unixNowMs();
if (this.responseTime > 5_000) {
console.debug(`Slow query ${this.subId} on ${this.relay} took ${this.responseTime.toLocaleString()}ms`);
}
} }
forceEose() { forceEose() {
@ -66,6 +69,13 @@ class QueryTrace {
return (this.eose === undefined ? unixNowMs() : this.eose) - this.start; return (this.eose === undefined ? unixNowMs() : this.eose) - this.start;
} }
/**
* Total time spent waiting for relay to respond
*/
get responseTime() {
return this.finished ? unwrap(this.eose) - unwrap(this.sent) : 0;
}
/** /**
* If tracing is finished, we got EOSE or timeout * If tracing is finished, we got EOSE or timeout
*/ */
@ -193,16 +203,13 @@ export class Query {
qt?.gotEose(); qt?.gotEose();
if (sub === this.id) { if (sub === this.id) {
console.debug(`[EOSE][${sub}] ${conn.Address}`); console.debug(`[EOSE][${sub}] ${conn.Address}`);
this.#feed.loading = this.progress < 1; if (!this.leaveOpen) {
if (!this.leaveOpen && !this.#feed.loading) { qt?.sendClose();
this.sendClose();
} }
} else { } else {
const subQ = this.subQueries.find(a => a.id === sub); const subQ = this.subQueries.find(a => a.id === sub);
if (subQ) { if (subQ) {
subQ.eose(sub, conn); subQ.eose(sub, conn);
} else {
throw new Error("No query found");
} }
} }
} }

View File

@ -1,5 +1,6 @@
import { useSyncExternalStore } from "react"; import { useEffect, useSyncExternalStore } from "react";
import ExternalStore from "ExternalStore";
import { decodeInvoice, unwrap } from "Util"; import { decodeInvoice, unwrap } from "Util";
import LNDHubWallet from "./LNDHub"; import LNDHubWallet from "./LNDHub";
import { NostrConnectWallet } from "./NostrWalletConnect"; import { NostrConnectWallet } from "./NostrWalletConnect";
@ -124,35 +125,19 @@ export interface WalletStoreSnapshot {
wallet?: LNWallet; wallet?: LNWallet;
} }
type WalletStateHook = (state: WalletStoreSnapshot) => void; export class WalletStore extends ExternalStore<WalletStoreSnapshot> {
export class WalletStore {
#configs: Array<WalletConfig>; #configs: Array<WalletConfig>;
#instance: Map<string, LNWallet>; #instance: Map<string, LNWallet>;
#hooks: Array<WalletStateHook>;
#snapshot: Readonly<WalletStoreSnapshot>;
constructor() { constructor() {
super();
this.#configs = []; this.#configs = [];
this.#instance = new Map(); this.#instance = new Map();
this.#hooks = [];
this.#snapshot = Object.freeze({
configs: [],
});
this.load(false); this.load(false);
setupWebLNWalletConfig(this); setupWebLNWalletConfig(this);
this.snapshotState(); this.snapshotState();
} }
hook(fn: WalletStateHook) {
this.#hooks.push(fn);
return () => {
const idx = this.#hooks.findIndex(a => a === fn);
this.#hooks = this.#hooks.splice(idx, 1);
};
}
list() { list() {
return Object.freeze([...this.#configs]); return Object.freeze([...this.#configs]);
} }
@ -171,9 +156,9 @@ export class WalletStore {
const w = this.#activateWallet(activeConfig); const w = this.#activateWallet(activeConfig);
if (w) { if (w) {
if ("then" in w) { if ("then" in w) {
w.then(wx => { w.then(async wx => {
this.#instance.set(activeConfig.id, wx); this.#instance.set(activeConfig.id, wx);
this.snapshotState(); this.notifyChange();
}); });
return undefined; return undefined;
} }
@ -209,7 +194,7 @@ export class WalletStore {
save() { save() {
const json = JSON.stringify(this.#configs); const json = JSON.stringify(this.#configs);
window.localStorage.setItem("wallet-config", json); window.localStorage.setItem("wallet-config", json);
this.snapshotState(); this.notifyChange();
} }
load(snapshot = true) { load(snapshot = true) {
@ -218,7 +203,7 @@ export class WalletStore {
this.#configs = JSON.parse(cfg); this.#configs = JSON.parse(cfg);
} }
if (snapshot) { if (snapshot) {
this.snapshotState(); this.notifyChange();
} }
} }
@ -226,21 +211,12 @@ export class WalletStore {
this.#instance.forEach(w => w.close()); this.#instance.forEach(w => w.close());
} }
getSnapshot() { takeSnapshot(): WalletStoreSnapshot {
return this.#snapshot; return {
}
snapshotState() {
const newState = {
configs: [...this.#configs], configs: [...this.#configs],
config: this.#configs.find(a => a.active), config: this.#configs.find(a => a.active),
wallet: this.get(), wallet: this.get(),
} as WalletStoreSnapshot; } as WalletStoreSnapshot;
this.#snapshot = Object.freeze(newState);
for (const hook of this.#hooks) {
console.debug(this.#snapshot);
hook(this.#snapshot);
}
} }
#activateWallet(cfg: WalletConfig): LNWallet | Promise<LNWallet> | undefined { #activateWallet(cfg: WalletConfig): LNWallet | Promise<LNWallet> | undefined {
@ -270,8 +246,14 @@ window.document.addEventListener("close", () => {
}); });
export function useWallet() { export function useWallet() {
return useSyncExternalStore<WalletStoreSnapshot>( const wallet = useSyncExternalStore<WalletStoreSnapshot>(
h => Wallets.hook(h), h => Wallets.hook(h),
() => Wallets.getSnapshot() () => Wallets.snapshot()
); );
useEffect(() => {
if (wallet.wallet?.isReady() === false && wallet.wallet.canAutoLogin()) {
wallet.wallet.login().catch(console.error);
}
}, [wallet]);
return wallet;
} }

View File

@ -96,10 +96,6 @@ export class Connection {
this.AwaitingAuth = new Map(); this.AwaitingAuth = new Map();
this.Auth = auth; this.Auth = auth;
this.Ephemeral = ephemeral; this.Ephemeral = ephemeral;
if (this.Ephemeral) {
this.ResetEphemeralTimeout();
}
} }
ResetEphemeralTimeout() { ResetEphemeralTimeout() {
@ -109,7 +105,7 @@ export class Connection {
if (this.Ephemeral) { if (this.Ephemeral) {
this.EphemeralTimeout = setTimeout(() => { this.EphemeralTimeout = setTimeout(() => {
this.Close(); this.Close();
}, 10_000); }, 30_000);
} }
} }
@ -139,6 +135,13 @@ export class Connection {
console.warn("Could not load relay information", e); console.warn("Could not load relay information", e);
} }
if (this.Socket) {
this.Id = uuid();
this.Socket.onopen = null;
this.Socket.onmessage = null;
this.Socket.onerror = null;
this.Socket.onclose = null;
}
this.IsClosed = false; this.IsClosed = false;
this.Socket = new WebSocket(this.Address); this.Socket = new WebSocket(this.Address);
this.Socket.onopen = () => this.OnOpen(); this.Socket.onopen = () => this.OnOpen();
@ -161,17 +164,15 @@ export class Connection {
this.ConnectTimeout = DefaultConnectTimeout; this.ConnectTimeout = DefaultConnectTimeout;
console.log(`[${this.Address}] Open!`); console.log(`[${this.Address}] Open!`);
this.Down = false; this.Down = false;
if (this.Ephemeral) {
this.ResetEphemeralTimeout();
}
this.OnConnected?.(); this.OnConnected?.();
this.#sendPendingRaw();
} }
OnClose(e: CloseEvent) { OnClose(e: CloseEvent) {
if (!this.IsClosed) { if (!this.IsClosed) {
this.OnDisconnect?.([...this.ActiveRequests], this.PendingRequests.map(a => a.cmd[1]))
this.#ResetQueues();
// reset connection Id on disconnect, for query-tracking
this.Id = uuid();
this.ConnectTimeout = this.ConnectTimeout * 2; this.ConnectTimeout = this.ConnectTimeout * 2;
console.log( console.log(
`[${this.Address}] Closed (${e.reason}), trying again in ${( `[${this.Address}] Closed (${e.reason}), trying again in ${(
@ -188,6 +189,11 @@ export class Connection {
console.log(`[${this.Address}] Closed!`); console.log(`[${this.Address}] Closed!`);
this.ReconnectTimer = null; this.ReconnectTimer = null;
} }
this.OnDisconnect?.([...this.ActiveRequests], this.PendingRequests.map(a => a.cmd[1]))
this.#ResetQueues();
// reset connection Id on disconnect, for query-tracking
this.Id = uuid();
this.#UpdateState(); this.#UpdateState();
} }
@ -387,6 +393,9 @@ export class Connection {
const authPending = !this.Authed && (this.AwaitingAuth.size > 0 || this.Info?.limitation?.auth_required === true); const authPending = !this.Authed && (this.AwaitingAuth.size > 0 || this.Info?.limitation?.auth_required === true);
if (this.Socket?.readyState !== WebSocket.OPEN || authPending) { if (this.Socket?.readyState !== WebSocket.OPEN || authPending) {
this.PendingRaw.push(obj); this.PendingRaw.push(obj);
if (this.Socket?.readyState === WebSocket.CLOSED && this.Ephemeral && this.IsClosed) {
this.Connect()
}
return false; return false;
} }
@ -405,7 +414,7 @@ export class Connection {
#sendOnWire(obj: unknown) { #sendOnWire(obj: unknown) {
if (this.Socket?.readyState !== WebSocket.OPEN) { if (this.Socket?.readyState !== WebSocket.OPEN) {
throw new Error("Socket is not open"); throw new Error(`Socket is not open, state is ${this.Socket?.readyState}`);
} }
const json = JSON.stringify(obj); const json = JSON.stringify(obj);
this.Socket.send(json); this.Socket.send(json);