Files

370 lines
12 KiB
TypeScript

// Native messaging removed - using remote server only
// import { initNativeHostListener } from './native-host';
// Temporarily disable semantic similarity to focus on connection issues
// import {
// initSemanticSimilarityListener,
// initializeSemanticEngineIfCached,
// } from './semantic-similarity';
import { initStorageManagerListener } from './storage-manager';
import { cleanupModelCache } from '@/utils/semantic-similarity-engine';
import { RemoteServerClient } from '@/utils/remote-server-client';
import { DEFAULT_CONNECTION_CONFIG } from '@/common/env-config';
import { handleCallTool } from './tools';
// Global remote server client instance
let remoteServerClient: RemoteServerClient | null = null;
/**
* Background script entry point
* Initializes all background services and listeners
*/
export default defineBackground(() => {
// Initialize remote server client first (prioritize over native messaging)
initRemoteServerClient();
// Initialize core services (native messaging removed)
// initNativeHostListener();
// initSemanticSimilarityListener();
initStorageManagerListener();
// Initialize browser event listeners for connection persistence
initBrowserEventListeners();
// Conditionally initialize semantic similarity engine if model cache exists
// initializeSemanticEngineIfCached()
// .then((initialized) => {
// if (initialized) {
// console.log('Background: Semantic similarity engine initialized from cache');
// } else {
// console.log(
// 'Background: Semantic similarity engine initialization skipped (no cache found)',
// );
// }
// })
// .catch((error) => {
// console.warn('Background: Failed to conditionally initialize semantic engine:', error);
// });
// Initial cleanup on startup
cleanupModelCache().catch((error) => {
console.warn('Background: Initial cache cleanup failed:', error);
});
});
/**
* Initialize remote server client (without auto-connecting)
*/
function initRemoteServerClient() {
try {
remoteServerClient = new RemoteServerClient({
serverUrl: DEFAULT_CONNECTION_CONFIG.serverUrl,
reconnectInterval: DEFAULT_CONNECTION_CONFIG.reconnectInterval,
maxReconnectAttempts: 50, // Increased for better reliability
});
console.log('Background: Remote server client initialized (not connected)');
console.log('Background: Use popup to manually connect to remote server');
} catch (error) {
console.error('Background: Failed to initialize remote server client:', error);
}
}
/**
* Get the remote server client instance
*/
export function getRemoteServerClient(): RemoteServerClient | null {
return remoteServerClient;
}
/**
* Initialize browser event listeners for connection persistence
*/
function initBrowserEventListeners() {
// Listen for browser startup events
chrome.runtime.onStartup.addListener(() => {
console.log('Background: Browser startup detected. Manual connection required via popup.');
if (remoteServerClient) {
console.log('Background: Remote server client ready for manual connection');
}
});
// Listen for extension installation/update events
chrome.runtime.onInstalled.addListener((details) => {
console.log('Background: Extension installed/updated:', details.reason);
if (details.reason === 'update') {
console.log('Background: Extension updated, manual connection required');
}
});
// Listen for browser suspension/resume events (Chrome specific)
if (chrome.runtime.onSuspend) {
chrome.runtime.onSuspend.addListener(() => {
console.log('Background: Browser suspending, connection state saved');
// Connection state is automatically saved when connected
});
}
if (chrome.runtime.onSuspendCanceled) {
chrome.runtime.onSuspendCanceled.addListener(() => {
console.log('Background: Browser suspend canceled, maintaining connection');
});
}
// Monitor tab events to ensure connection persists across tab operations
chrome.tabs.onActivated.addListener((activeInfo) => {
// Connection should persist regardless of tab switches
if (remoteServerClient && remoteServerClient.isConnected()) {
console.log(`Background: Tab switched to ${activeInfo.tabId}, connection maintained`);
}
});
// Monitor window events
chrome.windows.onFocusChanged.addListener((windowId) => {
// Connection should persist regardless of window focus changes
if (
remoteServerClient &&
remoteServerClient.isConnected() &&
windowId !== chrome.windows.WINDOW_ID_NONE
) {
console.log(`Background: Window focus changed to ${windowId}, connection maintained`);
}
});
console.log('Background: Browser event listeners initialized for connection persistence');
// Start periodic connection health check
startConnectionHealthCheck();
}
/**
* Start periodic connection health check to maintain persistent connections
*/
function startConnectionHealthCheck() {
// Check connection health every 5 minutes (for monitoring only, no auto-reconnection)
setInterval(
() => {
if (remoteServerClient) {
const isConnected = remoteServerClient.isConnected();
console.log(`Background: Connection health check - Connected: ${isConnected}`);
if (!isConnected) {
console.log('Background: Connection lost. Use popup to manually reconnect.');
// No automatic reconnection - user must manually reconnect via popup
}
}
},
5 * 60 * 1000,
); // 5 minutes
console.log(
'Background: Connection health check started (monitoring only, no auto-reconnection)',
);
}
/**
* Handle messages from popup for remote server control
*/
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'getRemoteServerStatus') {
const status = remoteServerClient?.getStatus() || {
connected: false,
connecting: false,
reconnectAttempts: 0,
connectionTime: undefined,
serverUrl: DEFAULT_CONNECTION_CONFIG.serverUrl,
};
sendResponse(status);
return true;
}
if (message.type === 'connectRemoteServer') {
if (!remoteServerClient) {
sendResponse({ success: false, error: 'Remote server client not initialized' });
return true;
}
if (remoteServerClient.isConnected()) {
sendResponse({ success: true, message: 'Already connected' });
return true;
}
console.log('Background: Attempting to connect to remote server...');
remoteServerClient
.connect()
.then(() => {
console.log('Background: Successfully connected to remote server');
sendResponse({ success: true });
})
.catch((error) => {
console.error('Background: Failed to connect to remote server:', error);
sendResponse({ success: false, error: error.message });
});
return true;
}
if (message.type === 'disconnectRemoteServer') {
if (!remoteServerClient) {
sendResponse({ success: false, error: 'Remote server client not initialized' });
return true;
}
console.log('Background: Disconnecting from remote server...');
try {
remoteServerClient.disconnect();
console.log('Background: Successfully disconnected from remote server');
sendResponse({ success: true });
} catch (error) {
console.error('Background: Error during disconnect:', error);
sendResponse({
success: false,
error: error instanceof Error ? error.message : 'Disconnect failed',
});
}
return true;
}
if (message.type === 'restoreRemoteConnection') {
if (!remoteServerClient) {
sendResponse({ success: false, error: 'Remote server client not initialized' });
return true;
}
if (remoteServerClient.isConnected()) {
sendResponse({ success: true, message: 'Already connected' });
return true;
}
console.log('Background: Attempting to restore previous connection...');
remoteServerClient
.restoreConnectionFromState()
.then((restored) => {
if (restored) {
console.log('Background: Successfully restored previous connection');
sendResponse({ success: true });
} else {
console.log('Background: No previous connection to restore');
sendResponse({ success: false, error: 'No previous connection found' });
}
})
.catch((error) => {
console.error('Background: Failed to restore previous connection:', error);
sendResponse({ success: false, error: error.message });
});
return true;
}
if (message.type === 'getCurrentUserId') {
if (!remoteServerClient) {
sendResponse({ success: false, error: 'Remote server client not initialized' });
return true;
}
remoteServerClient
.getCurrentUserId()
.then((userId) => {
sendResponse({ success: true, userId });
})
.catch((error) => {
console.error('Background: Failed to get current user ID:', error);
sendResponse({ success: false, error: error.message });
});
return true;
}
if (message.type === 'callTool') {
handleCallTool({ name: message.toolName, args: message.params })
.then((result) => {
sendResponse(result);
})
.catch((error) => {
sendResponse({ error: error.message });
});
return true;
}
if (message.type === 'injectUserIdHelper') {
injectUserIdHelper(message.tabId)
.then((result) => {
sendResponse(result);
})
.catch((error) => {
sendResponse({ success: false, error: error.message });
});
return true;
}
});
/**
* Inject user ID helper script into a specific tab
*/
async function injectUserIdHelper(tabId?: number): Promise<{ success: boolean; message: string }> {
try {
let targetTabId = tabId;
// If no tab ID provided, use the active tab
if (!targetTabId) {
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tabs[0]?.id) {
throw new Error('No active tab found');
}
targetTabId = tabs[0].id;
}
// Inject the user ID helper script
await chrome.scripting.executeScript({
target: { tabId: targetTabId },
files: ['inject-scripts/user-id-helper.js'],
});
// Get current user ID and inject it
if (remoteServerClient) {
const userId = await remoteServerClient.getCurrentUserId();
if (userId) {
// Inject the user ID into the page
await chrome.scripting.executeScript({
target: { tabId: targetTabId },
func: (userId) => {
// Make user ID available globally
(window as any).chromeExtensionUserId = userId;
// Store in sessionStorage
try {
sessionStorage.setItem('chromeExtensionUserId', userId);
} catch (e) {
// Ignore storage errors
}
// Dispatch event for pages waiting for user ID
window.dispatchEvent(
new CustomEvent('chromeExtensionUserIdReady', {
detail: { userId: userId },
}),
);
console.log('Chrome Extension User ID injected:', userId);
},
args: [userId],
});
return {
success: true,
message: `User ID helper injected into tab ${targetTabId} with user ID: ${userId}`,
};
} else {
return {
success: true,
message: `User ID helper injected into tab ${targetTabId} but no user ID available (not connected)`,
};
}
} else {
return {
success: true,
message: `User ID helper injected into tab ${targetTabId} but remote server client not initialized`,
};
}
} catch (error) {
console.error('Failed to inject user ID helper:', error);
throw error;
}
}