370 lines
12 KiB
TypeScript
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;
|
|
}
|
|
}
|