feat: implement process management service and initial dashboard UI for MultiPHP
This commit is contained in:
+13
-6
@@ -95,17 +95,24 @@ export function registerIpcHandlers(): void {
|
||||
return { success, message: success ? 'Nginx başlatıldı.' : 'Nginx devreye alınamadı (Hata loglarını kontrol edin).' }
|
||||
}
|
||||
|
||||
if (serviceName === 'php') {
|
||||
const binPath = findExecutable(binDir, 'php-cgi.exe')
|
||||
if (!binPath) return { success: false, message: 'PHP executable bulunamadı. Lütfen en az bir sürüm indirin.' }
|
||||
if (serviceName.startsWith('php')) {
|
||||
const versionMatch = serviceName.match(/^php:(.+)$/)
|
||||
const phpVersion = versionMatch ? versionMatch[1] : null
|
||||
const phpId = phpVersion ? `php-${phpVersion}` : null
|
||||
|
||||
const phpDir = phpId ? path.join(binDir, phpId) : binDir
|
||||
const binPath = findExecutable(phpDir, 'php-cgi.exe')
|
||||
|
||||
if (!binPath) return { success: false, message: `${phpVersion || ''} PHP executable bulunamadı. Lütfen indirin.` }
|
||||
|
||||
const phpPort = phpVersion ? portMappingService.getPhpPort(phpVersion) : settings.phpPort
|
||||
const extDir = path.join(path.dirname(binPath), 'ext')
|
||||
const configPath = await configService.generateConfig('php.ini.template', 'php.ini', {
|
||||
const configPath = await configService.generateConfig('php.ini.template', `php_${phpVersion || 'default'}.ini`, {
|
||||
EXT_DIR: extDir
|
||||
})
|
||||
|
||||
const success = await processManager.startService('php', binPath, ['-b', `127.0.0.1:${settings.phpPort}`, '-c', configPath], false)
|
||||
return { success, message: success ? 'PHP başlatıldı.' : 'PHP devreye alınamadı (Hata loglarını kontrol edin).' }
|
||||
const success = await processManager.startService(serviceName, binPath, ['-b', `127.0.0.1:${phpPort}`, '-c', configPath], false)
|
||||
return { success, message: success ? `${phpVersion || ''} PHP başlatıldı.` : `${phpVersion || ''} PHP devreye alınamadı.` }
|
||||
}
|
||||
|
||||
if (serviceName === 'mysql') {
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { app } from 'electron'
|
||||
import axios from 'axios'
|
||||
import { portMappingService } from './PortMappingService'
|
||||
|
||||
export interface PhpVersion {
|
||||
id: string
|
||||
@@ -9,6 +10,7 @@ export interface PhpVersion {
|
||||
url: string
|
||||
status: 'available' | 'downloading' | 'installed'
|
||||
progress: number
|
||||
port?: number
|
||||
}
|
||||
|
||||
export class PhpManagerService {
|
||||
@@ -136,7 +138,11 @@ export class PhpManagerService {
|
||||
await this.fetchAvailableVersions()
|
||||
}
|
||||
this.refreshInstalledStatus()
|
||||
return this.versions
|
||||
// Add ports for all versions
|
||||
return this.versions.map(v => ({
|
||||
...v,
|
||||
port: portMappingService.getPhpPort(v.version)
|
||||
}))
|
||||
}
|
||||
|
||||
updateProgress(id: string, progress: number, status: PhpVersion['status'] = 'downloading') {
|
||||
|
||||
@@ -170,11 +170,14 @@ export class ProcessManager {
|
||||
}
|
||||
|
||||
getStatuses(): Record<string, string> {
|
||||
return {
|
||||
nginx: this.isServiceRunning('nginx') ? 'running' : 'stopped',
|
||||
php: this.isServiceRunning('php') ? 'running' : 'stopped',
|
||||
mysql: this.isServiceRunning('mysql') ? 'running' : 'stopped'
|
||||
const statuses: Record<string, string> = {}
|
||||
for (const name of Array.from(this.processes.keys())) {
|
||||
statuses[name] = 'running'
|
||||
}
|
||||
// Ensure defaults are present if stopped
|
||||
if (!statuses['nginx']) statuses['nginx'] = 'stopped'
|
||||
if (!statuses['mysql']) statuses['mysql'] = 'stopped'
|
||||
return statuses
|
||||
}
|
||||
|
||||
private async checkErrorLogs(name: string) {
|
||||
|
||||
+54
-40
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import React, { useState, useEffect, Fragment } from 'react'
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
@@ -243,11 +243,11 @@ function App(): JSX.Element {
|
||||
|
||||
const interval = setInterval(() => {
|
||||
fetchStatus()
|
||||
fetchProjects()
|
||||
fetchPhpVersions()
|
||||
fetchMySqlVersions()
|
||||
fetchNginxVersions()
|
||||
}, 5000)
|
||||
// fetchProjects() // Reduced frequency for these
|
||||
// fetchPhpVersions()
|
||||
// fetchMySqlVersions()
|
||||
// fetchNginxVersions()
|
||||
}, 3000)
|
||||
|
||||
let logInterval: NodeJS.Timeout | null = null
|
||||
if (logDialogOpen && selectedService) {
|
||||
@@ -284,15 +284,15 @@ function App(): JSX.Element {
|
||||
}
|
||||
}
|
||||
|
||||
const handleToggleService = async (service: keyof ServiceStatus) => {
|
||||
const handleToggleService = async (service: string) => {
|
||||
if (!window.api) return
|
||||
|
||||
const isStarting = status[service] === 'stopped'
|
||||
const isStarting = (status[service] || 'stopped') === 'stopped'
|
||||
if (isStarting) {
|
||||
setStatus(prev => ({ ...prev, [service]: 'starting' }))
|
||||
}
|
||||
|
||||
const result = status[service] === 'running'
|
||||
const result = (status[service] || 'stopped') === 'running'
|
||||
? await window.api.stopService(service)
|
||||
: await window.api.startService(service)
|
||||
|
||||
@@ -328,29 +328,36 @@ function App(): JSX.Element {
|
||||
|
||||
const handleStartAll = async () => {
|
||||
if (!window.api) return
|
||||
const services: (keyof ServiceStatus)[] = ['nginx', 'php', 'mysql']
|
||||
for (const s of services) {
|
||||
if (status[s] === 'stopped') {
|
||||
setStatus(prev => ({ ...prev, [s]: 'starting' }))
|
||||
}
|
||||
const criticalServices = ['nginx', 'mysql']
|
||||
for (const s of criticalServices) {
|
||||
if (status[s] === 'stopped') setStatus(prev => ({ ...prev, [s]: 'starting' }))
|
||||
}
|
||||
for (const s of services) {
|
||||
if (status[s] !== 'running') {
|
||||
await window.api.startService(s)
|
||||
}
|
||||
|
||||
// Also starting each installed PHP version
|
||||
const phpToStart = phpVersions.filter(v => v.status === 'installed').map(v => `php:${v.version}`)
|
||||
for (const s of phpToStart) {
|
||||
if ((status[s] || 'stopped') === 'stopped') setStatus(prev => ({ ...prev, [s]: 'starting' }))
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
...criticalServices.filter(s => status[s] !== 'running').map(s => window.api?.startService(s)),
|
||||
...phpToStart.filter(s => (status[s] || 'stopped') !== 'running').map(s => window.api?.startService(s))
|
||||
])
|
||||
|
||||
fetchStatus()
|
||||
setNotification({ open: true, message: 'Tüm servisler başlatıldı.', severity: 'success' })
|
||||
}
|
||||
|
||||
const handleStopAll = async () => {
|
||||
if (!window.api) return
|
||||
const services: (keyof ServiceStatus)[] = ['nginx', 'php', 'mysql']
|
||||
for (const s of services) {
|
||||
if (status[s] === 'running') {
|
||||
await window.api.stopService(s)
|
||||
}
|
||||
}
|
||||
const criticalServices = ['nginx', 'mysql']
|
||||
const phpToStop = Object.keys(status).filter(s => s.startsWith('php:') && (status[s] === 'running' || status[s] === 'starting'))
|
||||
|
||||
await Promise.all([
|
||||
...criticalServices.filter(s => status[s] === 'running' || status[s] === 'starting').map(s => window.api?.stopService(s)),
|
||||
...phpToStop.map(s => window.api?.stopService(s))
|
||||
])
|
||||
|
||||
fetchStatus()
|
||||
setNotification({ open: true, message: 'Tüm servisler durduruldu.', severity: 'success' })
|
||||
}
|
||||
@@ -753,22 +760,29 @@ function App(): JSX.Element {
|
||||
/>
|
||||
</Box>
|
||||
</ListItem>
|
||||
<Divider variant="inset" />
|
||||
<ListItem sx={{ py: 1.5 }}>
|
||||
<ListItemIcon><PhpIcon color="primary" /></ListItemIcon>
|
||||
<ListItemText primary="PHP FastCGI" secondary={`Port: ${settings.phpPort}`} />
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<IconButton size="small" onClick={() => handleOpenLogs('php')} title="Logları Görüntüle">
|
||||
<TerminalIcon fontSize="small" />
|
||||
</IconButton>
|
||||
{getStatusChip(status.php)}
|
||||
<Switch
|
||||
checked={status.php === 'running' || status.php === 'starting'}
|
||||
onChange={() => handleToggleService('php')}
|
||||
disabled={status.php === 'starting'}
|
||||
/>
|
||||
</Box>
|
||||
</ListItem>
|
||||
{installedPhpVersions.map(v => (
|
||||
<Fragment key={v.id}>
|
||||
<Divider variant="inset" />
|
||||
<ListItem sx={{ py: 1.5 }}>
|
||||
<ListItemIcon><PhpIcon color="primary" /></ListItemIcon>
|
||||
<ListItemText
|
||||
primary={`PHP ${v.version} FastCGI`}
|
||||
secondary={`Port: ${v.port || '?'}`}
|
||||
/>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<IconButton size="small" onClick={() => handleOpenLogs(`php:${v.version}`)} title="Logları Görüntüle">
|
||||
<TerminalIcon fontSize="small" />
|
||||
</IconButton>
|
||||
{getStatusChip(status[`php:${v.version}`] || 'stopped')}
|
||||
<Switch
|
||||
checked={(status[`php:${v.version}`] || 'stopped') === 'running' || status[`php:${v.version}`] === 'starting'}
|
||||
onChange={() => handleToggleService(`php:${v.version}`)}
|
||||
disabled={status[`php:${v.version}`] === 'starting'}
|
||||
/>
|
||||
</Box>
|
||||
</ListItem>
|
||||
</Fragment>
|
||||
))}
|
||||
<Divider variant="inset" />
|
||||
<ListItem sx={{ py: 1.5 }}>
|
||||
<ListItemIcon><DbIcon color="primary" /></ListItemIcon>
|
||||
|
||||
Reference in New Issue
Block a user