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.' }
|
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
|
// Force kill this specific version if running or generic mysql
|
||||||
// Actually processManager handles by serviceName
|
|
||||||
await processManager.forceKillAll(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
|
// Initialize if data directory is empty
|
||||||
if (!fs.existsSync(dataDir) || fs.readdirSync(dataDir).length === 0) {
|
if (!fs.existsSync(dataDir) || fs.readdirSync(dataDir).length === 0) {
|
||||||
if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true })
|
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 sanitizedServiceName = serviceName.replace(/:/g, '_')
|
||||||
const logFile = path.join(configService.getBasePath(), 'logs', `${sanitizedServiceName}_error.log`)
|
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 {
|
isServiceRunning(name: string): boolean {
|
||||||
return this.processes.has(name)
|
return this.processes.has(name)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user