feat: implement Nginx and PHP service management IPC handlers and add sweetalert2 dependency
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
43936
|
||||
32612
|
||||
|
||||
Generated
+12
-1
@@ -20,7 +20,8 @@
|
||||
"i18next": "^23.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-i18next": "^13.0.0"
|
||||
"react-i18next": "^13.0.0",
|
||||
"sweetalert2": "^11.26.24"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-toolkit/eslint-config": "^1.0.2",
|
||||
@@ -8940,6 +8941,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/sweetalert2": {
|
||||
"version": "11.26.24",
|
||||
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.26.24.tgz",
|
||||
"integrity": "sha512-SLgukW4wicewpW5VOukSXY5Z6DL/z7HCOK2ODSjmQPiSphCN8gJAmh9npoceXOtBRNoDN0xIz+zHYthtfiHmjg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/limonte"
|
||||
}
|
||||
},
|
||||
"node_modules/synckit": {
|
||||
"version": "0.11.12",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz",
|
||||
|
||||
+2
-1
@@ -32,7 +32,8 @@
|
||||
"i18next": "^23.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-i18next": "^13.0.0"
|
||||
"react-i18next": "^13.0.0",
|
||||
"sweetalert2": "^11.26.24"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-toolkit/eslint-config": "^1.0.2",
|
||||
|
||||
+21
-3
@@ -120,7 +120,13 @@ export function registerIpcHandlers(): void {
|
||||
}
|
||||
|
||||
const success = await processManager.startService('nginx', binPath, ['-p', nginxPrefix, '-c', configPath], false)
|
||||
return { success, message: success ? 'Nginx başlatıldı.' : 'Nginx devreye alınamadı (Hata loglarını kontrol edin).' }
|
||||
|
||||
if (!success) {
|
||||
const errorLogs = await processManager.getLastErrorLogs('nginx')
|
||||
return { success: false, message: `Nginx başlatılamadı.\n\n${errorLogs.join('\n')}` }
|
||||
}
|
||||
|
||||
return { success, message: success ? 'Nginx başlatıldı.' : 'Nginx devreye alınamadı.' }
|
||||
}
|
||||
|
||||
if (serviceName.startsWith('php')) {
|
||||
@@ -151,6 +157,12 @@ export function registerIpcHandlers(): void {
|
||||
})
|
||||
|
||||
const success = await processManager.startService(serviceName, binPath, ['-b', `127.0.0.1:${phpPort}`, '-c', configPath], false)
|
||||
|
||||
if (!success) {
|
||||
const errorLogs = await processManager.getLastErrorLogs(serviceName)
|
||||
return { success: false, message: `${phpVersion || ''} PHP başlatılamadı.\n\n${errorLogs.join('\n')}` }
|
||||
}
|
||||
|
||||
return { success, message: success ? `${phpVersion || ''} PHP başlatıldı.` : `${phpVersion || ''} PHP devreye alınamadı.` }
|
||||
}
|
||||
|
||||
@@ -168,7 +180,9 @@ 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
|
||||
const mysqlVersions = await mySqlManagerService.getVersions()
|
||||
const mysqlInfo = mysqlVersions.find(v => v.id === mysqlId)
|
||||
const mysqlPort = mysqlInfo?.port || (mysqlId ? '3306' : settings.mysqlPort)
|
||||
|
||||
// Force kill this specific version if running or generic mysql
|
||||
await processManager.forceKillAll(serviceName)
|
||||
@@ -214,8 +228,12 @@ export function registerIpcHandlers(): void {
|
||||
// Quick health check for MySQL
|
||||
await new Promise(r => setTimeout(r, 1500))
|
||||
if (!processManager.isServiceRunning(serviceName)) {
|
||||
return { success: false, message: `${mysqlVersion || ''} MySQL başlatıldı ancak çalışma hatası verdi. Lütfen logları ve port çakışmalarını kontrol edin.` }
|
||||
const errorLogs = await processManager.getLastErrorLogs(serviceName)
|
||||
return { success: false, message: `${mysqlVersion || ''} MySQL başlatıldı ancak çalışma hatası verdi (ExitCode: 1).\n\n${errorLogs.length > 0 ? 'Önemli Hata Logları:\n' + errorLogs.join('\n') : 'Lütfen log sekmesini kontrol edin.'}` }
|
||||
}
|
||||
} else {
|
||||
const errorLogs = await processManager.getLastErrorLogs(serviceName)
|
||||
return { success: false, message: `${mysqlVersion || ''} MySQL başlatılamadı.\n\n${errorLogs.join('\n')}` }
|
||||
}
|
||||
|
||||
return { success, message: success ? `${mysqlVersion || ''} MySQL başlatıldı.` : `${mysqlVersion || ''} MySQL devreye alınamadı.` }
|
||||
|
||||
@@ -318,6 +318,51 @@ export class ProcessManager {
|
||||
}
|
||||
}
|
||||
|
||||
getLastLogs(name: string, count: number = 10): string[] {
|
||||
const serviceLogs = this.logs.get(name) || []
|
||||
return serviceLogs.slice(-count)
|
||||
}
|
||||
|
||||
async getLastErrorLogs(name: string, count: number = 10): Promise<string[]> {
|
||||
this.initLogs()
|
||||
const foundLogs: string[] = []
|
||||
|
||||
// 1. Check in-memory logs for [CORE ERROR] or other error markers
|
||||
const memLogs = this.logs.get(name) || []
|
||||
const errorMarkers = ['ERROR', 'failed', 'Fatal', 'error']
|
||||
const recentErrors = memLogs.filter(line =>
|
||||
errorMarkers.some(m => line.toLowerCase().includes(m.toLowerCase()))
|
||||
).slice(-count)
|
||||
|
||||
foundLogs.push(...recentErrors)
|
||||
|
||||
// 2. Check physical log files if memory logs are insufficient
|
||||
const sanitizedName = name.replace(/:/g, '_')
|
||||
const possibleFiles = [
|
||||
path.join(this.logDir, `${sanitizedName}.log`),
|
||||
path.join(this.logDir, `${sanitizedName}_error.log`),
|
||||
path.join(this.logDir, `mysql_error.log`),
|
||||
path.join(this.logDir, `nginx_error.log`)
|
||||
]
|
||||
|
||||
for (const logPath of possibleFiles) {
|
||||
if (fs.existsSync(logPath)) {
|
||||
try {
|
||||
const content = fs.readFileSync(logPath, 'utf8')
|
||||
const lines = content.split(/\r?\n/).filter(l => l.trim())
|
||||
const relevantLines = lines.slice(-count)
|
||||
relevantLines.forEach(l => {
|
||||
if (!foundLogs.includes(l)) foundLogs.push(l)
|
||||
})
|
||||
} catch (e) {
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(new Set(foundLogs)).slice(-count)
|
||||
}
|
||||
|
||||
stopAll(): void {
|
||||
for (const name of this.processes.keys()) {
|
||||
this.stopService(name)
|
||||
|
||||
@@ -69,6 +69,7 @@ import {
|
||||
Handyman as ToolsIcon,
|
||||
Restore as ResetIcon
|
||||
} from '@mui/icons-material'
|
||||
import Swal from 'sweetalert2'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
declare global {
|
||||
@@ -302,11 +303,26 @@ function App(): JSX.Element {
|
||||
// Refresh status after operation
|
||||
fetchStatus()
|
||||
|
||||
setNotification({
|
||||
open: true,
|
||||
message: result.message,
|
||||
severity: result.success ? 'success' : 'error'
|
||||
})
|
||||
if (!result.success) {
|
||||
Swal.fire({
|
||||
title: 'Hata!',
|
||||
text: result.message,
|
||||
icon: 'error',
|
||||
confirmButtonText: 'Tamam',
|
||||
background: '#1e1e1e',
|
||||
color: '#fff',
|
||||
confirmButtonColor: '#153E5E',
|
||||
customClass: {
|
||||
popup: 'swal2-dark-popup'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
setNotification({
|
||||
open: true,
|
||||
message: result.message,
|
||||
severity: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleOpenLogs = async (service: string) => {
|
||||
@@ -316,10 +332,30 @@ function App(): JSX.Element {
|
||||
}
|
||||
|
||||
const handleResetData = async (service: string) => {
|
||||
if (!window.confirm(`${service} verilerini sıfırlamak istiyor musunuz? Bu işlem tüm verileri siler ve temiz kurulum yapar.`)) return
|
||||
const result = await window.api.invoke('services:reset-data', service)
|
||||
alert(result.message)
|
||||
fetchStatus()
|
||||
const confirmResult = await Swal.fire({
|
||||
title: 'Emin misiniz?',
|
||||
text: `${service} verilerini sıfırlamak istiyor musunuz? Bu işlem tüm verileri siler ve temiz kurulum yapar.`,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Sıfırla',
|
||||
cancelButtonText: 'Vazgeç',
|
||||
background: '#1e1e1e',
|
||||
color: '#fff',
|
||||
confirmButtonColor: '#d33',
|
||||
cancelButtonColor: '#3085d6'
|
||||
})
|
||||
|
||||
if (confirmResult.isConfirmed) {
|
||||
const result = await window.api.invoke('services:reset-data', service)
|
||||
Swal.fire({
|
||||
title: result.success ? 'Başarılı!' : 'Hata!',
|
||||
text: result.message,
|
||||
icon: result.success ? 'success' : 'error',
|
||||
background: '#1e1e1e',
|
||||
color: '#fff'
|
||||
})
|
||||
fetchStatus()
|
||||
}
|
||||
}
|
||||
|
||||
const handleSaveSettings = async () => {
|
||||
|
||||
Reference in New Issue
Block a user