Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(desktop): fix sqlite disconnect warning issue #1897

Merged
merged 2 commits into from
Mar 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
"babel-plugin-prismjs": "^2.1.0",
"chai": "^4.1.2",
"electron": "^22.0.0",
"electron-devtools-installer": "^3.2.0",
"electron-devtools-installer": "^3.1.1",
"eslint": "6.5.1",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
Expand Down
20 changes: 15 additions & 5 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'reflect-metadata' // Required by TypoORM.
;('use strict')
import { app, protocol, BrowserWindow, ipcMain, shell, Menu } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
import { quitAndRenameLogger } from './utils/logger'
import { defaultWindowSize, restoreWindowState, saveWindowState } from './utils/windowStateManager'
import rebuildDatabase from './database/rebuildDatabase'
Expand Down Expand Up @@ -43,6 +42,9 @@ protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: tru

const { ConnectionInit, ConnectionDestroy } = useConnection()

// Flag to track if connections have been destroyed
let connectionsDestroyed = false

function handleIpcMessages() {
ipcMain.on('setting', (event: Electron.IpcMainEvent, ...args: any[]) => {
event.sender.send('setting', ...args)
Expand Down Expand Up @@ -120,10 +122,16 @@ function handleIpcMessages() {
function beforeAppQuit() {
// close all log appender and rename log file with date
quitAndRenameLogger()
// close all SQLite connection
ConnectionDestroy()

// close all SQLite connection - only if not already destroyed
if (!connectionsDestroyed) {
connectionsDestroyed = true
ConnectionDestroy()
}

// cleanup MCP connections
cleanupMCPConnections()

// quit APP
app.quit()
}
Expand Down Expand Up @@ -246,10 +254,12 @@ async function createWindow() {
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
// Install Vue Devtools on development mode
if (isDevelopment && !process.env.IS_TEST) {
// Install Vue Devtools
try {
await installExtension(VUEJS_DEVTOOLS)
const installExtension = require('electron-devtools-installer').default
await installExtension('iaajmlceplecbljialhhkmedjlpdblhp')
console.log('Vue Devtools installed successfully')
} catch (e) {
console.error('Vue Devtools failed to install:', e)
}
Expand Down
7 changes: 3 additions & 4 deletions src/components/ai/Copilot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ export default class Copilot extends Vue {
const throttledScroll = throttle(() => this.scrollToBottom(), 100)

this.abortController = new AbortController()
this.$log.info(`[Copilot] AI response stream started with provider: "${this.model}" from "${this.openAIAPIHost}"`)
const { textStream } = streamText({
model: getModelProvider({
model: this.model,
Expand All @@ -226,8 +227,6 @@ export default class Copilot extends Vue {
if (this.shouldProcessMCP) {
const processedContent = await processMCPCalls(this.responseStreamText)
responseMessage.content = processedContent
// AI TOOL CALL RESULT
console.log(processedContent)
} else {
responseMessage.content = this.responseStreamText
}
Expand Down Expand Up @@ -372,7 +371,7 @@ export default class Copilot extends Vue {
}
@keyframes rightbarPop {
from {
right: -45%;
right: -50%;
}
to {
right: 0px;
Expand All @@ -382,7 +381,7 @@ export default class Copilot extends Vue {
box-shadow: -2px 0px 8px 0px var(--color-shadow-leftlist);
position: fixed;
right: 0px;
width: 45%;
width: 50%;
background: var(--color-bg-normal);
border-radius: 0;
top: 0;
Expand Down
11 changes: 10 additions & 1 deletion src/database/useConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,16 @@ const useConnection = () => {
}
async function ConnectionDestroy() {
if (sqlConnection) {
await sqlConnection.close()
try {
if (sqlConnection.isConnected) {
await sqlConnection.close()
}
} catch (error) {
console.error('[Database] Error closing database connection:', error)
// Gracefully handle errors during connection close
} finally {
sqlConnection = undefined
}
}
}
return {
Expand Down
76 changes: 38 additions & 38 deletions src/main/ai/mcp/MCPManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const activeClients: Map<string, MCPClient> = new Map()
export function initMCPHandlers(): void {
// Test connection to a server
ipcMain.handle('mcp:test-connection', async (_, serverConfig: MCPServer, serverName: string) => {
console.log(`Testing connection to MCP server: ${serverName}`)
console.log(`[MCP] Testing connection to MCP server: ${serverName}`)
try {
const client = new MCPClient()
const connected = await client.connectToServer(serverConfig)
Expand Down Expand Up @@ -60,16 +60,16 @@ export function initMCPHandlers(): void {

// Call a tool on a specific server
ipcMain.handle('mcp:call-tool', async (_, serverName: string, toolName: string, toolArgs: any) => {
console.log(`Calling tool ${toolName} on server ${serverName}`)
console.log(`[MCP] Calling tool ${toolName} on server ${serverName}`)

try {
const client = activeClients.get(serverName)
if (!client) {
// 如果服务器未连接,尝试自动连接
// If server is not connected, try to auto-connect
await autoConnectToServer(serverName)
const reconnectedClient = activeClients.get(serverName)
if (!reconnectedClient) {
throw new Error(`No active connection to server: ${serverName} and auto-reconnect failed`)
throw new Error(`[MCP] No active connection to server: ${serverName} and auto-reconnect failed`)
}

const result = await reconnectedClient.callTool(toolName, toolArgs)
Expand All @@ -80,7 +80,7 @@ export function initMCPHandlers(): void {
}

if (!client.isConnected()) {
throw new Error(`Connection to server ${serverName} has been lost`)
throw new Error(`[MCP] Connection to server ${serverName} has been lost`)
}

const result = await client.callTool(toolName, toolArgs)
Expand All @@ -89,7 +89,7 @@ export function initMCPHandlers(): void {
result,
}
} catch (error) {
console.error(`Error calling tool ${toolName} on server ${serverName}:`, error)
console.error(`[MCP] Error calling tool ${toolName} on server ${serverName}:`, error)
return {
success: false,
message: error instanceof Error ? error.message : String(error),
Expand All @@ -99,7 +99,7 @@ export function initMCPHandlers(): void {

// Disconnect from a server
ipcMain.handle('mcp:disconnect', async (_, serverName: string) => {
console.log(`Disconnecting from MCP server: ${serverName}`)
console.log(`[MCP] Disconnecting from MCP server: ${serverName}`)

try {
const client = activeClients.get(serverName)
Expand All @@ -116,81 +116,81 @@ export function initMCPHandlers(): void {
message: `No active connection to server: ${serverName}`,
}
} catch (error) {
console.error(`Error disconnecting from MCP server: ${serverName}`, error)
console.error(`[MCP] Error disconnecting from MCP server: ${serverName}`, error)
return {
success: false,
message: error instanceof Error ? error.message : String(error),
}
}
})

// 自动连接已启用的 MCP 服务器
// Auto-connect to enabled MCP servers
autoConnectToEnabledServers()
}

/**
* 自动连接到启用的 MCP 服务器
* Automatically connect to enabled MCP servers
*/
async function autoConnectToEnabledServers(): Promise<void> {
console.log('Checking for enabled MCP servers to auto-connect')
console.log('[MCP] Checking for enabled MCP servers to auto-connect')

try {
// 从本地存储中读取 MCP 配置
// Read MCP configuration from local storage
const Store = require('electron-store')
const store = new Store()

// 检查 MCP 是否启用
// Check if MCP is enabled
const mcpEnabled = store.get('mcpEnabled')
if (mcpEnabled !== 'true') {
console.log('MCP is not enabled, skipping auto-connect')
console.log('[MCP] MCP is not enabled, skipping auto-connect')
return
}

// 获取 MCP 配置
// Get MCP configuration
const mcpConfigStr = store.get('mcpConfig')
if (!mcpConfigStr) {
console.log('No MCP configuration found, skipping auto-connect')
console.log('[MCP] No MCP configuration found, skipping auto-connect')
return
}

let mcpConfig
try {
mcpConfig = JSON.parse(mcpConfigStr)
} catch (err) {
console.error('Failed to parse MCP configuration:', err)
console.error('[MCP] Failed to parse MCP configuration:', err)
return
}

if (!mcpConfig.mcpServers) {
console.log('No MCP servers configured, skipping auto-connect')
console.log('[MCP] No MCP servers configured, skipping auto-connect')
return
}

// 连接所有启用的服务器
// Connect to all enabled servers
for (const [serverName, serverConfig] of Object.entries(mcpConfig.mcpServers)) {
const serverEnabled = store.get(`mcpServerEnabled:${serverName}`)
if (serverEnabled === 'true') {
await autoConnectToServer(serverName, serverConfig as MCPServer)
}
}

console.log(`Auto-connected to ${activeClients.size} MCP servers`)
console.log(`[MCP] Auto-connected to ${activeClients.size} MCP servers`)
} catch (error) {
console.error('Error during MCP auto-connect:', error)
console.error('[MCP] Error during MCP auto-connect:', error)
}
}

/**
* 自动连接到指定的 MCP 服务器
* Automatically connect to a specific MCP server
*
* @param serverName 服务器名称
* @param serverConfig 服务器配置(可选)
* @param serverName Server name
* @param serverConfig Server configuration (optional)
*/
async function autoConnectToServer(serverName: string, serverConfig?: MCPServer): Promise<boolean> {
console.log(`Auto-connecting to MCP server: ${serverName}`)
console.log(`[MCP] Auto-connecting to MCP server: ${serverName}`)

try {
// 如果没有提供服务器配置,从存储中获取
// If server configuration is not provided, get it from storage
if (!serverConfig) {
const Store = require('electron-store')
const store = new Store()
Expand All @@ -205,35 +205,35 @@ async function autoConnectToServer(serverName: string, serverConfig?: MCPServer)
serverConfig = mcpConfig.mcpServers[serverName] as MCPServer

if (!serverConfig) {
console.error(`Server configuration for ${serverName} not found`)
console.error(`[MCP] Server configuration for ${serverName} not found`)
return false
}
} catch (err) {
console.error('Failed to parse MCP configuration:', err)
console.error('[MCP] Failed to parse MCP configuration:', err)
return false
}
}

// 检查是否已经有连接
// Check if connection already exists
if (activeClients.has(serverName)) {
const existingClient = activeClients.get(serverName)
if (existingClient && existingClient.isConnected()) {
console.log(`Server ${serverName} is already connected`)
console.log(`[MCP] Server ${serverName} is already connected`)
return true
}

// 如果存在但断开连接,先清理
// If exists but disconnected, clean up first
if (existingClient) {
try {
await existingClient.disconnect()
} catch (err) {
console.error(`Error disconnecting existing client for ${serverName}:`, err)
console.error(`[MCP] Error disconnecting existing client for ${serverName}:`, err)
}
activeClients.delete(serverName)
}
}

// 创建并连接新客户端
// Create and connect new client
const client = new MCPClient()
const connected = await client.connectToServer(serverConfig)

Expand All @@ -245,11 +245,11 @@ async function autoConnectToServer(serverName: string, serverConfig?: MCPServer)
activeClients.set(serverName, client)
return true
} else {
console.error(`Failed to connect to MCP server: ${serverName}`)
console.error(`[MCP] Failed to connect to MCP server: ${serverName}`)
return false
}
} catch (error) {
console.error(`Error auto-connecting to MCP server ${serverName}:`, error)
console.error(`[MCP] Error auto-connecting to MCP server ${serverName}:`, error)
return false
}
}
Expand All @@ -258,14 +258,14 @@ async function autoConnectToServer(serverName: string, serverConfig?: MCPServer)
* Clean up all active connections
*/
export async function cleanupMCPConnections(): Promise<void> {
console.log(`Cleaning up ${activeClients.size} MCP connections`)
console.log(`[MCP] Cleaning up ${activeClients.size} MCP connections`)

for (const [name, client] of activeClients.entries()) {
try {
await client.disconnect()
console.log(`Disconnected from MCP server: ${name}`)
console.log(`[MCP] Disconnected from MCP server: ${name}`)
} catch (error) {
console.error(`Error disconnecting from MCP server: ${name}`, error)
console.error(`[MCP] Error disconnecting from MCP server: ${name}`, error)
}
}

Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5282,10 +5282,10 @@ [email protected], electron-builder@^22.2.0:
simple-update-notifier "^1.0.7"
yargs "^17.5.1"

electron-devtools-installer@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-3.2.0.tgz#acc48d24eb7033fe5af284a19667e73b78d406d0"
integrity sha512-t3UczsYugm4OAbqvdImMCImIMVdFzJAHgbwHpkl5jmfu1izVgUcP/mnrPqJIpEeCK1uZGpt+yHgWEN+9EwoYhQ==
electron-devtools-installer@^3.1.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-3.2.1.tgz#338a0ada7b4232ee42cd88fe5cf305c6be95cfe9"
integrity sha512-FaCi+oDCOBTw0gJUsuw5dXW32b2Ekh5jO8lI1NRCQigo3azh2VogsIi0eelMVrP1+LkN/bewyH3Xoo1USjO0eQ==
dependencies:
rimraf "^3.0.2"
semver "^7.2.1"
Expand Down