feat: implement IPC handlers for service management and add ProcessManager for background process control
This commit is contained in:
@@ -168,10 +168,14 @@ export function registerIpcHandlers(): void {
|
||||
|
||||
if (!binPath) return { success: false, message: 'MySQL executable bulunamadı. Lütfen indirin.' }
|
||||
|
||||
const mysqlPort = mysqlId ? (settings.mysqlPorts?.[mysqlId] || '3306') : settings.mysqlPort
|
||||
|
||||
// Force kill this specific version if running or generic mysql
|
||||
// Actually processManager handles by serviceName
|
||||
await processManager.forceKillAll(serviceName)
|
||||
|
||||
// Also kill anything else listening on the same port
|
||||
await processManager.killByPort(serviceName, mysqlPort)
|
||||
|
||||
// Initialize if data directory is empty
|
||||
if (!fs.existsSync(dataDir) || fs.readdirSync(dataDir).length === 0) {
|
||||
if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true })
|
||||
@@ -194,7 +198,6 @@ export function registerIpcHandlers(): void {
|
||||
}
|
||||
}
|
||||
|
||||
const mysqlPort = mysqlId ? (settings.mysqlPorts?.[mysqlId] || '3306') : settings.mysqlPort
|
||||
const sanitizedServiceName = serviceName.replace(/:/g, '_')
|
||||
const logFile = path.join(configService.getBasePath(), 'logs', `${sanitizedServiceName}_error.log`)
|
||||
|
||||
|
||||
@@ -222,6 +222,65 @@ export class ProcessManager {
|
||||
})
|
||||
}
|
||||
|
||||
async killByPort(name: string, port: string | number): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
if (!port) return resolve(true)
|
||||
|
||||
this.addLog(name, `Checking if port ${port} is in use...`)
|
||||
// findstr will return lines containing the port and "LISTENING"
|
||||
const cmd = `netstat -ano | findstr :${port} | findstr LISTENING`
|
||||
const netstat = spawn('cmd.exe', ['/c', cmd], { windowsHide: true, shell: false })
|
||||
|
||||
let output = ''
|
||||
netstat.stdout?.on('data', (data) => {
|
||||
output += data.toString()
|
||||
})
|
||||
|
||||
netstat.on('close', () => {
|
||||
const lines = output.split('\n').filter(l => l.trim())
|
||||
if (lines.length === 0) {
|
||||
this.addLog(name, `Port ${port} is free.`)
|
||||
return resolve(true)
|
||||
}
|
||||
|
||||
// netstat output format: TCP 0.0.0.0:3306 0.0.0.0:0 LISTENING 1234
|
||||
// We want the last part, which is the PID
|
||||
const pids = new Set<string>()
|
||||
lines.forEach(line => {
|
||||
const parts = line.trim().split(/\s+/)
|
||||
const pid = parts[parts.length - 1]
|
||||
if (pid && !isNaN(parseInt(pid)) && parseInt(pid) > 0) {
|
||||
pids.add(pid)
|
||||
}
|
||||
})
|
||||
|
||||
if (pids.size === 0) {
|
||||
this.addLog(name, `Port ${port} in use but PID not found.`)
|
||||
return resolve(true)
|
||||
}
|
||||
|
||||
this.addLog(name, `Port ${port} is used by PIDs: ${Array.from(pids).join(', ')}. Terminating...`)
|
||||
|
||||
const killProcesses = Array.from(pids).map(pid => {
|
||||
return new Promise<void>((res) => {
|
||||
const tk = spawn('taskkill', ['/F', '/PID', pid, '/T'], { windowsHide: true, shell: false })
|
||||
tk.on('close', () => res())
|
||||
})
|
||||
})
|
||||
|
||||
Promise.all(killProcesses).then(() => {
|
||||
this.addLog(name, `Successfully cleared port ${port}.`)
|
||||
resolve(true)
|
||||
})
|
||||
})
|
||||
|
||||
netstat.on('error', (err) => {
|
||||
this.addLog(name, `Port check error: ${err.message}`)
|
||||
resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
isServiceRunning(name: string): boolean {
|
||||
return this.processes.has(name)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user