diff --git a/src/Feed/EventPublisher.ts b/src/Feed/EventPublisher.ts index 8c12130c..b62d6883 100644 --- a/src/Feed/EventPublisher.ts +++ b/src/Feed/EventPublisher.ts @@ -6,7 +6,7 @@ import Tag from "Nostr/Tag"; import { RootState } from "State/Store"; import { HexKey, RawEvent, u256, UserMetadata } from "Nostr"; import { bech32ToHex } from "Util" -import { HashtagRegex } from "Const"; +import { DefaultRelays, HashtagRegex } from "Const"; declare global { interface Window { @@ -72,6 +72,18 @@ export default function useEventPublisher() { System.BroadcastEvent(ev); } }, + /** + * Write event to DefaultRelays, this is important for profiles / relay lists to prevent bugs + * If a user removes all the DefaultRelays from their relay list and saves that relay list, + * When they open the site again we wont see that updated relay list and so it will appear to reset back to the previous state + */ + broadcastForBootstrap: (ev: NEvent | undefined) => { + if(ev) { + for(let [k, _] of DefaultRelays) { + System.WriteOnceToRelay(k, ev); + } + } + }, metadata: async (obj: UserMetadata) => { if (pubKey) { let ev = NEvent.ForPubKey(pubKey); diff --git a/src/Nostr/Connection.ts b/src/Nostr/Connection.ts index 680eb64b..1ddd14f8 100644 --- a/src/Nostr/Connection.ts +++ b/src/Nostr/Connection.ts @@ -5,7 +5,7 @@ import { Subscriptions } from "Nostr/Subscriptions"; import { default as NEvent } from "Nostr/Event"; import { DefaultConnectTimeout } from "Const"; import { ConnectionStats } from "Nostr/ConnectionStats"; -import { RawEvent, TaggedRawEvent } from "Nostr"; +import { RawEvent, TaggedRawEvent, u256 } from "Nostr"; export type CustomHook = (state: Readonly) => void; @@ -44,6 +44,7 @@ export default class Connection { LastState: Readonly; IsClosed: boolean; ReconnectTimer: ReturnType | null; + EventsCallback: Map void>; constructor(addr: string, options: RelaySettings) { this.Address = addr; @@ -67,6 +68,7 @@ export default class Connection { this.LastState = Object.freeze({ ...this.CurrentState }); this.IsClosed = false; this.ReconnectTimer = null; + this.EventsCallback = new Map(); this.Connect(); } @@ -138,6 +140,12 @@ export default class Connection { case "OK": { // feedback to broadcast call console.debug("OK: ", msg); + const id = msg[1]; + if (this.EventsCallback.has(id)) { + let cb = this.EventsCallback.get(id)!; + this.EventsCallback.delete(id); + cb(); + } break; } case "NOTICE": { @@ -170,6 +178,30 @@ export default class Connection { this._UpdateState(); } + /** + * Send event on this connection and wait for OK response + */ + async SendAsync(e: NEvent, timeout: number = 5000) { + return new Promise((resolve, reject) => { + if (!this.Settings.write) { + resolve(); + return; + } + let t = setTimeout(() => { + resolve(); + }, timeout); + this.EventsCallback.set(e.Id, () => { + clearTimeout(t); + resolve(); + }); + + let req = ["EVENT", e.ToObject()]; + this._SendJson(req); + this.Stats.EventsSent++; + this._UpdateState(); + }); + } + /** * Subscribe to data from this connection */ diff --git a/src/Nostr/System.ts b/src/Nostr/System.ts index 8cfda4a5..bdc81e73 100644 --- a/src/Nostr/System.ts +++ b/src/Nostr/System.ts @@ -50,6 +50,9 @@ export class NostrSystem { for (let [_, s] of this.Subscriptions) { c.AddSubscription(s); } + } else { + // update settings if already connected + this.Sockets.get(address)!.Settings = options; } } catch (e) { console.error(e); @@ -90,6 +93,15 @@ export class NostrSystem { } } + /** + * Write an event to a relay then disconnect + */ + async WriteOnceToRelay(address: string, ev: Event) { + let c = new Connection(address, { write: true, read: false }); + await c.SendAsync(ev); + c.Close(); + } + /** * Request profile metadata for a set of pubkeys */ @@ -179,9 +191,9 @@ export class NostrSystem { let profile = mapEventToProfile(e); if (profile) { let existing = await db.users.get(profile.pubkey); - if((existing?.created ?? 0) < profile.created) { + if ((existing?.created ?? 0) < profile.created) { await db.users.put(profile); - } else if(existing) { + } else if (existing) { await db.users.update(profile.pubkey, { loaded: new Date().getTime() }); } } diff --git a/src/Pages/settings/Relays.tsx b/src/Pages/settings/Relays.tsx index bb81c1e7..3ca0fca4 100644 --- a/src/Pages/settings/Relays.tsx +++ b/src/Pages/settings/Relays.tsx @@ -16,6 +16,7 @@ const RelaySettingsPage = () => { async function saveRelays() { let ev = await publisher.saveRelays(); publisher.broadcast(ev); + publisher.broadcastForBootstrap(ev); }