Skip to content

Commit

Permalink
improve loading relays when app loads
Browse files Browse the repository at this point in the history
  • Loading branch information
hzrd149 committed Oct 6, 2023
1 parent 88929a8 commit 37489e5
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 43 deletions.
5 changes: 5 additions & 0 deletions .changeset/pretty-buses-remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostrudel": patch
---

Reduce churn when loading relays on app load
2 changes: 1 addition & 1 deletion src/providers/post-modal-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function PostModalProvider({ children }: PropsWithChildren) {
return (
<PostModalContext.Provider value={context}>
<ErrorBoundary>
{isOpen && <PostModal isOpen onClose={onClose} initContent={initContent} />}
<PostModal isOpen={isOpen} onClose={onClose} initContent={initContent} />
{children}
</ErrorBoundary>
</PostModalContext.Provider>
Expand Down
88 changes: 51 additions & 37 deletions src/services/client-relays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const DEFAULT_RELAYS = [
{ url: "wss://relay.snort.social", mode: RelayMode.READ },
{ url: "wss://eden.nostr.land", mode: RelayMode.READ },
{ url: "wss://nos.lol", mode: RelayMode.READ },
{ url: "wss://purplerelay.com", mode: RelayMode.READ },
];

const userRelaysToRelayConfig: Connection<ParsedUserRelays, RelayConfig[], RelayConfig[] | undefined> = (
Expand All @@ -26,58 +27,71 @@ const userRelaysToRelayConfig: Connection<ParsedUserRelays, RelayConfig[], Relay
) => next(userRelays.relays);

class ClientRelayService {
bootstrapRelays = new Set<string>();
// bootstrapRelays = new Set<string>();
relays = new PersistentSubject<RelayConfig[]>([]);
writeRelays = new PersistentSubject<RelayConfig[]>([]);
readRelays = new PersistentSubject<RelayConfig[]>([]);

log = logger.extend("ClientRelays");

constructor() {
let lastSubject: Subject<ParsedUserRelays> | undefined;
accountService.current.subscribe((account) => {
if (!account) {
this.log("No account, using default relays");
this.relays.next(DEFAULT_RELAYS);
return;
} else this.relays.next([]);

if (account.relays) {
this.log("Found bootstrap relays");
this.bootstrapRelays.clear();
for (const relay of account.relays) {
this.bootstrapRelays.add(relay);
}
}

if (lastSubject) {
this.log("Disconnecting from previous user relays");
this.relays.disconnect(lastSubject);
lastSubject = undefined;
}

// load the relays from cache or bootstrap relays
this.log("Load users relays from cache or bootstrap relays");
lastSubject = userRelaysService.requestRelays(account.pubkey, Array.from(this.bootstrapRelays), {
alwaysRequest: true,
});
setTimeout(() => {
// double check for new relay notes
this.log("Requesting latest relays from the write relays");
userRelaysService.requestRelays(account.pubkey, this.getWriteUrls(), { alwaysRequest: true });
}, 1000);

this.relays.connectWithHandler(lastSubject, userRelaysToRelayConfig);
});
accountService.loading.subscribe(this.handleAccountChange, this);
accountService.current.subscribe(this.handleAccountChange, this);

// set the read and write relays
this.relays.subscribe((relays) => {
this.log("Got new relay list");
this.log("Got new relay list", relays);
this.writeRelays.next(relays.filter((r) => r.mode & RelayMode.WRITE));
this.readRelays.next(relays.filter((r) => r.mode & RelayMode.READ));
});
}

private userRequestRelaySubject: Subject<ParsedUserRelays> | undefined;
private handleAccountChange() {
if (accountService.loading.value) return;

// disconnect the relay list subject
if (this.userRequestRelaySubject) {
this.relays.disconnect(this.userRequestRelaySubject);
this.userRequestRelaySubject = undefined;
}

const account = accountService.current.value;
if (!account) {
this.log("No account, using default relays");
this.relays.next(DEFAULT_RELAYS);
return;
}

// clear relays
this.relays.next([]);

// connect the relay subject with the account relay subject
this.userRequestRelaySubject = userRelaysService.getRelays(account.pubkey);
this.relays.connectWithHandler(this.userRequestRelaySubject, userRelaysToRelayConfig);

// load the relays from cache
if (!userRelaysService.getRelays(account.pubkey).value) {
this.log("Load users relay list from cache");
userRelaysService.loadFromCache(account.pubkey).then(() => {
if (this.relays.value.length === 0) {
const bootstrapRelays = account.relays ?? ["wss://purplepag.es"];

this.log("Loading relay list from bootstrap relays", bootstrapRelays);
userRelaysService.requestRelays(account.pubkey, bootstrapRelays, { alwaysRequest: true });
}
});
}

// double check for new relay notes
setTimeout(() => {
if (this.relays.value.length === 0) return;

this.log("Requesting latest relay list from relays");
userRelaysService.requestRelays(account.pubkey, this.getWriteUrls(), { alwaysRequest: true });
}, 5000);
}

async addRelay(url: string, mode: RelayMode) {
this.log(`Adding ${url} relay`);
if (!this.relays.value.some((r) => r.url === url)) {
Expand Down
2 changes: 1 addition & 1 deletion src/services/replaceable-event-requester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ class ReplaceableEventLoaderService {
await transaction.done;
}
private loadCacheDedupe = new Map<string, Promise<boolean>>();
private loadFromCache(cord: string) {
loadFromCache(cord: string) {
const dedupe = this.loadCacheDedupe.get(cord);
if (dedupe) return dedupe;

Expand Down
12 changes: 11 additions & 1 deletion src/services/user-relays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import SuperMap from "../classes/super-map";
import Subject from "../classes/subject";
import { normalizeRelayConfigs } from "../helpers/relay";
import userContactsService from "./user-contacts";
import replaceableEventLoaderService, { RequestOptions } from "./replaceable-event-requester";
import replaceableEventLoaderService, { createCoordinate, RequestOptions } from "./replaceable-event-requester";

export type ParsedUserRelays = {
pubkey: string;
Expand Down Expand Up @@ -44,6 +44,16 @@ class UserRelaysService {
return sub;
}

async loadFromCache(pubkey: string) {
const sub = this.subjects.get(pubkey);

// load from cache
await replaceableEventLoaderService.loadFromCache(createCoordinate(Kind.RelayList, pubkey));

const requestSub = replaceableEventLoaderService.getEvent(Kind.RelayList, pubkey);
sub.connectWithHandler(requestSub, (event, next) => next(parseRelaysEvent(event)));
}

receiveEvent(event: NostrEvent) {
replaceableEventLoaderService.handleEvent(event);
}
Expand Down
2 changes: 0 additions & 2 deletions src/views/login/npub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ export default function LoginNpubView() {
accountService.addAccount({ pubkey, relays: [relayUrl], readonly: true });
}
accountService.switchAccount(pubkey);

clientRelaysService.bootstrapRelays.add(relayUrl);
};

return (
Expand Down
1 change: 0 additions & 1 deletion src/views/login/nsec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ export default function LoginNsecView() {

const encrypted = await signingService.encryptSecKey(hexKey);
accountService.addAccount({ pubkey, relays: [relayUrl], ...encrypted, readonly: false });
clientRelaysService.bootstrapRelays.add(relayUrl);
accountService.switchAccount(pubkey);
};

Expand Down

0 comments on commit 37489e5

Please sign in to comment.