background.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // Fixed URI for WebSocket server
  2. const WS_URL = 'ws://localhost:6768/ws';
  3. const TEN_SECONDS_MS = 10000;
  4. let webSocket = null;
  5. // Setup side panel behavior
  6. chrome.sidePanel
  7. .setPanelBehavior({ openPanelOnActionClick: true })
  8. .catch((error) => console.error(error));
  9. // WebSocket connection management
  10. function connectWebSocket() {
  11. webSocket = new WebSocket(WS_URL);
  12. webSocket.onopen = () => {
  13. console.log('WebSocket connected');
  14. broadcastConnectionStatus(true);
  15. keepAlive();
  16. };
  17. webSocket.onclose = () => {
  18. console.log('WebSocket disconnected');
  19. broadcastConnectionStatus(false);
  20. // Attempt to reconnect after 5 seconds
  21. setTimeout(connectWebSocket, 5000);
  22. };
  23. webSocket.onmessage = (event) => {
  24. try {
  25. const message = JSON.parse(event.data);
  26. const kind = message.kind;
  27. if (kind === 'state') {
  28. // Broadcast task progress to sidebar
  29. broadcastToSidebar({
  30. type: 'state',
  31. data: message.data
  32. });
  33. } else if (kind === 'ack') {
  34. // console.log('ACK:', message);
  35. }
  36. } catch (error) {
  37. console.error('Failed to parse WebSocket message:', error);
  38. }
  39. };
  40. }
  41. function keepAlive() {
  42. const keepAliveIntervalId = setInterval(
  43. () => {
  44. if (webSocket && webSocket.readyState === WebSocket.OPEN) {
  45. console.log('sending heartbeat');
  46. const heartbeatMessage = {
  47. kind: "hb",
  48. data: {
  49. timestamp: Math.floor(new Date().getTime() / 1000)
  50. }
  51. };
  52. webSocket.send(JSON.stringify(heartbeatMessage));
  53. } else {
  54. clearInterval(keepAliveIntervalId);
  55. }
  56. },
  57. TEN_SECONDS_MS
  58. );
  59. }
  60. // Broadcast helpers
  61. function broadcastConnectionStatus(isConnected) {
  62. broadcastToSidebar({
  63. type: 'connection_status',
  64. data: { isConnected }
  65. });
  66. }
  67. function broadcastToSidebar(message) {
  68. chrome.runtime.sendMessage(message).catch(err => {
  69. console.log('Failed to send message to sidebar:', err);
  70. });
  71. }
  72. function generateTaskId() {
  73. const timestamp = Date.now();
  74. const random = Math.floor(Math.random() * 900000) + 100000; // 6-digit random number
  75. return `${timestamp}-${random}`;
  76. }
  77. // Message handling from sidebar
  78. chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  79. if (message.type === 'SEND_MESSAGE' && webSocket) {
  80. const taskId = generateTaskId();
  81. const taskMessage = {
  82. kind: "create",
  83. data: {
  84. task_id: taskId,
  85. intent: message.text,
  86. args: { tab_id: message.tabId }
  87. }
  88. };
  89. webSocket.send(JSON.stringify(taskMessage));
  90. sendResponse({ success: true, taskId: taskId }); // Send back the taskId
  91. } else if (message.type === 'CANCEL_TASK' && webSocket) {
  92. if (message.taskId) {
  93. console.log('Cancelling task:', message.taskId);
  94. const cancelMessage = {
  95. kind: "cancel",
  96. data: {
  97. task_id: message.taskId
  98. }
  99. };
  100. webSocket.send(JSON.stringify(cancelMessage));
  101. sendResponse({ success: true });
  102. } else {
  103. console.warn('Attempted to cancel task without taskId');
  104. sendResponse({ success: false });
  105. }
  106. }
  107. return true;
  108. });
  109. // Initialize WebSocket connection
  110. connectWebSocket();
  111. chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
  112. if (changeInfo.status === 'complete' && tab.url?.startsWith('http')) {
  113. chrome.scripting.executeScript({
  114. target: { tabId: tabId },
  115. files: ['content.js']
  116. }).catch(err => console.error('Failed to inject content script:', err));
  117. }
  118. });
  119. chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  120. if (message.type === 'GET_TAB_ID') {
  121. if (sender.tab && sender.tab.id !== undefined) {
  122. sendResponse({ tabId: sender.tab.id });
  123. } else {
  124. sendResponse({ tabId: null });
  125. }
  126. }
  127. });