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