| 1 |
// Background script for LooseCannon - Fixed Connection Issues |
| 2 |
console.log('[LooseCannon Background] Initialized'); |
| 3 |
|
| 4 |
class LooseCannonBackground { |
| 5 |
constructor() { |
| 6 |
this.serverUrl = 'http://localhost:8765'; // Local server URL |
| 7 |
this.isConnected = false; |
| 8 |
this.activeTabs = new Map(); |
| 9 |
this.personalities = []; |
| 10 |
this.currentPersonality = 'default'; |
| 11 |
this.init(); |
| 12 |
} |
| 13 |
|
| 14 |
init() { |
| 15 |
this.setupMessageListeners(); |
| 16 |
this.checkServerConnection(); |
| 17 |
this.loadSettings(); |
| 18 |
} |
| 19 |
|
| 20 |
setupMessageListeners() { |
| 21 |
browser.runtime.onMessage.addListener((message, sender, sendResponse) => { |
| 22 |
console.log('[LooseCannon Background] Received message:', message.type); |
| 23 |
|
| 24 |
switch (message.type) { |
| 25 |
case 'NEW_MESSAGE': |
| 26 |
this.handleNewMessage(message.data, sender.tab.id) |
| 27 |
.then(sendResponse) |
| 28 |
.catch(error => { |
| 29 |
console.error('Error handling message:', error); |
| 30 |
sendResponse({ error: error.message }); |
| 31 |
}); |
| 32 |
return true; // Keep channel open for async response |
| 33 |
|
| 34 |
case 'TOGGLE_ACTIVE': |
| 35 |
this.handleToggleActive(sender.tab.id, message.data.isActive); |
| 36 |
sendResponse({ success: true }); |
| 37 |
break; |
| 38 |
|
| 39 |
case 'GET_SERVER_STATUS': |
| 40 |
// Check connection immediately when asked |
| 41 |
this.checkServerConnection().then(() => { |
| 42 |
sendResponse({ connected: this.isConnected }); |
| 43 |
}); |
| 44 |
return true; // Keep channel open for async response |
| 45 |
|
| 46 |
case 'GET_PERSONALITIES': |
| 47 |
sendResponse({ personalities: this.personalities }); |
| 48 |
break; |
| 49 |
|
| 50 |
case 'SET_PERSONALITY': |
| 51 |
this.currentPersonality = message.data.personality; |
| 52 |
this.saveSettings(); |
| 53 |
sendResponse({ success: true }); |
| 54 |
break; |
| 55 |
|
| 56 |
default: |
| 57 |
console.warn('Unknown message type:', message.type); |
| 58 |
} |
| 59 |
}); |
| 60 |
} |
| 61 |
|
| 62 |
async handleNewMessage(data, tabId) { |
| 63 |
if (!this.isConnected) { |
| 64 |
console.warn('[LooseCannon] Server not connected, cannot process message'); |
| 65 |
return { error: 'Server not connected' }; |
| 66 |
} |
| 67 |
|
| 68 |
try { |
| 69 |
// Send message to local server for LLM processing |
| 70 |
const response = await fetch(`${this.serverUrl}/generate`, { |
| 71 |
method: 'POST', |
| 72 |
headers: { |
| 73 |
'Content-Type': 'application/json', |
| 74 |
}, |
| 75 |
body: JSON.stringify({ |
| 76 |
message: data.text, |
| 77 |
personality: this.currentPersonality, |
| 78 |
chatId: data.chatId, |
| 79 |
timestamp: data.timestamp |
| 80 |
}) |
| 81 |
}); |
| 82 |
|
| 83 |
if (!response.ok) { |
| 84 |
throw new Error(`Server error: ${response.status}`); |
| 85 |
} |
| 86 |
|
| 87 |
const result = await response.json(); |
| 88 |
console.log('[LooseCannon] Generated response:', result.reply); |
| 89 |
|
| 90 |
// Log conversation for debugging |
| 91 |
this.logConversation(data.chatId, data.text, result.reply); |
| 92 |
|
| 93 |
return { reply: result.reply }; |
| 94 |
} catch (error) { |
| 95 |
console.error('[LooseCannon] Error generating response:', error); |
| 96 |
return { error: error.message }; |
| 97 |
} |
| 98 |
} |
| 99 |
|
| 100 |
handleToggleActive(tabId, isActive) { |
| 101 |
if (isActive) { |
| 102 |
this.activeTabs.set(tabId, { |
| 103 |
activated: new Date().toISOString(), |
| 104 |
messageCount: 0 |
| 105 |
}); |
| 106 |
console.log(`[LooseCannon] Activated for tab ${tabId}`); |
| 107 |
} else { |
| 108 |
this.activeTabs.delete(tabId); |
| 109 |
console.log(`[LooseCannon] Deactivated for tab ${tabId}`); |
| 110 |
} |
| 111 |
} |
| 112 |
|
| 113 |
async checkServerConnection() { |
| 114 |
try { |
| 115 |
console.log('[LooseCannon] Checking server connection...'); |
| 116 |
const response = await fetch(`${this.serverUrl}/status`); |
| 117 |
|
| 118 |
if (response.ok) { |
| 119 |
const data = await response.json(); |
| 120 |
this.isConnected = true; |
| 121 |
this.personalities = data.personalities || []; |
| 122 |
console.log('[LooseCannon] Server connected successfully'); |
| 123 |
console.log('[LooseCannon] Available personalities:', this.personalities); |
| 124 |
return true; |
| 125 |
} else { |
| 126 |
this.isConnected = false; |
| 127 |
console.warn('[LooseCannon] Server responded with error:', response.status); |
| 128 |
return false; |
| 129 |
} |
| 130 |
} catch (error) { |
| 131 |
this.isConnected = false; |
| 132 |
console.error('[LooseCannon] Could not connect to server:', error.message); |
| 133 |
|
| 134 |
// Retry in 5 seconds |
| 135 |
setTimeout(() => this.checkServerConnection(), 5000); |
| 136 |
return false; |
| 137 |
} |
| 138 |
} |
| 139 |
|
| 140 |
async loadSettings() { |
| 141 |
try { |
| 142 |
const settings = await browser.storage.local.get(['personality', 'serverUrl']); |
| 143 |
if (settings.personality) { |
| 144 |
this.currentPersonality = settings.personality; |
| 145 |
} |
| 146 |
if (settings.serverUrl) { |
| 147 |
this.serverUrl = settings.serverUrl; |
| 148 |
} |
| 149 |
console.log('[LooseCannon] Settings loaded:', settings); |
| 150 |
} catch (error) { |
| 151 |
console.error('[LooseCannon] Error loading settings:', error); |
| 152 |
} |
| 153 |
} |
| 154 |
|
| 155 |
async saveSettings() { |
| 156 |
try { |
| 157 |
await browser.storage.local.set({ |
| 158 |
personality: this.currentPersonality, |
| 159 |
serverUrl: this.serverUrl |
| 160 |
}); |
| 161 |
console.log('[LooseCannon] Settings saved'); |
| 162 |
} catch (error) { |
| 163 |
console.error('[LooseCannon] Error saving settings:', error); |
| 164 |
} |
| 165 |
} |
| 166 |
|
| 167 |
logConversation(chatId, userMessage, botReply) { |
| 168 |
const log = { |
| 169 |
timestamp: new Date().toISOString(), |
| 170 |
chatId, |
| 171 |
userMessage, |
| 172 |
botReply |
| 173 |
}; |
| 174 |
|
| 175 |
// Store conversation logs (with limit to prevent storage overflow) |
| 176 |
browser.storage.local.get('conversationLogs').then(result => { |
| 177 |
let logs = result.conversationLogs || []; |
| 178 |
logs.push(log); |
| 179 |
|
| 180 |
// Keep only last 100 messages |
| 181 |
if (logs.length > 100) { |
| 182 |
logs = logs.slice(-100); |
| 183 |
} |
| 184 |
|
| 185 |
browser.storage.local.set({ conversationLogs: logs }); |
| 186 |
}); |
| 187 |
} |
| 188 |
} |
| 189 |
|
| 190 |
// Initialize background script |
| 191 |
const looseCannonBg = new LooseCannonBackground(); |