A quick vibe-coded site to test response times of PLC.directory mirrors (over 3 attempts)
at main 6.1 kB view raw
1import { useState } from "react"; 2import { Button } from "@/components/ui/button"; 3import { Input } from "@/components/ui/input"; 4import { BenchmarkTable } from "@/components/BenchmarkTable"; 5import { mirrors } from "@/config/mirrors"; 6import { benchmarkAllMirrors } from "@/utils/benchmark"; 7import { BenchmarkResult } from "@/types/benchmark"; 8import { toast } from "sonner"; 9import { Activity, Zap } from "lucide-react"; 10 11const Index = () => { 12 const [did, setDid] = useState(""); 13 const [loading, setLoading] = useState(false); 14 const [results, setResults] = useState<BenchmarkResult[]>([]); 15 16 const resolveHandle = async (handle: string): Promise<string | null> => { 17 try { 18 const response = await fetch( 19 `https://quickdid.smokesignal.tools/xrpc/com.atproto.identity.resolveHandle?handle=${ 20 encodeURIComponent(handle) 21 }`, 22 ); 23 const data = await response.json(); 24 25 if (data.error) { 26 toast.error( 27 `Unable to resolve handle: ${data.message || "Invalid handle"}`, 28 ); 29 return null; 30 } 31 32 return data.did; 33 } catch (error) { 34 toast.error("Failed to resolve handle"); 35 console.error(error); 36 return null; 37 } 38 }; 39 40 const handleBenchmark = async () => { 41 if (!did.trim()) { 42 toast.error("Please enter a DID or handle"); 43 return; 44 } 45 46 setLoading(true); 47 setResults([]); 48 49 try { 50 let resolvedDid = did.trim(); 51 52 // If input doesn't start with "did:plc", treat it as a handle 53 if (!resolvedDid.startsWith("did:plc")) { 54 const resolved = await resolveHandle(resolvedDid); 55 if (!resolved) { 56 setLoading(false); 57 return; 58 } 59 resolvedDid = resolved; 60 toast.success(`Resolved to ${resolvedDid}`); 61 } 62 63 const benchmarkResults = await benchmarkAllMirrors(mirrors, resolvedDid); 64 setResults(benchmarkResults); 65 66 const successCount = benchmarkResults.filter((r) => 67 r.status === "success" 68 ).length; 69 toast.success( 70 `Benchmark complete! ${successCount}/${benchmarkResults.length} mirrors responded`, 71 ); 72 } catch (error) { 73 toast.error("Failed to run benchmark"); 74 console.error(error); 75 } finally { 76 setLoading(false); 77 } 78 }; 79 80 const handleKeyPress = (e: React.KeyboardEvent) => { 81 if (e.key === "Enter" && !loading) { 82 handleBenchmark(); 83 } 84 }; 85 86 return ( 87 <div className="min-h-screen bg-background py-8 px-4"> 88 <div className="max-w-6xl mx-auto space-y-8"> 89 {/* Header */} 90 <header className="text-center space-y-3"> 91 <div className="flex items-center justify-center gap-2 text-primary"> 92 <Activity className="w-8 h-8" /> 93 <h1 className="text-4xl font-bold">PLC Mirror Benchmark</h1> 94 </div> 95 <p className="text-muted-foreground text-lg max-w-2xl mx-auto"> 96 Test and compare response times across different PLC.directory 97 mirrors 98 </p> 99 </header> 100 101 {/* Input Section */} 102 <div className="bg-card border border-border rounded-lg p-6 shadow-sm"> 103 <div className="space-y-4"> 104 <div> 105 <label 106 htmlFor="did-input" 107 className="block text-sm font-medium mb-2" 108 > 109 ATProto DID or Handle 110 </label> 111 <div className="flex gap-3"> 112 <Input 113 id="did-input" 114 type="text" 115 placeholder="did:plc:example123... or handle.bsky.social" 116 value={did} 117 onChange={(e) => setDid(e.target.value)} 118 onKeyPress={handleKeyPress} 119 className="flex-1 font-mono" 120 disabled={loading} 121 /> 122 <Button 123 onClick={handleBenchmark} 124 disabled={loading || !did.trim()} 125 className="gap-2" 126 > 127 <Zap className="w-4 h-4" /> 128 {loading ? "Benchmarking..." : "Run Benchmark"} 129 </Button> 130 </div> 131 </div> 132 <div className="text-sm text-muted-foreground"> 133 Testing {mirrors.length} mirrors with 5 attempts each 134 </div> 135 </div> 136 </div> 137 138 {/* Results Section */} 139 {(results.length > 0 || loading) && ( 140 <div className="space-y-4"> 141 <h2 className="text-2xl font-semibold">Results</h2> 142 {loading 143 ? ( 144 <div className="bg-card border border-border rounded-lg p-12 text-center"> 145 <div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-primary mb-4"> 146 </div> 147 <p className="text-muted-foreground"> 148 Benchmarking mirrors... 149 </p> 150 </div> 151 ) 152 : <BenchmarkTable results={results} />} 153 </div> 154 )} 155 156 {/* Info Section */} 157 {results.length === 0 && !loading && ( 158 <div className="bg-muted/30 border border-border rounded-lg p-6"> 159 <h3 className="font-semibold mb-2">How to use:</h3> 160 <ol className="list-decimal list-inside space-y-1 text-sm text-muted-foreground"> 161 <li> 162 Enter an ATProto DID or handle (e.g., 163 did:plc:z72i7hdynmk6r22z27h6tvur or handle.bsky.social) 164 </li> 165 <li>Click "Run Benchmark" or press Enter</li> 166 <li>View response times and status for each mirror</li> 167 </ol> 168 <div className="mt-4 pt-4 border-t border-border"> 169 <p className="text-sm text-muted-foreground"> 170 Mirrors can be configured in{" "} 171 <code className="bg-background px-2 py-1 rounded text-mono"> 172 src/config/mirrors.ts 173 </code> 174 </p> 175 </div> 176 </div> 177 )} 178 </div> 179 </div> 180 ); 181}; 182 183export default Index;