BrowserTools MCP
by oenius
Verified
- browser-tools-mcp
- chrome-extension
// Store settings
let settings = {
logLimit: 50,
queryLimit: 30000,
stringSizeLimit: 500,
showRequestHeaders: false,
showResponseHeaders: false,
maxLogSize: 20000,
screenshotPath: "",
// Add server connection settings
serverHost: "localhost",
serverPort: 3025,
allowAutoPaste: false, // Default auto-paste setting
};
// Track connection status
let serverConnected = false;
let reconnectAttemptTimeout = null;
// Add a flag to track ongoing discovery operations
let isDiscoveryInProgress = false;
// Add an AbortController to cancel fetch operations
let discoveryController = null;
// Load saved settings on startup
chrome.storage.local.get(["browserConnectorSettings"], (result) => {
if (result.browserConnectorSettings) {
settings = { ...settings, ...result.browserConnectorSettings };
updateUIFromSettings();
}
// Create connection status banner at the top
createConnectionBanner();
// Automatically discover server on panel load with quiet mode enabled
discoverServer(true);
});
// Add listener for connection status updates from background script (page refresh events)
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === "CONNECTION_STATUS_UPDATE") {
console.log(
`Received connection status update: ${
message.isConnected ? "Connected" : "Disconnected"
}`
);
// Update UI based on connection status
if (message.isConnected) {
// If already connected, just maintain the current state
if (!serverConnected) {
// Connection was re-established, update UI
serverConnected = true;
updateConnectionBanner(true, {
name: "Browser Tools Server",
version: "reconnected",
host: settings.serverHost,
port: settings.serverPort,
});
}
} else {
// Connection lost, update UI to show disconnected
serverConnected = false;
updateConnectionBanner(false, null);
}
}
if (message.type === "INITIATE_AUTO_DISCOVERY") {
console.log(
`Initiating auto-discovery after page refresh (reason: ${message.reason})`
);
// For page refreshes or if forceRestart is set to true, always cancel any ongoing discovery and restart
if (message.reason === "page_refresh" || message.forceRestart === true) {
// Cancel any ongoing discovery operation
cancelOngoingDiscovery();
// Update UI to indicate we're starting a fresh scan
if (connectionStatusDiv) {
connectionStatusDiv.style.display = "block";
if (statusIcon) statusIcon.className = "status-indicator";
if (statusText)
statusText.textContent =
"Page refreshed. Restarting server discovery...";
}
// Always update the connection banner when a page refresh occurs
updateConnectionBanner(false, null);
// Start a new discovery process with quiet mode
console.log("Starting fresh discovery after page refresh");
discoverServer(true);
}
// For other types of auto-discovery requests, only start if not already in progress
else if (!isDiscoveryInProgress) {
// Use quiet mode for auto-discovery to minimize UI changes
discoverServer(true);
}
}
// Handle successful server validation
if (message.type === "SERVER_VALIDATION_SUCCESS") {
console.log(
`Server validation successful: ${message.serverHost}:${message.serverPort}`
);
// Update the connection status banner
serverConnected = true;
updateConnectionBanner(true, message.serverInfo);
// If we were showing the connection status dialog, we can hide it now
if (connectionStatusDiv && connectionStatusDiv.style.display === "block") {
connectionStatusDiv.style.display = "none";
}
}
// Handle failed server validation
if (message.type === "SERVER_VALIDATION_FAILED") {
console.log(
`Server validation failed: ${message.reason} - ${message.serverHost}:${message.serverPort}`
);
// Update the connection status
serverConnected = false;
updateConnectionBanner(false, null);
// Start auto-discovery if this was a page refresh validation
if (
message.reason === "connection_error" ||
message.reason === "http_error"
) {
// If we're not already trying to discover the server, start the process
if (!isDiscoveryInProgress) {
console.log("Starting auto-discovery after validation failure");
discoverServer(true);
}
}
}
// Handle successful WebSocket connection
if (message.type === "WEBSOCKET_CONNECTED") {
console.log(
`WebSocket connected to ${message.serverHost}:${message.serverPort}`
);
// Update connection status if it wasn't already connected
if (!serverConnected) {
serverConnected = true;
updateConnectionBanner(true, {
name: "Browser Tools Server",
version: "connected via WebSocket",
host: message.serverHost,
port: message.serverPort,
});
}
}
});
// Create connection status banner
function createConnectionBanner() {
// Check if banner already exists
if (document.getElementById("connection-banner")) {
return;
}
// Create the banner
const banner = document.createElement("div");
banner.id = "connection-banner";
banner.style.cssText = `
padding: 6px 0px;
margin-bottom: 4px;
width: 40%;
display: flex;
flex-direction: column;
align-items: flex-start;
background-color:rgba(0,0,0,0);
border-radius: 11px;
font-size: 11px;
font-weight: 500;
color: #ffffff;
`;
// Create reconnect button (now placed at the top)
const reconnectButton = document.createElement("button");
reconnectButton.id = "banner-reconnect-btn";
reconnectButton.textContent = "Reconnect";
reconnectButton.style.cssText = `
background-color: #333333;
color: #ffffff;
border: 1px solid #444444;
border-radius: 3px;
padding: 2px 8px;
font-size: 10px;
cursor: pointer;
margin-bottom: 6px;
align-self: flex-start;
display: none;
transition: background-color 0.2s;
`;
reconnectButton.addEventListener("mouseover", () => {
reconnectButton.style.backgroundColor = "#444444";
});
reconnectButton.addEventListener("mouseout", () => {
reconnectButton.style.backgroundColor = "#333333";
});
reconnectButton.addEventListener("click", () => {
// Hide the button while reconnecting
reconnectButton.style.display = "none";
reconnectButton.textContent = "Reconnecting...";
// Update UI to show searching state
updateConnectionBanner(false, null);
// Try to discover server
discoverServer(false);
});
// Create a container for the status indicator and text
const statusContainer = document.createElement("div");
statusContainer.style.cssText = `
display: flex;
align-items: center;
width: 100%;
`;
// Create status indicator
const indicator = document.createElement("div");
indicator.id = "banner-status-indicator";
indicator.style.cssText = `
width: 6px;
height: 6px;
position: relative;
top: 1px;
border-radius: 50%;
background-color: #ccc;
margin-right: 8px;
flex-shrink: 0;
transition: background-color 0.3s ease;
`;
// Create status text
const statusText = document.createElement("div");
statusText.id = "banner-status-text";
statusText.textContent = "Searching for server...";
statusText.style.cssText =
"flex-grow: 1; font-weight: 400; letter-spacing: 0.1px; font-size: 11px;";
// Add elements to statusContainer
statusContainer.appendChild(indicator);
statusContainer.appendChild(statusText);
// Add elements to banner - reconnect button first, then status container
banner.appendChild(reconnectButton);
banner.appendChild(statusContainer);
// Add banner to the beginning of the document body
// This ensures it's the very first element
document.body.prepend(banner);
// Set initial state
updateConnectionBanner(false, null);
}
// Update the connection banner with current status
function updateConnectionBanner(connected, serverInfo) {
const indicator = document.getElementById("banner-status-indicator");
const statusText = document.getElementById("banner-status-text");
const banner = document.getElementById("connection-banner");
const reconnectButton = document.getElementById("banner-reconnect-btn");
if (!indicator || !statusText || !banner || !reconnectButton) return;
if (connected && serverInfo) {
// Connected state with server info
indicator.style.backgroundColor = "#4CAF50"; // Green indicator
statusText.style.color = "#ffffff"; // White text for contrast on black
statusText.textContent = `Connected to ${serverInfo.name} v${serverInfo.version} at ${settings.serverHost}:${settings.serverPort}`;
// Hide reconnect button when connected
reconnectButton.style.display = "none";
} else if (connected) {
// Connected without server info
indicator.style.backgroundColor = "#4CAF50"; // Green indicator
statusText.style.color = "#ffffff"; // White text for contrast on black
statusText.textContent = `Connected to server at ${settings.serverHost}:${settings.serverPort}`;
// Hide reconnect button when connected
reconnectButton.style.display = "none";
} else {
// Disconnected state
indicator.style.backgroundColor = "#F44336"; // Red indicator
statusText.style.color = "#ffffff"; // White text for contrast on black
// Only show "searching" message if discovery is in progress
if (isDiscoveryInProgress) {
statusText.textContent = "Not connected to server. Searching...";
// Hide reconnect button while actively searching
reconnectButton.style.display = "none";
} else {
statusText.textContent = "Not connected to server.";
// Show reconnect button above status message when disconnected and not searching
reconnectButton.style.display = "block";
reconnectButton.textContent = "Reconnect";
}
}
}
// Initialize UI elements
const logLimitInput = document.getElementById("log-limit");
const queryLimitInput = document.getElementById("query-limit");
const stringSizeLimitInput = document.getElementById("string-size-limit");
const showRequestHeadersCheckbox = document.getElementById(
"show-request-headers"
);
const showResponseHeadersCheckbox = document.getElementById(
"show-response-headers"
);
const maxLogSizeInput = document.getElementById("max-log-size");
const screenshotPathInput = document.getElementById("screenshot-path");
const captureScreenshotButton = document.getElementById("capture-screenshot");
// Server connection UI elements
const serverHostInput = document.getElementById("server-host");
const serverPortInput = document.getElementById("server-port");
const discoverServerButton = document.getElementById("discover-server");
const testConnectionButton = document.getElementById("test-connection");
const connectionStatusDiv = document.getElementById("connection-status");
const statusIcon = document.getElementById("status-icon");
const statusText = document.getElementById("status-text");
// Initialize collapsible advanced settings
const advancedSettingsHeader = document.getElementById(
"advanced-settings-header"
);
const advancedSettingsContent = document.getElementById(
"advanced-settings-content"
);
const chevronIcon = advancedSettingsHeader.querySelector(".chevron");
advancedSettingsHeader.addEventListener("click", () => {
advancedSettingsContent.classList.toggle("visible");
chevronIcon.classList.toggle("open");
});
// Get all inputs by ID
const allowAutoPasteCheckbox = document.getElementById("allow-auto-paste");
// Update UI from settings
function updateUIFromSettings() {
logLimitInput.value = settings.logLimit;
queryLimitInput.value = settings.queryLimit;
stringSizeLimitInput.value = settings.stringSizeLimit;
showRequestHeadersCheckbox.checked = settings.showRequestHeaders;
showResponseHeadersCheckbox.checked = settings.showResponseHeaders;
maxLogSizeInput.value = settings.maxLogSize;
screenshotPathInput.value = settings.screenshotPath;
serverHostInput.value = settings.serverHost;
serverPortInput.value = settings.serverPort;
allowAutoPasteCheckbox.checked = settings.allowAutoPaste;
}
// Save settings
function saveSettings() {
chrome.storage.local.set({ browserConnectorSettings: settings });
// Notify devtools.js about settings change
chrome.runtime.sendMessage({
type: "SETTINGS_UPDATED",
settings,
});
}
// Add event listeners for all inputs
logLimitInput.addEventListener("change", (e) => {
settings.logLimit = parseInt(e.target.value, 10);
saveSettings();
});
queryLimitInput.addEventListener("change", (e) => {
settings.queryLimit = parseInt(e.target.value, 10);
saveSettings();
});
stringSizeLimitInput.addEventListener("change", (e) => {
settings.stringSizeLimit = parseInt(e.target.value, 10);
saveSettings();
});
showRequestHeadersCheckbox.addEventListener("change", (e) => {
settings.showRequestHeaders = e.target.checked;
saveSettings();
});
showResponseHeadersCheckbox.addEventListener("change", (e) => {
settings.showResponseHeaders = e.target.checked;
saveSettings();
});
maxLogSizeInput.addEventListener("change", (e) => {
settings.maxLogSize = parseInt(e.target.value, 10);
saveSettings();
});
screenshotPathInput.addEventListener("change", (e) => {
settings.screenshotPath = e.target.value;
saveSettings();
});
// Add event listeners for server settings
serverHostInput.addEventListener("change", (e) => {
settings.serverHost = e.target.value;
saveSettings();
// Automatically test connection when host is changed
testConnection(settings.serverHost, settings.serverPort);
});
serverPortInput.addEventListener("change", (e) => {
settings.serverPort = parseInt(e.target.value, 10);
saveSettings();
// Automatically test connection when port is changed
testConnection(settings.serverHost, settings.serverPort);
});
// Add event listener for auto-paste checkbox
allowAutoPasteCheckbox.addEventListener("change", (e) => {
settings.allowAutoPaste = e.target.checked;
saveSettings();
});
// Function to cancel any ongoing discovery operations
function cancelOngoingDiscovery() {
if (isDiscoveryInProgress) {
console.log("Cancelling ongoing discovery operation");
// Abort any fetch requests in progress
if (discoveryController) {
try {
discoveryController.abort();
} catch (error) {
console.error("Error aborting discovery controller:", error);
}
discoveryController = null;
}
// Reset the discovery status
isDiscoveryInProgress = false;
// Update UI to indicate the operation was cancelled
if (
statusText &&
connectionStatusDiv &&
connectionStatusDiv.style.display === "block"
) {
statusText.textContent = "Server discovery operation cancelled";
}
// Clear any pending network timeouts that might be part of the discovery process
clearTimeout(reconnectAttemptTimeout);
reconnectAttemptTimeout = null;
console.log("Discovery operation cancelled successfully");
}
}
// Test server connection
testConnectionButton.addEventListener("click", async () => {
// Cancel any ongoing discovery operations before testing
cancelOngoingDiscovery();
await testConnection(settings.serverHost, settings.serverPort);
});
// Function to test server connection
async function testConnection(host, port) {
// Cancel any ongoing discovery operations
cancelOngoingDiscovery();
connectionStatusDiv.style.display = "block";
statusIcon.className = "status-indicator";
statusText.textContent = "Testing connection...";
try {
// Use the identity endpoint instead of .port for more reliable validation
const response = await fetch(`http://${host}:${port}/.identity`, {
signal: AbortSignal.timeout(5000), // 5 second timeout
});
if (response.ok) {
const identity = await response.json();
// Verify this is actually our server by checking the signature
if (identity.signature !== "mcp-browser-connector-24x7") {
statusIcon.className = "status-indicator status-disconnected";
statusText.textContent = `Connection failed: Found a server at ${host}:${port} but it's not the Browser Tools server`;
serverConnected = false;
updateConnectionBanner(false, null);
scheduleReconnectAttempt();
return false;
}
statusIcon.className = "status-indicator status-connected";
statusText.textContent = `Connected successfully to ${identity.name} v${identity.version} at ${host}:${port}`;
serverConnected = true;
updateConnectionBanner(true, identity);
// Clear any scheduled reconnect attempts
if (reconnectAttemptTimeout) {
clearTimeout(reconnectAttemptTimeout);
reconnectAttemptTimeout = null;
}
// Update settings if different port was discovered
if (parseInt(identity.port, 10) !== port) {
console.log(`Detected different port: ${identity.port}`);
settings.serverPort = parseInt(identity.port, 10);
serverPortInput.value = settings.serverPort;
saveSettings();
}
return true;
} else {
statusIcon.className = "status-indicator status-disconnected";
statusText.textContent = `Connection failed: Server returned ${response.status}`;
serverConnected = false;
// Make sure isDiscoveryInProgress is false so the reconnect button will show
isDiscoveryInProgress = false;
// Now update the connection banner to show the reconnect button
updateConnectionBanner(false, null);
scheduleReconnectAttempt();
return false;
}
} catch (error) {
statusIcon.className = "status-indicator status-disconnected";
statusText.textContent = `Connection failed: ${error.message}`;
serverConnected = false;
// Make sure isDiscoveryInProgress is false so the reconnect button will show
isDiscoveryInProgress = false;
// Now update the connection banner to show the reconnect button
updateConnectionBanner(false, null);
scheduleReconnectAttempt();
return false;
}
}
// Schedule a reconnect attempt if server isn't found
function scheduleReconnectAttempt() {
// Clear any existing reconnect timeout
if (reconnectAttemptTimeout) {
clearTimeout(reconnectAttemptTimeout);
}
// Schedule a reconnect attempt in 30 seconds
reconnectAttemptTimeout = setTimeout(() => {
console.log("Attempting to reconnect to server...");
// Only show minimal UI during auto-reconnect
discoverServer(true);
}, 30000); // 30 seconds
}
// Helper function to try connecting to a server
async function tryServerConnection(host, port) {
try {
// Check if the discovery process was cancelled
if (!isDiscoveryInProgress) {
return false;
}
// Create a local timeout that won't abort the entire discovery process
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
}, 500); // 500ms timeout for each connection attempt
try {
// Use identity endpoint for validation
const response = await fetch(`http://${host}:${port}/.identity`, {
// Use a local controller for this specific request timeout
// but also respect the global discovery cancellation
signal: discoveryController
? AbortSignal.any([controller.signal, discoveryController.signal])
: controller.signal,
});
clearTimeout(timeoutId);
// Check again if discovery was cancelled during the fetch
if (!isDiscoveryInProgress) {
return false;
}
if (response.ok) {
const identity = await response.json();
// Verify this is actually our server by checking the signature
if (identity.signature !== "mcp-browser-connector-24x7") {
console.log(
`Found a server at ${host}:${port} but it's not the Browser Tools server`
);
return false;
}
console.log(`Successfully found server at ${host}:${port}`);
// Update settings with discovered server
settings.serverHost = host;
settings.serverPort = parseInt(identity.port, 10);
serverHostInput.value = settings.serverHost;
serverPortInput.value = settings.serverPort;
saveSettings();
statusIcon.className = "status-indicator status-connected";
statusText.textContent = `Discovered ${identity.name} v${identity.version} at ${host}:${identity.port}`;
// Update connection banner with server info
updateConnectionBanner(true, identity);
// Update connection status
serverConnected = true;
// Clear any scheduled reconnect attempts
if (reconnectAttemptTimeout) {
clearTimeout(reconnectAttemptTimeout);
reconnectAttemptTimeout = null;
}
// End the discovery process
isDiscoveryInProgress = false;
// Successfully found server
return true;
}
return false;
} finally {
clearTimeout(timeoutId);
}
} catch (error) {
// Ignore connection errors during discovery
// But check if it was an abort (cancellation)
if (error.name === "AbortError") {
// Check if this was due to the global discovery cancellation
if (discoveryController && discoveryController.signal.aborted) {
console.log("Connection attempt aborted by global cancellation");
return "aborted";
}
// Otherwise it was just a timeout for this specific connection attempt
return false;
}
console.log(`Connection error for ${host}:${port}: ${error.message}`);
return false;
}
}
// Server discovery function (extracted to be reusable)
async function discoverServer(quietMode = false) {
// Cancel any ongoing discovery operations before starting a new one
cancelOngoingDiscovery();
// Create a new AbortController for this discovery process
discoveryController = new AbortController();
isDiscoveryInProgress = true;
// In quiet mode, we don't show the connection status until we either succeed or fail completely
if (!quietMode) {
connectionStatusDiv.style.display = "block";
statusIcon.className = "status-indicator";
statusText.textContent = "Discovering server...";
}
// Always update the connection banner
updateConnectionBanner(false, null);
try {
console.log("Starting server discovery process");
// Add an early cancellation listener that will respond to page navigation/refresh
discoveryController.signal.addEventListener("abort", () => {
console.log("Discovery aborted via AbortController signal");
isDiscoveryInProgress = false;
});
// Common IPs to try (in order of likelihood)
const hosts = ["localhost", "127.0.0.1"];
// Add the current configured host if it's not already in the list
if (
!hosts.includes(settings.serverHost) &&
settings.serverHost !== "0.0.0.0"
) {
hosts.unshift(settings.serverHost); // Put at the beginning for priority
}
// Add common local network IPs
const commonLocalIps = ["192.168.0.", "192.168.1.", "10.0.0.", "10.0.1."];
for (const prefix of commonLocalIps) {
for (let i = 1; i <= 5; i++) {
// Reduced from 10 to 5 for efficiency
hosts.push(`${prefix}${i}`);
}
}
// Build port list in a smart order:
// 1. Start with current configured port
// 2. Add default port (3025)
// 3. Add sequential ports around the default (for fallback detection)
const ports = [];
// Current configured port gets highest priority
const configuredPort = parseInt(settings.serverPort, 10);
ports.push(configuredPort);
// Add default port if it's not the same as configured
if (configuredPort !== 3025) {
ports.push(3025);
}
// Add sequential fallback ports (from default up to default+10)
for (let p = 3026; p <= 3035; p++) {
if (p !== configuredPort) {
// Avoid duplicates
ports.push(p);
}
}
// Remove duplicates
const uniquePorts = [...new Set(ports)];
console.log("Will check ports:", uniquePorts);
// Create a progress indicator
let progress = 0;
let totalChecked = 0;
// Phase 1: Try the most likely combinations first (current host:port and localhost variants)
console.log("Starting Phase 1: Quick check of high-priority hosts/ports");
const priorityHosts = hosts.slice(0, 2); // First two hosts are highest priority
for (const host of priorityHosts) {
// Check if discovery was cancelled
if (!isDiscoveryInProgress) {
console.log("Discovery process was cancelled during Phase 1");
return false;
}
// Try configured port first
totalChecked++;
if (!quietMode) {
statusText.textContent = `Checking ${host}:${uniquePorts[0]}...`;
}
console.log(`Checking ${host}:${uniquePorts[0]}...`);
const result = await tryServerConnection(host, uniquePorts[0]);
// Check for cancellation or success
if (result === "aborted" || !isDiscoveryInProgress) {
console.log("Discovery process was cancelled");
return false;
} else if (result === true) {
console.log("Server found in priority check");
if (quietMode) {
// In quiet mode, only show the connection banner but hide the status box
connectionStatusDiv.style.display = "none";
}
return true; // Successfully found server
}
// Then try default port if different
if (uniquePorts.length > 1) {
// Check if discovery was cancelled
if (!isDiscoveryInProgress) {
console.log("Discovery process was cancelled");
return false;
}
totalChecked++;
if (!quietMode) {
statusText.textContent = `Checking ${host}:${uniquePorts[1]}...`;
}
console.log(`Checking ${host}:${uniquePorts[1]}...`);
const result = await tryServerConnection(host, uniquePorts[1]);
// Check for cancellation or success
if (result === "aborted" || !isDiscoveryInProgress) {
console.log("Discovery process was cancelled");
return false;
} else if (result === true) {
console.log("Server found in priority check");
if (quietMode) {
// In quiet mode, only show the connection banner but hide the status box
connectionStatusDiv.style.display = "none";
}
return true; // Successfully found server
}
}
}
// If we're in quiet mode and the quick checks failed, show the status now
// as we move into more intensive scanning
if (quietMode) {
connectionStatusDiv.style.display = "block";
statusIcon.className = "status-indicator";
statusText.textContent = "Searching for server...";
}
// Phase 2: Systematic scan of all combinations
const totalAttempts = hosts.length * uniquePorts.length;
console.log(
`Starting Phase 2: Full scan (${totalAttempts} total combinations)`
);
statusText.textContent = `Quick check failed. Starting full scan (${totalChecked}/${totalAttempts})...`;
// First, scan through all ports on localhost/127.0.0.1 to find fallback ports quickly
const localHosts = ["localhost", "127.0.0.1"];
for (const host of localHosts) {
// Skip the first two ports on localhost if we already checked them in Phase 1
const portsToCheck = uniquePorts.slice(
localHosts.includes(host) && priorityHosts.includes(host) ? 2 : 0
);
for (const port of portsToCheck) {
// Check if discovery was cancelled
if (!isDiscoveryInProgress) {
console.log("Discovery process was cancelled during local port scan");
return false;
}
// Update progress
progress++;
totalChecked++;
statusText.textContent = `Scanning local ports... (${totalChecked}/${totalAttempts}) - Trying ${host}:${port}`;
console.log(`Checking ${host}:${port}...`);
const result = await tryServerConnection(host, port);
// Check for cancellation or success
if (result === "aborted" || !isDiscoveryInProgress) {
console.log("Discovery process was cancelled");
return false;
} else if (result === true) {
console.log(`Server found at ${host}:${port}`);
return true; // Successfully found server
}
}
}
// Then scan all the remaining host/port combinations
for (const host of hosts) {
// Skip hosts we already checked
if (localHosts.includes(host)) {
continue;
}
for (const port of uniquePorts) {
// Check if discovery was cancelled
if (!isDiscoveryInProgress) {
console.log("Discovery process was cancelled during remote scan");
return false;
}
// Update progress
progress++;
totalChecked++;
statusText.textContent = `Scanning remote hosts... (${totalChecked}/${totalAttempts}) - Trying ${host}:${port}`;
console.log(`Checking ${host}:${port}...`);
const result = await tryServerConnection(host, port);
// Check for cancellation or success
if (result === "aborted" || !isDiscoveryInProgress) {
console.log("Discovery process was cancelled");
return false;
} else if (result === true) {
console.log(`Server found at ${host}:${port}`);
return true; // Successfully found server
}
}
}
console.log(
`Discovery process completed, checked ${totalChecked} combinations, no server found`
);
// If we get here, no server was found
statusIcon.className = "status-indicator status-disconnected";
statusText.textContent =
"No server found. Please check server is running and try again.";
serverConnected = false;
// End the discovery process first before updating the banner
isDiscoveryInProgress = false;
// Update the connection banner to show the reconnect button
updateConnectionBanner(false, null);
// Schedule a reconnect attempt
scheduleReconnectAttempt();
return false;
} catch (error) {
console.error("Error during server discovery:", error);
statusIcon.className = "status-indicator status-disconnected";
statusText.textContent = `Error discovering server: ${error.message}`;
serverConnected = false;
// End the discovery process first before updating the banner
isDiscoveryInProgress = false;
// Update the connection banner to show the reconnect button
updateConnectionBanner(false, null);
// Schedule a reconnect attempt
scheduleReconnectAttempt();
return false;
} finally {
console.log("Discovery process finished");
// Always clean up, even if there was an error
if (discoveryController) {
discoveryController = null;
}
}
}
// Bind discover server button to the extracted function
discoverServerButton.addEventListener("click", () => discoverServer(false));
// Screenshot capture functionality
captureScreenshotButton.addEventListener("click", () => {
captureScreenshotButton.textContent = "Capturing...";
// Send message to background script to capture screenshot
chrome.runtime.sendMessage(
{
type: "CAPTURE_SCREENSHOT",
tabId: chrome.devtools.inspectedWindow.tabId,
screenshotPath: settings.screenshotPath,
},
(response) => {
console.log("Screenshot capture response:", response);
if (!response) {
captureScreenshotButton.textContent = "Failed to capture!";
console.error("Screenshot capture failed: No response received");
} else if (!response.success) {
captureScreenshotButton.textContent = "Failed to capture!";
console.error("Screenshot capture failed:", response.error);
} else {
captureScreenshotButton.textContent = `Captured: ${response.title}`;
console.log("Screenshot captured successfully:", response.path);
}
setTimeout(() => {
captureScreenshotButton.textContent = "Capture Screenshot";
}, 2000);
}
);
});
// Add wipe logs functionality
const wipeLogsButton = document.getElementById("wipe-logs");
wipeLogsButton.addEventListener("click", () => {
const serverUrl = `http://${settings.serverHost}:${settings.serverPort}/wipelogs`;
console.log(`Sending wipe request to ${serverUrl}`);
fetch(serverUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
})
.then((response) => response.json())
.then((result) => {
console.log("Logs wiped successfully:", result.message);
wipeLogsButton.textContent = "Logs Wiped!";
setTimeout(() => {
wipeLogsButton.textContent = "Wipe All Logs";
}, 2000);
})
.catch((error) => {
console.error("Failed to wipe logs:", error);
wipeLogsButton.textContent = "Failed to Wipe Logs";
setTimeout(() => {
wipeLogsButton.textContent = "Wipe All Logs";
}, 2000);
});
});