mirror of https://github.com/waku-org/waku-lab.git
chore(buddybook): improvements
This commit is contained in:
parent
c047f204e9
commit
8ce736a665
|
@ -16,6 +16,8 @@ import ConnectionStatus from '@/components/ConnectionStatus';
|
||||||
|
|
||||||
type Status = 'success' | 'in-progress' | 'error';
|
type Status = 'success' | 'in-progress' | 'error';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface WakuStatus {
|
interface WakuStatus {
|
||||||
filter: Status;
|
filter: Status;
|
||||||
store: Status;
|
store: Status;
|
||||||
|
@ -30,6 +32,9 @@ function App() {
|
||||||
filter: 'in-progress',
|
filter: 'in-progress',
|
||||||
store: 'in-progress',
|
store: 'in-progress',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
(global.window as any).waku = node;
|
||||||
|
|
||||||
const [telemetryOptIn, setTelemetryOptIn] = useState<boolean | null>(null);
|
const [telemetryOptIn, setTelemetryOptIn] = useState<boolean | null>(null);
|
||||||
const [isLoadingChains, setIsLoadingChains] = useState(true);
|
const [isLoadingChains, setIsLoadingChains] = useState(true);
|
||||||
|
|
||||||
|
@ -41,10 +46,22 @@ function App() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isWakuLoading || !node || node.libp2p.getConnections().length <= 1 || chainsData.length > 0 || isListening) return;
|
if (isWakuLoading || !node || node.libp2p.getConnections().length === 0 || chainsData.length > 0 || isListening) {
|
||||||
|
console.log("not starting message listening");
|
||||||
|
console.log({
|
||||||
|
isWakuLoading,
|
||||||
|
node,
|
||||||
|
connections: node?.libp2p.getConnections().length,
|
||||||
|
chainsData,
|
||||||
|
isListening
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
setIsListening(true);
|
setIsListening(true);
|
||||||
console.log("connections", node.libp2p.getConnections().length)
|
console.log("connections", node.libp2p.getConnections().length)
|
||||||
startMessageListening();
|
setTimeout(() => {
|
||||||
|
startMessageListening();
|
||||||
|
}, 2000);
|
||||||
}, [node, isWakuLoading, wakuStatus])
|
}, [node, isWakuLoading, wakuStatus])
|
||||||
|
|
||||||
const handleTelemetryOptIn = (optIn: boolean) => {
|
const handleTelemetryOptIn = (optIn: boolean) => {
|
||||||
|
@ -69,25 +86,36 @@ function App() {
|
||||||
const startMessageListening = async () => {
|
const startMessageListening = async () => {
|
||||||
console.log("Starting message listening")
|
console.log("Starting message listening")
|
||||||
console.log("connections", node.libp2p.getConnections().length)
|
console.log("connections", node.libp2p.getConnections().length)
|
||||||
|
|
||||||
|
// Add timeout for store query
|
||||||
|
const STORE_TIMEOUT = 30000; // 30 seconds
|
||||||
|
const storeTimeout = new Promise((_, reject) => {
|
||||||
|
setTimeout(() => reject(new Error('Store query timeout')), STORE_TIMEOUT);
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setWakuStatus(prev => ({ ...prev, store: 'in-progress' }));
|
setWakuStatus(prev => ({ ...prev, store: 'in-progress' }));
|
||||||
setIsLoadingChains(true);
|
setIsLoadingChains(true);
|
||||||
const messageGenerator = getMessagesFromStore(node as LightNode);
|
const messageGenerator = getMessagesFromStore(node as LightNode);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for await (const message of messageGenerator) {
|
// Race between store query and timeout
|
||||||
setChainsData(prevChains => {
|
await Promise.race([
|
||||||
const blockExists = prevChains.some(block => block.blockUUID === message.blockUUID);
|
(async () => {
|
||||||
if (blockExists) return prevChains;
|
for await (const message of messageGenerator) {
|
||||||
return [...prevChains, message];
|
setChainsData(prevChains => {
|
||||||
});
|
const blockExists = prevChains.some(block => block.blockUUID === message.blockUUID);
|
||||||
}
|
if (blockExists) return prevChains;
|
||||||
|
return [...prevChains, message];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
storeTimeout
|
||||||
|
]);
|
||||||
setWakuStatus(prev => ({ ...prev, store: 'success' }));
|
setWakuStatus(prev => ({ ...prev, store: 'success' }));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error processing message:", error);
|
console.error("Error processing message:", error);
|
||||||
// Update store status to error when query fails
|
|
||||||
setWakuStatus(prev => ({ ...prev, store: 'error' }));
|
setWakuStatus(prev => ({ ...prev, store: 'error' }));
|
||||||
// Continue processing other messages
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching messages from store:", error);
|
console.error("Error fetching messages from store:", error);
|
||||||
|
@ -96,11 +124,21 @@ function App() {
|
||||||
setIsLoadingChains(false);
|
setIsLoadingChains(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add timeout for filter subscription
|
||||||
|
const FILTER_TIMEOUT = 15000; // 15 seconds
|
||||||
try {
|
try {
|
||||||
setWakuStatus(prev => ({ ...prev, filter: 'in-progress' }));
|
setWakuStatus(prev => ({ ...prev, filter: 'in-progress' }));
|
||||||
await subscribeToFilter(node as LightNode, (message) => {
|
const filterPromise = subscribeToFilter(node as LightNode, (message) => {
|
||||||
handleChainUpdate(message); // Use the same function for both updates
|
handleChainUpdate(message);
|
||||||
})
|
});
|
||||||
|
|
||||||
|
await Promise.race([
|
||||||
|
filterPromise,
|
||||||
|
new Promise((_, reject) =>
|
||||||
|
setTimeout(() => reject(new Error('Filter subscription timeout')), FILTER_TIMEOUT)
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
setWakuStatus(prev => ({ ...prev, filter: 'success' }));
|
setWakuStatus(prev => ({ ...prev, filter: 'success' }));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error subscribing to filter:", error);
|
console.error("Error subscribing to filter:", error);
|
||||||
|
|
|
@ -171,8 +171,8 @@ const SignChain: React.FC<SignChainProps> = ({ block, chainsData, onSuccess }) =
|
||||||
{alreadySigned ? 'Already Signed' : !address ? 'Connect Wallet' : 'Sign Chain'}
|
{alreadySigned ? 'Already Signed' : !address ? 'Connect Wallet' : 'Sign Chain'}
|
||||||
</Button>
|
</Button>
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<DialogContent className="sm:max-w-md flex flex-col max-h-[90vh] md:max-h-[85vh]">
|
<DialogContent className="sm:max-w-md">
|
||||||
<DialogHeader className="flex-shrink-0">
|
<DialogHeader>
|
||||||
<DialogTitle>Sign Chain</DialogTitle>
|
<DialogTitle>Sign Chain</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
{alreadySigned
|
{alreadySigned
|
||||||
|
@ -180,32 +180,28 @@ const SignChain: React.FC<SignChainProps> = ({ block, chainsData, onSuccess }) =
|
||||||
: 'Review the block details and sign to add your signature to the chain.'}
|
: 'Review the block details and sign to add your signature to the chain.'}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex-1 min-h-0 overflow-y-auto py-4">
|
<div className="flex flex-col space-y-4">
|
||||||
<div className="space-y-4">
|
<div className="space-y-2">
|
||||||
<div className="space-y-2">
|
<h4 className="font-medium">Block Details</h4>
|
||||||
<h4 className="font-medium">Block Details</h4>
|
<p className="text-sm text-muted-foreground">{block.title}</p>
|
||||||
<p className="text-sm text-muted-foreground">{block.title}</p>
|
<p className="text-sm text-muted-foreground">{block.description}</p>
|
||||||
<p className="text-sm text-muted-foreground">{block.description}</p>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<QRCode text={`${window.location.origin}/sign/${block.chainUUID}/${block.blockUUID}`} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{(error || isWalletPrompt) && (
|
<QRCode text={`${window.location.origin}/sign/${block.chainUUID}/${block.blockUUID}`} />
|
||||||
<div className="space-y-2 mt-4">
|
|
||||||
{error && <p className="text-sm text-destructive">{error}</p>}
|
|
||||||
{isWalletPrompt && (
|
|
||||||
<div className="rounded-md bg-blue-50 p-4">
|
|
||||||
<p className="text-sm text-blue-700">Attempting to connect to your wallet...</p>
|
|
||||||
<p className="text-xs text-blue-600 mt-1">
|
|
||||||
If your wallet doesn't open automatically, please open it manually to approve the connection.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<DialogFooter className="flex-shrink-0 mt-4">
|
{(error || isWalletPrompt) && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
{error && <p className="text-sm text-destructive">{error}</p>}
|
||||||
|
{isWalletPrompt && (
|
||||||
|
<div className="rounded-md bg-blue-50 p-4">
|
||||||
|
<p className="text-sm text-blue-700">Attempting to connect to your wallet...</p>
|
||||||
|
<p className="text-xs text-blue-600 mt-1">
|
||||||
|
If your wallet doesn't open automatically, please open it manually to approve the connection.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<DialogFooter>
|
||||||
<Button variant="secondary" onClick={() => setIsOpen(false)}>Cancel</Button>
|
<Button variant="secondary" onClick={() => setIsOpen(false)}>Cancel</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSign}
|
onClick={handleSign}
|
||||||
|
|
|
@ -65,28 +65,33 @@ export function createMessage({
|
||||||
|
|
||||||
export async function* getMessagesFromStore(node: LightNode) {
|
export async function* getMessagesFromStore(node: LightNode) {
|
||||||
console.time("getMessagesFromStore")
|
console.time("getMessagesFromStore")
|
||||||
for await (const messagePromises of node.store.queryGenerator([decoder])) {
|
try {
|
||||||
const messages = await Promise.all(messagePromises);
|
for await (const messagePromises of node.store.queryGenerator([decoder])) {
|
||||||
for (const message of messages) {
|
const messages = await Promise.all(messagePromises);
|
||||||
console.log(message)
|
for (const message of messages) {
|
||||||
if (!message?.payload) continue;
|
if (!message?.payload) continue;
|
||||||
const blockPayload = block.decode(message.payload) as unknown as BlockPayload;
|
const blockPayload = block.decode(message.payload) as unknown as BlockPayload;
|
||||||
blockPayload.signatures = blockPayload.signatures.map(s => JSON.parse(s as unknown as string) as Signature);
|
blockPayload.signatures = blockPayload.signatures.map(s => JSON.parse(s as unknown as string) as Signature);
|
||||||
yield blockPayload;
|
yield blockPayload;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
console.timeEnd("getMessagesFromStore")
|
||||||
}
|
}
|
||||||
console.timeEnd("getMessagesFromStore")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function subscribeToFilter(node: LightNode, callback: (message: BlockPayload) => void) {
|
export async function subscribeToFilter(node: LightNode, callback: (message: BlockPayload) => void) {
|
||||||
const {error, subscription, results} = await node.filter.subscribe([decoder], (message) => {
|
const {error, subscription, results} = await node.filter.subscribe(
|
||||||
console.log('message received from filter', message)
|
[decoder],
|
||||||
if (message.payload) {
|
(message) => {
|
||||||
const blockPayload = block.decode(message.payload) as unknown as BlockPayload;
|
console.log('message received from filter', message)
|
||||||
blockPayload.signatures = blockPayload.signatures.map(s => JSON.parse(s as unknown as string) as Signature);
|
if (message.payload) {
|
||||||
callback(blockPayload);
|
const blockPayload = block.decode(message.payload) as unknown as BlockPayload;
|
||||||
|
blockPayload.signatures = blockPayload.signatures.map(s => JSON.parse(s as unknown as string) as Signature);
|
||||||
|
callback(blockPayload);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, {forceUseAllPeers: false});
|
);
|
||||||
|
|
||||||
console.log("results", results)
|
console.log("results", results)
|
||||||
|
|
||||||
|
@ -94,7 +99,7 @@ export async function subscribeToFilter(node: LightNode, callback: (message: Blo
|
||||||
console.log("Error subscribing to filter", error)
|
console.log("Error subscribing to filter", error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!subscription || error || results.successes.length === 0 ||results.failures.length >0) {
|
if (!subscription || error || results.successes.length === 0 || results.failures.length > 0) {
|
||||||
throw new Error("Failed to subscribe to filter")
|
throw new Error("Failed to subscribe to filter")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue