first commit
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { ToolExecutor } from '@/common/tool-handler';
|
||||
import type { ToolResult } from '@/common/tool-handler';
|
||||
import { TIMEOUTS, ERROR_MESSAGES } from '@/common/constants';
|
||||
|
||||
const PING_TIMEOUT_MS = 300;
|
||||
|
||||
/**
|
||||
* Base class for browser tool executors
|
||||
*/
|
||||
export abstract class BaseBrowserToolExecutor implements ToolExecutor {
|
||||
abstract name: string;
|
||||
abstract execute(args: any): Promise<ToolResult>;
|
||||
|
||||
/**
|
||||
* Inject content script into tab
|
||||
*/
|
||||
protected async injectContentScript(
|
||||
tabId: number,
|
||||
files: string[],
|
||||
injectImmediately = false,
|
||||
world: 'MAIN' | 'ISOLATED' = 'ISOLATED',
|
||||
): Promise<void> {
|
||||
console.log(`Injecting ${files.join(', ')} into tab ${tabId}`);
|
||||
|
||||
// check if script is already injected
|
||||
try {
|
||||
const response = await Promise.race([
|
||||
chrome.tabs.sendMessage(tabId, { action: `${this.name}_ping` }),
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(
|
||||
() => reject(new Error(`${this.name} Ping action to tab ${tabId} timed out`)),
|
||||
PING_TIMEOUT_MS,
|
||||
),
|
||||
),
|
||||
]);
|
||||
|
||||
if (response && response.status === 'pong') {
|
||||
console.log(
|
||||
`pong received for action '${this.name}' in tab ${tabId}. Assuming script is active.`,
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
console.warn(`Unexpected ping response in tab ${tabId}:`, response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`ping content script failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
await chrome.scripting.executeScript({
|
||||
target: { tabId },
|
||||
files,
|
||||
injectImmediately,
|
||||
world,
|
||||
});
|
||||
console.log(`'${files.join(', ')}' injection successful for tab ${tabId}`);
|
||||
} catch (injectionError) {
|
||||
const errorMessage =
|
||||
injectionError instanceof Error ? injectionError.message : String(injectionError);
|
||||
console.error(
|
||||
`Content script '${files.join(', ')}' injection failed for tab ${tabId}: ${errorMessage}`,
|
||||
);
|
||||
throw new Error(
|
||||
`${ERROR_MESSAGES.TOOL_EXECUTION_FAILED}: Failed to inject content script in tab ${tabId}: ${errorMessage}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message to tab
|
||||
*/
|
||||
protected async sendMessageToTab(tabId: number, message: any): Promise<any> {
|
||||
try {
|
||||
const response = await chrome.tabs.sendMessage(tabId, message);
|
||||
|
||||
if (response && response.error) {
|
||||
throw new Error(String(response.error));
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
console.error(
|
||||
`Error sending message to tab ${tabId} for action ${message?.action || 'unknown'}: ${errorMessage}`,
|
||||
);
|
||||
|
||||
if (error instanceof Error) {
|
||||
throw error;
|
||||
}
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user