diff --git a/src/main/ipc/index.ts b/src/main/ipc/index.ts index 505b885..17e955b 100644 --- a/src/main/ipc/index.ts +++ b/src/main/ipc/index.ts @@ -28,29 +28,36 @@ function findExecutable(dir: string, name: string): string | null { return null } +async function reloadNginx(): Promise<{ success: boolean; message: string }> { + try { + const binDir = path.join(configService.getBasePath(), 'bin') + const nginxDir = path.join(binDir, 'nginx') + const nginxVersions = fs.readdirSync(nginxDir).filter(f => fs.statSync(path.join(nginxDir, f)).isDirectory()) + const activeVersion = nginxVersions[0] + if (!activeVersion) throw new Error('Nginx sürümü bulunamadı.') + + const nginxPrefix = path.join(nginxDir, activeVersion) + const binPath = path.join(nginxPrefix, 'nginx.exe') + const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') + + const result = await processManager.runOnce(binPath, ['-p', nginxPrefix, '-c', configPath, '-s', 'reload'], 'nginx') + if (result.success) { + console.log('Nginx reload successful') + return { success: true, message: 'Nginx reloaded' } + } else { + console.error('Nginx reload failed:', result.output) + return { success: false, message: result.output || 'Nginx reload failed' } + } + } catch (error: any) { + return { success: false, message: `Reload hatası: ${error.message}` } + } +} + export function registerIpcHandlers(): void { // Service management ipcMain.handle('services:reload', async (_event, serviceName: string) => { if (serviceName !== 'nginx') return { success: false, message: 'Yalnızca Nginx için reload desteklenmektedir.' } - - try { - // Re-generate config - const binDir = path.join(configService.getBasePath(), 'bin') - const nginxDir = path.join(binDir, 'nginx') - const nginxVersions = fs.readdirSync(nginxDir).filter(f => fs.statSync(path.join(nginxDir, f)).isDirectory()) - const activeVersion = nginxVersions[0] // Simplify: use first installed - if (!activeVersion) throw new Error('Nginx sürümü bulunamadı.') - - const nginxPrefix = path.join(nginxDir, activeVersion) - const binPath = path.join(nginxPrefix, 'nginx.exe') - const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') - - // For reload, we need the same prefix and config - const success = await processManager.runOnce(binPath, ['-p', nginxPrefix, '-c', configPath, '-s', 'reload'], 'nginx') - return { success, message: success ? 'Nginx yapılandırması yeniden yüklendi.' : 'Nginx reload hatası (Nginx çalışmıyor olabilir).' } - } catch (error: any) { - return { success: false, message: `Reload hatası: ${error.message}` } - } + return await reloadNginx() }) ipcMain.handle('services:start', async (_event, serviceName: string) => { @@ -116,8 +123,9 @@ export function registerIpcHandlers(): void { // Test config first with prefix const testResult = await processManager.runOnce(binPath, ['-t', '-p', nginxPrefix, '-c', configPath], 'nginx') - if (!testResult) { - return { success: false, message: 'Nginx konfigürasyon hatası! Log sekmesini kontrol edin.' } + if (!testResult.success) { + console.error('Nginx config test failed before reload:', testResult.output) + return { success: false, message: `Nginx config error: ${testResult.output}` } } const success = await processManager.startService('nginx', binPath, ['-p', nginxPrefix, '-c', configPath], false) @@ -416,8 +424,7 @@ export function registerIpcHandlers(): void { const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') fs.writeFileSync(configPath, content) // Reload Nginx after save - await ipcMain.emit('services:reload', null, 'nginx') - return { success: true } + return await reloadNginx() }) ipcMain.handle('nginx:config:test', async () => { @@ -431,8 +438,8 @@ export function registerIpcHandlers(): void { const binPath = path.join(nginxPrefix, 'nginx.exe') const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') - const success = await processManager.runOnce(binPath, ['-t', '-p', nginxPrefix, '-c', configPath], 'nginx') - return { success, message: success ? 'Configuration test successful' : 'Configuration test failed' } + const result = await processManager.runOnce(binPath, ['-t', '-p', nginxPrefix, '-c', configPath], 'nginx') + return { success: result.success, message: result.success ? 'Configuration test successful' : result.output } } catch (error: any) { return { success: false, message: error.message } } @@ -447,12 +454,50 @@ export function registerIpcHandlers(): void { return '' }) + ipcMain.handle('project:nginx:test', async (_event, host, content) => { + const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${host}.conf`) + let originalContent = '' + if (fs.existsSync(configPath)) { + originalContent = fs.readFileSync(configPath, 'utf8') + } + + try { + // 1. Save new content temporarily + fs.writeFileSync(configPath, content) + + // 2. Run global test + const binDir = path.join(configService.getBasePath(), 'bin', 'nginx') + const nginxVersions = fs.readdirSync(binDir).filter(f => fs.statSync(path.join(binDir, f)).isDirectory()) + const activeVersion = nginxVersions[0] + if (!activeVersion) throw new Error('Nginx sürümü bulunamadı.') + + const nginxPrefix = path.join(binDir, activeVersion) + const binPath = path.join(nginxPrefix, 'nginx.exe') + const globalConfigPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') + + const result = await processManager.runOnce(binPath, ['-t', '-p', nginxPrefix, '-c', globalConfigPath], 'nginx') + + // 3. Restore original content regardless of test result + // (The user must click "Save" to keep it) + if (originalContent) { + fs.writeFileSync(configPath, originalContent) + } else { + fs.unlinkSync(configPath) + } + + return { success: result.success, message: result.success ? 'Configuration test successful' : result.output } + } catch (error: any) { + // Restore on error too + if (originalContent) fs.writeFileSync(configPath, originalContent) + return { success: false, message: error.message } + } + }) + ipcMain.handle('project:nginx:save', async (_event, host, content) => { const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${host}.conf`) fs.writeFileSync(configPath, content) // Reload Nginx after save - await ipcMain.emit('services:reload', null, 'nginx') - return { success: true } + return await reloadNginx() }) // phpMyAdmin diff --git a/src/main/services/ProcessManager.ts b/src/main/services/ProcessManager.ts index ef56874..659f1c8 100644 --- a/src/main/services/ProcessManager.ts +++ b/src/main/services/ProcessManager.ts @@ -64,35 +64,35 @@ export class ProcessManager { return this.logs.get(name) || [] } - async runOnce(binPath: string, args: string[], name?: string): Promise { + async runOnce(binPath: string, args: string[], name?: string): Promise<{ success: boolean; output: string }> { return new Promise((resolve) => { const child = spawn(binPath, args, { stdio: 'pipe', shell: false, windowsHide: true }) + let output = '' child.stdout?.on('data', (data) => { const out = data.toString() + output += out console.log(`[INIT:${name || '?'}] ${out}`) if (name) this.addLog(name, out) }) - child.on('error', (err) => { - console.error(`[INIT ERROR:${name || '?'}] ${err.message}`) - if (name) this.addLog(name, `RunOnce Error: ${err.message}`) - resolve(false) - }) - child.stderr?.on('data', (data) => { const err = data.toString() + output += err console.error(`[INIT ERROR:${name || '?'}] ${err}`) if (name) this.addLog(name, err) }) - child.on('close', (code) => { - resolve(code === 0) - }) child.on('error', (err) => { - console.error('RunOnce error:', err) - if (name) this.addLog(name, `RunOnce Error: ${err.message}`) - resolve(false) + const msg = `RunOnce Error: ${err.message}` + output += msg + console.error(`[INIT ERROR:${name || '?'}] ${msg}`) + if (name) this.addLog(name, msg) + resolve({ success: false, output }) + }) + + child.on('close', (code) => { + resolve({ success: code === 0, output: output.trim() }) }) }) } diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index a1f3f67..73f41ab 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -12,12 +12,13 @@ import { AppBar, Toolbar, IconButton, + Divider, + GlobalStyles, Tooltip, Container, Paper, Chip, Switch, - Divider, Button, Snackbar, Alert, @@ -37,8 +38,7 @@ import { CircularProgress, Stack, Grid, - Avatar, - GlobalStyles + Avatar } from '@mui/material' import { Dashboard as DashboardIcon, @@ -484,7 +484,10 @@ function App(): JSX.Element { text: result.message, icon: result.success ? 'success' : 'error', background: '#1e1e1e', - color: '#fff' + color: '#fff', + customClass: { + htmlContainer: 'nginx-error-container' + } }) } } @@ -569,6 +572,16 @@ function App(): JSX.Element { @@ -1465,6 +1478,31 @@ function App(): JSX.Element { /> +