"use client" import { useState, useEffect } from "react" import { ComposableMap, Geographies, Geography, Marker } from "react-simple-maps" export interface TunnelConfig { type: "http" | "tcp" serverPort: number localPort: number } interface Server { id: string name: string location: string subdomain: string coordinates: [number, number] ping: number | null status: "online" | "offline" | "maintenance" pingStatus: "idle" | "testing" | "success" | "failed" | "timeout" capabilities: { http: boolean tcp: boolean } } const geoUrl = "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json" interface TunnelConfigProps { config: TunnelConfig onConfigChange: (config: TunnelConfig) => void selectedServer: Server | null onServerSelect: (server: Server) => void } const fetchServers = async (): Promise => { await new Promise((resolve) => setTimeout(resolve, 2000)) const mockServers: Server[] = [ { id: "us", name: "United States", location: "Chicago", subdomain: "us.tunnl.live", coordinates: [-87.6298, 41.8781], ping: null, status: "online", pingStatus: "idle", capabilities: { http: true, tcp: false, }, }, { id: "eu", name: "Europe", location: "Frankfurt", subdomain: "eu.tunnl.live", coordinates: [8.6821, 50.1109], ping: null, status: "online", pingStatus: "idle", capabilities: { http: true, tcp: false, }, }, { id: "sgp", name: "Singapore", location: "Singapore", subdomain: "sgp.tunnl.live", coordinates: [103.8198, 1.3521], ping: null, status: "online", pingStatus: "idle", capabilities: { http: true, tcp: true, }, }, { id: "id", name: "Indonesia", location: "Bogor", subdomain: "id.tunnl.live", coordinates: [106.8456, -6.5950], ping: null, status: "online", pingStatus: "idle", capabilities: { http: true, tcp: true, }, }, ] return mockServers.filter((server) => server.status === "online") } const testServerPing = ( server: Server, ): Promise<{ server: Server; ping: number | null; status: Server["pingStatus"] }> => { return new Promise((resolve) => { const startTime = Date.now() const timeout = 5000 let resolved = false const pingUrl = `wss://ping.${server.subdomain}` try { const ws = new WebSocket(pingUrl) const timeoutId = setTimeout(() => { if (!resolved) { resolved = true ws.close() resolve({ server, ping: null, status: "timeout", }) } }, timeout) ws.onopen = () => { console.log(`Connected to ${pingUrl}`) } ws.onmessage = (event) => { if (event.data === "pong" && !resolved) { resolved = true const ping = Date.now() - startTime clearTimeout(timeoutId) ws.close() resolve({ server, ping, status: "success", }) } } ws.onclose = (event) => { if (!resolved) { resolved = true clearTimeout(timeoutId) resolve({ server, ping: null, status: "failed", }) } } ws.onerror = (error) => { if (!resolved) { resolved = true clearTimeout(timeoutId) console.error(`WebSocket error for ${pingUrl}:`, error) resolve({ server, ping: null, status: "failed", }) } } } catch (error) { console.error(`Failed to create WebSocket for ${pingUrl}:`, error) resolve({ server, ping: null, status: "failed", }) } }) } export default function TunnelConfig({ config, onConfigChange, selectedServer, onServerSelect }: TunnelConfigProps) { const [localConfig, setLocalConfig] = useState(config) const [servers, setServers] = useState([]) const [isLoadingServers, setIsLoadingServers] = useState(true) const [isTestingPings, setIsTestingPings] = useState(false) const [hasAutoTested, setHasAutoTested] = useState(false) const [copied, setCopied] = useState(false) const [serverError, setServerError] = useState(null) useEffect(() => { const loadServers = async () => { try { setIsLoadingServers(true) setServerError(null) const serverData = await fetchServers() setServers(serverData) if (serverData.length === 0) { setServerError("No servers are currently available. Please try again later.") } } catch (error) { setServerError("Failed to load servers. Please check your connection and try again.") } finally { setIsLoadingServers(false) } } loadServers() }, []) useEffect(() => { if (servers.length > 0 && !isLoadingServers && !hasAutoTested) { const autoTestPings = async () => { setIsTestingPings(true) setHasAutoTested(true) setServers((prevServers) => prevServers.map((server) => ({ ...server, pingStatus: "testing" as const, })), ) try { const pingPromises = servers.map((server) => testServerPing(server)) const results = await Promise.all(pingPromises) const updatedServers = results.map((result) => ({ ...result.server, ping: result.ping, pingStatus: result.status, })) setServers(updatedServers) const compatibleServers = updatedServers.filter( (s) => s.pingStatus === "success" && s.ping !== null && ((localConfig.type === "http" && s.capabilities.http) || (localConfig.type === "tcp" && s.capabilities.tcp)), ) if (compatibleServers.length > 0) { const bestServer = compatibleServers.reduce((prev, current) => prev.ping! < current.ping! ? prev : current, ) onServerSelect(bestServer) } else { const successfulServers = updatedServers.filter((s) => s.pingStatus === "success" && s.ping !== null) if (successfulServers.length > 0) { const bestServer = successfulServers.reduce((prev, current) => prev.ping! < current.ping! ? prev : current, ) onServerSelect(bestServer) if (localConfig.type === "tcp" && !bestServer.capabilities.tcp) { updateConfig({ type: "http", serverPort: 443 }) } } else if (updatedServers.length > 0) { onServerSelect(updatedServers[0]) } } } catch (error) { console.error("Error testing pings:", error) } finally { setIsTestingPings(false) } } autoTestPings() } }, [servers.length, isLoadingServers, hasAutoTested, onServerSelect, localConfig.type]) useEffect(() => { if (selectedServer && localConfig.type === "tcp" && !selectedServer.capabilities.tcp) { updateConfig({ type: "http", serverPort: 443 }) } }, [selectedServer, localConfig.type]) const updateConfig = (updates: Partial) => { const newConfig = { ...localConfig, ...updates } if (updates.serverPort && (updates.serverPort === 80 || updates.serverPort === 443)) { newConfig.type = "http" } setLocalConfig(newConfig) onConfigChange(newConfig) } const generateCommand = () => { if (!selectedServer) return "" const { serverPort, localPort } = localConfig return `ssh ${selectedServer.subdomain} -p 2200 -R ${serverPort}:localhost:${localPort}` } const copyToClipboard = () => { const command = generateCommand() if (command) { navigator.clipboard.writeText(command) setCopied(true) setTimeout(() => setCopied(false), 2000) } } const getPingColor = (server: Server) => { if (server.pingStatus === "testing") return "text-gray-400" if (server.pingStatus === "failed" || server.pingStatus === "timeout") return "text-red-400" if (server.pingStatus === "idle" || !server.ping) return "text-gray-400" if (server.ping < 50) return "text-green-400" if (server.ping < 100) return "text-yellow-400" if (server.ping < 150) return "text-orange-400" return "text-red-400" } const getPingDisplay = (server: Server) => { if (server.pingStatus === "testing") return "Testing..." if (server.pingStatus === "timeout") return "Timeout" if (server.pingStatus === "failed") return "Failed" if (server.pingStatus === "idle") return "Click to test" if (server.ping === null) return "N/A" return `${server.ping}ms` } const getPingStatus = (server: Server) => { if (server.pingStatus === "testing") return "Testing..." if (server.pingStatus === "timeout") return "Timeout (5s)" if (server.pingStatus === "failed") return "Connection Failed" if (server.pingStatus === "idle") return "Not tested" if (!server.ping) return "Unknown" if (server.ping < 50) return "Excellent" if (server.ping < 100) return "Good" if (server.ping < 150) return "Fair" return "Poor" } const getMarkerColor = (server: Server) => { if (selectedServer?.id === server.id) return "#10b981" if (server.pingStatus === "failed" || server.pingStatus === "timeout") return "#ef4444" if (server.pingStatus === "success" && server.ping !== null) { if (server.ping < 50) return "#10b981" if (server.ping < 100) return "#eab308" if (server.ping < 150) return "#f97316" return "#ef4444" } return "#6b7280" } const getMarkerStroke = (server: Server) => { if (selectedServer?.id === server.id) return "#34d399" if (server.pingStatus === "failed" || server.pingStatus === "timeout") return "#f87171" if (server.pingStatus === "success" && server.ping !== null) { if (server.ping < 50) return "#34d399" if (server.ping < 100) return "#facc15" if (server.ping < 150) return "#fb923c" return "#f87171" } return "#9ca3af" } const testPingForServer = async (server: Server) => { setServers((prevServers) => prevServers.map((s) => (s.id === server.id ? { ...s, pingStatus: "testing", ping: null } : s)), ) try { const timeoutPromise = new Promise<{ server: Server; ping: number | null; status: Server["pingStatus"] }>( (_, reject) => { setTimeout(() => reject(new Error("Timeout")), 5000) }, ) const result = await Promise.race([testServerPing(server), timeoutPromise]) setServers((prevServers) => prevServers.map((s) => (s.id === server.id ? { ...s, ping: result.ping, pingStatus: result.status } : s)), ) } catch (error) { console.error("Error testing ping:", error) setServers((prevServers) => prevServers.map((s) => (s.id === server.id ? { ...s, ping: null, pingStatus: "timeout" } : s)), ) } } const testAllPings = async () => { if (servers.length === 0 || isTestingPings) return setIsTestingPings(true) setServers((prevServers) => prevServers.map((server) => ({ ...server, ping: null, pingStatus: "testing" as const, })), ) try { const pingPromises = servers.map((server) => testServerPing(server)) const results = await Promise.all(pingPromises) const updatedServers = results.map((result) => ({ ...result.server, ping: result.ping, pingStatus: result.status, })) setServers(updatedServers) } catch (error) { console.error("Error testing pings:", error) } finally { setIsTestingPings(false) } } const canSelectServer = (server: Server) => { if (server.pingStatus === "failed" || server.pingStatus === "timeout") { return false } if (localConfig.type === "http" && !server.capabilities.http) { return false } if (localConfig.type === "tcp" && !server.capabilities.tcp) { return false } return true } const getServerUnavailableReason = (server: Server) => { if (server.pingStatus === "failed" || server.pingStatus === "timeout") { return "Server unavailable" } if (localConfig.type === "tcp" && !server.capabilities.tcp) { return "TCP not supported" } if (localConfig.type === "http" && !server.capabilities.http) { return "HTTP not supported" } return null } const getCompatibleServers = () => { return servers.filter((server) => { if (localConfig.type === "http") return server.capabilities.http if (localConfig.type === "tcp") return server.capabilities.tcp return true }) } const compatibleServers = getCompatibleServers() return (

Tunnel Configuration

Choose Your Server Location

{servers.length > 0 && hasAutoTested && ( )}
{compatibleServers.length === 0 && servers.length > 0 && (

No servers support {localConfig.type.toUpperCase()} forwarding

Please switch to HTTP/HTTPS forwarding or wait for TCP-compatible servers to come online.

)} {isLoadingServers ? (

Loading available servers...

) : serverError ? (

Server Unavailable

{serverError}

) : servers.length === 0 ? (

No Servers Available

All servers are currently offline for maintenance.

) : ( <>
{({ geographies }) => geographies.map((geo) => ( )) } {servers.map((server) => ( { if (canSelectServer(server)) { onServerSelect(server) } }} > {selectedServer?.id === server.id && ( )} {server.location} ))}
{servers.map((server) => { const canSelect = canSelectServer(server) const unavailableReason = getServerUnavailableReason(server) return (
{ if (canSelect) { onServerSelect(server) } }} className={`p-3 rounded-lg border transition-all duration-200 ${selectedServer?.id === server.id ? "bg-emerald-950 border-emerald-500" : !canSelect ? "bg-red-950 border-red-800 cursor-not-allowed opacity-75" : "bg-gray-800 border-gray-700 hover:border-gray-600 cursor-pointer" }`} >
{server.name}

{server.location}

{server.subdomain}

Supports:
{server.capabilities.http && ( HTTP )} {server.capabilities.tcp && ( TCP )}
Ping:
{server.pingStatus === "testing" && (
)} {hasAutoTested ? ( ) : ( {getPingDisplay(server)} )}

{getPingStatus(server)}

{unavailableReason && (

Cannot select - {unavailableReason}

)}
) })}
)}
{servers.length > 0 && ( <>
) } export type { Server }