diff --git a/.gitignore b/.gitignore index ab59bd2..24a8876 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ logs/ bin/ *.exe *.dll +projects.json diff --git a/logs/nginx.pid b/logs/nginx.pid index ebd1b4f..774222b 100644 --- a/logs/nginx.pid +++ b/logs/nginx.pid @@ -1 +1 @@ -39708 +23324 diff --git a/src/main/ipc/index.ts b/src/main/ipc/index.ts index 71a8351..cff5cda 100644 --- a/src/main/ipc/index.ts +++ b/src/main/ipc/index.ts @@ -60,13 +60,12 @@ export function registerIpcHandlers(): void { const phpPort = portMappingService.getPhpPort(p.phpVersion) const normalizedPath = p.path.replace(/\\/g, '/') return ` - location /${p.host} { - alias "${normalizedPath}"; + location /${p.host}/ { + alias "${normalizedPath}/"; index index.php index.html; try_files $uri $uri/ /${p.host}/index.php?$query_string; - location ~ ^/${p.host}/(.+\\.php)$ { - alias "${normalizedPath}/$1"; + location ~ \.php$ { fastcgi_pass 127.0.0.1:${phpPort}; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $request_filename; @@ -140,7 +139,22 @@ export function registerIpcHandlers(): void { if (!fs.existsSync(dataDir) || fs.readdirSync(dataDir).length === 0) { if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true }) console.log(`Initializing MySQL data directory for ${serviceName}...`) - await processManager.runOnce(binPath, ['--initialize-insecure', `--datadir=${dataDir.replace(/\\/g, '/')}`]) + + try { + // Try modern initialization first (5.7+) + await processManager.runOnce(binPath, ['--initialize-insecure', `--datadir=${dataDir.replace(/\\/g, '/')}`]) + } catch (err) { + console.log(`Modern init failed, trying template copy for ${serviceName}...`) + // Fallback for 5.6: Copy default 'data' folder from binary dir if it exists + const templateDataDir = path.join(mysqlDir, 'data') + if (fs.existsSync(templateDataDir)) { + // Recursively copy template data (mysql, performance_schema, etc.) + fs.cpSync(templateDataDir, dataDir, { recursive: true }) + console.log(`Successfully copied template data for ${serviceName}`) + } else { + throw new Error(`MySQL initialization failed and no template data found at ${templateDataDir}`) + } + } } const mysqlPort = mysqlId ? (settings.mysqlPorts?.[mysqlId] || '3306') : settings.mysqlPort @@ -155,6 +169,15 @@ export function registerIpcHandlers(): void { }) const success = await processManager.startService(serviceName, binPath, ['--defaults-file=' + configPath], false) + + if (success) { + // 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.` } + } + } + return { success, message: success ? `${mysqlVersion || ''} MySQL başlatıldı.` : `${mysqlVersion || ''} MySQL devreye alınamadı.` } } @@ -310,4 +333,24 @@ export function registerIpcHandlers(): void { event.sender.send('pma:progress', p) }) }) + + ipcMain.handle('services:reset-data', async (_event, serviceName: string) => { + try { + await processManager.forceKillAll(serviceName) + + const versionMatch = serviceName.match(/^mysql:(.+)$/) + const mysqlVersion = versionMatch ? versionMatch[1] : null + const mysqlId = mysqlVersion ? `mysql-${mysqlVersion}` : null + + if (!mysqlId) return { success: false, message: 'Geçersiz servis adı.' } + + const dataDir = path.join(configService.getBasePath(), 'data', mysqlId) + if (fs.existsSync(dataDir)) { + fs.rmSync(dataDir, { recursive: true, force: true }) + } + return { success: true, message: `${serviceName} verileri sıfırlandı. Tekrar başlatmayı deneyebilirsiniz.` } + } catch (error: any) { + return { success: false, message: `Sıfırlama hatası: ${error.message}` } + } + }) } diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 3ed4e8e..5d0c74e 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -66,7 +66,8 @@ import { Storage as MySQLIcon, Language as HostIcon, Launch as LaunchIcon, - Handyman as ToolsIcon + Handyman as ToolsIcon, + Restore as ResetIcon } from '@mui/icons-material' import { useTranslation } from 'react-i18next' @@ -314,6 +315,13 @@ function App(): JSX.Element { await fetchLogs(service) } + 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 handleSaveSettings = async () => { if (window.api && window.api.saveSettings) { const result = await window.api.saveSettings(settings) @@ -819,9 +827,14 @@ function App(): JSX.Element { MySQL {v.version} Port: {settings.mysqlPorts?.[v.id] || v.port} - handleOpenLogs(`mysql:${v.version}`)} size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)' }}> - - + + handleOpenLogs(`mysql:${v.version}`)} title="Hata Logları" size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)' }}> + + + handleResetData(`mysql:${v.version}`)} title="Verileri Sıfırla" size="small" sx={{ bgcolor: 'rgba(255,255,255,0.05)', '&:hover': { color: 'error.main' } }}> + + + handleToggleService(`mysql:${v.version}`)}