Wait for the signer before loading the UI (fix Ditto race condition)
This commit is contained in:
parent
bbdc224010
commit
0b1446c655
|
@ -8,7 +8,10 @@ const secretStorageKey = 'soapbox:nip46:secret';
|
|||
sessionStorage.setItem(secretStorageKey, crypto.randomUUID());
|
||||
|
||||
function useSignerStream() {
|
||||
const { relay, signer } = useNostr();
|
||||
const [isSubscribed, setIsSubscribed] = useState(false);
|
||||
const [isSubscribing, setIsSubscribing] = useState(true);
|
||||
|
||||
const { relay, signer, hasNostr } = useNostr();
|
||||
const [pubkey, setPubkey] = useState<string | undefined>(undefined);
|
||||
|
||||
const authStorageKey = `soapbox:nostr:auth:${pubkey}`;
|
||||
|
@ -16,7 +19,7 @@ function useSignerStream() {
|
|||
useEffect(() => {
|
||||
let isCancelled = false;
|
||||
|
||||
if (signer) {
|
||||
if (signer && hasNostr) {
|
||||
signer.getPublicKey().then((newPubkey) => {
|
||||
if (!isCancelled) {
|
||||
setPubkey(newPubkey);
|
||||
|
@ -27,7 +30,7 @@ function useSignerStream() {
|
|||
return () => {
|
||||
isCancelled = true;
|
||||
};
|
||||
}, [signer]);
|
||||
}, [signer, hasNostr]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!relay || !signer || !pubkey) return;
|
||||
|
@ -39,6 +42,10 @@ function useSignerStream() {
|
|||
localStorage.setItem(authStorageKey, authorizedPubkey);
|
||||
sessionStorage.setItem(secretStorageKey, crypto.randomUUID());
|
||||
},
|
||||
onSubscribed() {
|
||||
setIsSubscribed(true);
|
||||
setIsSubscribing(false);
|
||||
},
|
||||
authorizedPubkey: localStorage.getItem(authStorageKey) ?? undefined,
|
||||
getSecret: () => sessionStorage.getItem(secretStorageKey)!,
|
||||
});
|
||||
|
@ -47,6 +54,11 @@ function useSignerStream() {
|
|||
connect.close();
|
||||
};
|
||||
}, [relay, signer, pubkey]);
|
||||
|
||||
return {
|
||||
isSubscribed,
|
||||
isSubscribing,
|
||||
};
|
||||
}
|
||||
|
||||
export { useSignerStream };
|
||||
|
|
|
@ -8,6 +8,8 @@ import { useInstance } from 'soapbox/hooks/useInstance';
|
|||
interface NostrContextType {
|
||||
relay?: NRelay;
|
||||
signer?: NostrSigner;
|
||||
hasNostr: boolean;
|
||||
isRelayOpen: boolean;
|
||||
}
|
||||
|
||||
const NostrContext = createContext<NostrContextType | undefined>(undefined);
|
||||
|
@ -18,7 +20,10 @@ interface NostrProviderProps {
|
|||
|
||||
export const NostrProvider: React.FC<NostrProviderProps> = ({ children }) => {
|
||||
const instance = useInstance();
|
||||
const hasNostr = !!instance.nostr;
|
||||
|
||||
const [relay, setRelay] = useState<NRelay1>();
|
||||
const [isRelayOpen, setIsRelayOpen] = useState(false);
|
||||
|
||||
const { account } = useOwnAccount();
|
||||
|
||||
|
@ -30,17 +35,24 @@ export const NostrProvider: React.FC<NostrProviderProps> = ({ children }) => {
|
|||
[accountPubkey],
|
||||
);
|
||||
|
||||
const handleRelayOpen = () => {
|
||||
setIsRelayOpen(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (url) {
|
||||
setRelay(new NRelay1(url));
|
||||
const relay = new NRelay1(url);
|
||||
relay.socket.underlyingWebsocket.addEventListener('open', handleRelayOpen);
|
||||
setRelay(relay);
|
||||
}
|
||||
return () => {
|
||||
relay?.socket.underlyingWebsocket.removeEventListener('open', handleRelayOpen);
|
||||
relay?.close();
|
||||
};
|
||||
}, [url]);
|
||||
|
||||
return (
|
||||
<NostrContext.Provider value={{ relay, signer }}>
|
||||
<NostrContext.Provider value={{ relay, signer, isRelayOpen, hasNostr }}>
|
||||
{children}
|
||||
</NostrContext.Provider>
|
||||
);
|
||||
|
|
|
@ -5,6 +5,7 @@ interface NConnectOpts {
|
|||
signer: NostrSigner;
|
||||
authorizedPubkey: string | undefined;
|
||||
onAuthorize(pubkey: string): void;
|
||||
onSubscribed(): void;
|
||||
getSecret(): string;
|
||||
}
|
||||
|
||||
|
@ -14,6 +15,7 @@ export class NConnect {
|
|||
private signer: NostrSigner;
|
||||
private authorizedPubkey: string | undefined;
|
||||
private onAuthorize: (pubkey: string) => void;
|
||||
private onSubscribed: () => void;
|
||||
private getSecret: () => string;
|
||||
|
||||
private controller = new AbortController();
|
||||
|
@ -23,6 +25,7 @@ export class NConnect {
|
|||
this.signer = opts.signer;
|
||||
this.authorizedPubkey = opts.authorizedPubkey;
|
||||
this.onAuthorize = opts.onAuthorize;
|
||||
this.onSubscribed = opts.onSubscribed;
|
||||
this.getSecret = opts.getSecret;
|
||||
|
||||
this.open();
|
||||
|
@ -32,7 +35,10 @@ export class NConnect {
|
|||
const pubkey = await this.signer.getPublicKey();
|
||||
const signal = this.controller.signal;
|
||||
|
||||
for await (const msg of this.relay.req([{ kinds: [24133], '#p': [pubkey] }], { signal })) {
|
||||
const sub = this.relay.req([{ kinds: [24133], '#p': [pubkey] }], { signal });
|
||||
this.onSubscribed();
|
||||
|
||||
for await (const msg of sub) {
|
||||
if (msg[0] === 'EVENT') {
|
||||
const event = msg[2];
|
||||
this.handleEvent(event);
|
||||
|
|
|
@ -6,6 +6,7 @@ import { fetchMe } from 'soapbox/actions/me';
|
|||
import { loadSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import { useSignerStream } from 'soapbox/api/hooks/nostr/useSignerStream';
|
||||
import LoadingScreen from 'soapbox/components/loading-screen';
|
||||
import { useNostr } from 'soapbox/contexts/nostr-context';
|
||||
import {
|
||||
useAppSelector,
|
||||
useAppDispatch,
|
||||
|
@ -44,7 +45,8 @@ const SoapboxLoad: React.FC<ISoapboxLoad> = ({ children }) => {
|
|||
const [localeLoading, setLocaleLoading] = useState(true);
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
|
||||
useSignerStream();
|
||||
const { hasNostr, isRelayOpen } = useNostr();
|
||||
const { isSubscribed } = useSignerStream();
|
||||
|
||||
/** Whether to display a loading indicator. */
|
||||
const showLoading = [
|
||||
|
@ -53,6 +55,7 @@ const SoapboxLoad: React.FC<ISoapboxLoad> = ({ children }) => {
|
|||
!isLoaded,
|
||||
localeLoading,
|
||||
swUpdating,
|
||||
hasNostr && (!isRelayOpen || !isSubscribed),
|
||||
].some(Boolean);
|
||||
|
||||
// Load the user's locale
|
||||
|
|
Loading…
Reference in New Issue