From cdd414b8a0000457f03531b0963a419e3d661d5a Mon Sep 17 00:00:00 2001 From: Blackwhitebear8 Date: Thu, 14 Aug 2025 12:54:25 +0200 Subject: [PATCH] Update static/js/looking_glass.js --- static/js/looking_glass.js | 164 +++++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 69 deletions(-) diff --git a/static/js/looking_glass.js b/static/js/looking_glass.js index 9a27600..acdef14 100644 --- a/static/js/looking_glass.js +++ b/static/js/looking_glass.js @@ -7,10 +7,8 @@ document.addEventListener('DOMContentLoaded', function() { const outputConsole = document.getElementById('output-console'); const visualizerContainer = document.getElementById('visualizer-container'); const networkContainer = document.getElementById('mynetwork'); - const alertModal = new bootstrap.Modal(document.getElementById('alertModal')); - const alertModalBody = document.getElementById('alertModalBody'); + const formError = document.getElementById('form-error'); const mainLocationSelector = document.getElementById('main-location-selector'); - const locationsDropdownMenu = document.getElementById('locations-dropdown-menu'); const locationNameDisplay = document.getElementById('location-name-display'); const facilityNameDisplay = document.getElementById('facility-name-display'); const mapLinkBtn = document.getElementById('map-link-btn'); @@ -55,46 +53,82 @@ document.addEventListener('DOMContentLoaded', function() { const target = document.getElementById('target').value.trim(); const method = methodSelect.value; - if (!target) { - showModalAlert('Please enter a target.'); - return; - } - - let isValid = false; - if (method === 'visualize') { - isValid = isValidIpOrCidr(target); - if (!isValid) { - showModalAlert('Invalid input for Visualizer. Please provide a valid IPv4/IPv6 address or CIDR prefix.'); - return; - } - } else { - const isSingleIp = isValidIPv4(target) || isValidIPv6(target); - const isHostname = isValidFqdn(target); - isValid = isSingleIp || isHostname; - - if (!isValid) { - showModalAlert('Invalid input. For this method, please provide a valid IP address (without a prefix) or a fully qualified domain name.'); - return; - } + formError.textContent = ''; + outputConsole.innerHTML = 'Output will appear here...'; + visualizerContainer.style.display = 'none'; + if (network) { + network.destroy(); + networkContainer.innerHTML = ''; } setLoadingState(true); if (method === 'visualize') { handleVisualize(target); + } else if (method === 'bgp_raw') { + handleRawBgpLookup(target); } else { handleCommand(method, target); } }); mainLocationSelector.addEventListener('change', updateLocationInfo); - locationsDropdownMenu.addEventListener('click', function(e) { - if (e.target.matches('a.dropdown-item')) { - e.preventDefault(); - mainLocationSelector.value = e.target.dataset.location; - mainLocationSelector.dispatchEvent(new Event('change')); + + function highlightBGPOutput(text) { + if (!text) return ''; + + text = text.replace(/&/g, "&").replace(//g, ">"); + + text = text.replace(/\b215085\b/g, '215085'); + + text = text.replace(/\b\d{4,6}\b/g, match => { + if (match === '215085') return `215085`; + return `${match}`; + }); + + text = text.split('\n').map(line => { + const lowerLine = line.toLowerCase(); + if (lowerLine.includes('best') || lowerLine.includes('table entry') || lowerLine.includes('multipath')) { + return `${line}`; + } + return line; + }).join('\n'); + + return text.replace(/\n/g, '
'); + } + + async function handleRawBgpLookup(target) { + visualizerContainer.style.display = 'none'; + outputConsole.style.display = 'block'; + outputConsole.innerHTML = `Looking up BGP route for ${target}...\n\nThis may take a few moments. Please wait.`; + + try { + const response = await fetch('/api/bgp_raw_lookup', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ target }) + }); + + const contentType = response.headers.get("content-type"); + + if (contentType && contentType.indexOf("application/json") !== -1) { + const data = await response.json(); + if (data.error) { + formError.textContent = data.error; + outputConsole.innerHTML = ''; + } + } else if (response.ok && contentType && contentType.indexOf("text/plain") !== -1) { + const rawText = await response.text(); + outputConsole.innerHTML = highlightBGPOutput(rawText); + } else { + throw new Error('Received an unexpected response from the server.'); + } + } catch (error) { + formError.textContent = error.message; + } finally { + setLoadingState(false); } - }); + } async function handleCommand(method, target) { visualizerContainer.style.display = 'none'; @@ -107,26 +141,32 @@ document.addEventListener('DOMContentLoaded', function() { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ method, target }) }); + + const contentType = response.headers.get("content-type"); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(errorText); - } - - const reader = response.body.getReader(); - const decoder = new TextDecoder(); - - outputConsole.textContent = ''; - - while (true) { - const { value, done } = await reader.read(); - if (done) break; - outputConsole.textContent += decoder.decode(value, { stream: true }); - outputConsole.scrollTop = outputConsole.scrollHeight; + if (contentType && contentType.indexOf("application/json") !== -1) { + const data = await response.json(); + if (data.error) { + formError.textContent = data.error; + outputConsole.textContent = ''; + } + } else if (response.ok && contentType && contentType.indexOf("text/plain") !== -1) { + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + outputConsole.textContent = ''; + + while (true) { + const { value, done } = await reader.read(); + if (done) break; + outputConsole.textContent += decoder.decode(value, { stream: true }); + outputConsole.scrollTop = outputConsole.scrollHeight; + } + } else { + throw new Error('Received an unexpected response from the server.'); } } catch (error) { - outputConsole.textContent = `--- ERROR ---\n${error.message}`; + formError.textContent = error.message; } finally { setLoadingState(false); } @@ -148,20 +188,22 @@ document.addEventListener('DOMContentLoaded', function() { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ip_address: target }) }) - .then(response => response.json().then(data => ({ ok: response.ok, data }))) - .then(({ ok, data }) => { - if (!ok || data.error) { - throw new Error(data.error || 'Failed to retrieve visualization data.'); + .then(response => response.json()) + .then(data => { + if (data.error) { + formError.textContent = data.error; + visualizerContainer.style.display = 'none'; + return; } if (data.not_found) { + formError.textContent = `Route information not found for: ${data.target}`; visualizerContainer.style.display = 'none'; - showModalAlert(`Route information not found for: ${data.target}`); return; } const pathCount = data.path_count || 0; - const dynamicHeight = Math.max(400, 200 + (pathCount * 150)); + const dynamicHeight = Math.max(600, 200 + (pathCount * 150)); networkContainer.style.height = `${dynamicHeight}px`; network = new vis.Network(networkContainer, data, { @@ -180,37 +222,21 @@ document.addEventListener('DOMContentLoaded', function() { }) .catch(error => { visualizerContainer.style.display = 'none'; - outputConsole.style.display = 'block'; - outputConsole.textContent = `Visualization Error: ${error.message}`; + formError.textContent = `An unexpected error occurred: ${error.message}`; }) .finally(() => { loader.style.display = 'none'; setLoadingState(false); }); } - - function showModalAlert(message) { - alertModalBody.textContent = message; - alertModal.show(); - } function populateLocationSelectors() { mainLocationSelector.innerHTML = ''; - locationsDropdownMenu.innerHTML = ''; for (const locationName in allLocationsData) { const option = document.createElement('option'); option.value = locationName; option.textContent = locationName; mainLocationSelector.appendChild(option); - - const li = document.createElement('li'); - const a = document.createElement('a'); - a.className = 'dropdown-item'; - a.href = '#'; - a.textContent = locationName; - a.dataset.location = locationName; - li.appendChild(a); - locationsDropdownMenu.appendChild(li); } }