* refactor(arch): 移除全局变量,使用 ServiceToken 模式 - 创建 PluginServiceRegistry 类,提供类型安全的服务注册/获取 - 添加 ProfilerServiceToken 和 CollisionLayerConfigToken - 重构所有 __PROFILER_SERVICE__ 全局变量访问为 getProfilerService() - 重构 __PHYSICS_RAPIER2D__ 全局变量访问为 CollisionLayerConfigToken - 在 Core 类添加 pluginServices 静态属性 - 添加 getService.ts 辅助模块简化服务获取 这是 ServiceToken 模式重构的第一阶段,移除了最常用的两个全局变量。 后续可继续应用到其他模块(Camera/Audio 等)。 * refactor(arch): 改进 ServiceToken 设计,移除重复常量 - tokens.ts: 从 engine-core 导入 createServiceToken(符合规范) - tokens.ts: Token 使用接口 IProfilerService 而非具体类 - 移除 AssetPickerDialog 和 ContentBrowser 中重复的 MANAGED_ASSET_DIRECTORIES - 统一从 editor-core 导入 MANAGED_ASSET_DIRECTORIES * fix(type): 修复 IProfilerService 接口与实现类型不匹配 - 将 ProfilerData 等数据类型移到 tokens.ts 以避免循环依赖 - ProfilerService 显式实现 IProfilerService 接口 - 更新使用方使用 IProfilerService 接口类型而非具体类 * refactor(type): 移除类型重导出,改进类型安全 - 删除 ProfilerService.ts 中的类型重导出,消费方直接从 tokens.ts 导入 - PanelDescriptor 接口添加 titleZh 属性,移除 App.tsx 中的 as any - 改进 useDynamicIcon.ts 的类型安全,使用正确的 Record 类型 * refactor(arch): 为模块添加 ServiceToken 支持 - Material System: 创建 tokens.ts,定义 IMaterialManager 接口和 MaterialManagerToken - Audio: 创建预留 tokens.ts 文件,为未来 AudioManager 服务扩展做准备 - Camera: 创建预留 tokens.ts 文件,为未来 CameraManager 服务扩展做准备 遵循"谁定义接口,谁导出 Token"原则,统一服务访问模式
166 lines
6.7 KiB
TypeScript
166 lines
6.7 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { invoke } from '@tauri-apps/api/core';
|
|
import { X, Server, WifiOff, Wifi } from 'lucide-react';
|
|
import { SettingsService } from '../services/SettingsService';
|
|
import { getProfilerService } from '../services/getService';
|
|
import '../styles/PortManager.css';
|
|
|
|
interface PortManagerProps {
|
|
onClose: () => void;
|
|
}
|
|
|
|
export function PortManager({ onClose }: PortManagerProps) {
|
|
const [isServerRunning, setIsServerRunning] = useState(false);
|
|
const [serverPort, setServerPort] = useState<string>('8080');
|
|
const [isChecking, setIsChecking] = useState(false);
|
|
const [isStopping, setIsStopping] = useState(false);
|
|
const [isStarting, setIsStarting] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const settings = SettingsService.getInstance();
|
|
const savedPort = settings.get('profiler.port', 8080);
|
|
console.log('[PortManager] Initial port from settings:', savedPort);
|
|
setServerPort(String(savedPort));
|
|
|
|
const handleSettingsChange = ((event: CustomEvent) => {
|
|
console.log('[PortManager] settings:changed event received:', event.detail);
|
|
const newPort = event.detail['profiler.port'];
|
|
if (newPort !== undefined) {
|
|
console.log('[PortManager] Updating port to:', newPort);
|
|
setServerPort(String(newPort));
|
|
}
|
|
}) as EventListener;
|
|
|
|
window.addEventListener('settings:changed', handleSettingsChange);
|
|
|
|
return () => {
|
|
window.removeEventListener('settings:changed', handleSettingsChange);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
checkServerStatus();
|
|
}, []);
|
|
|
|
const checkServerStatus = async () => {
|
|
setIsChecking(true);
|
|
try {
|
|
const status = await invoke<boolean>('get_profiler_status');
|
|
setIsServerRunning(status);
|
|
} catch (error) {
|
|
console.error('[PortManager] Failed to check server status:', error);
|
|
setIsServerRunning(false);
|
|
} finally {
|
|
setIsChecking(false);
|
|
}
|
|
};
|
|
|
|
const handleStopServer = async () => {
|
|
setIsStopping(true);
|
|
try {
|
|
const profilerService = getProfilerService();
|
|
if (profilerService) {
|
|
await profilerService.manualStopServer();
|
|
setIsServerRunning(false);
|
|
}
|
|
} catch (error) {
|
|
console.error('[PortManager] Failed to stop server:', error);
|
|
} finally {
|
|
setIsStopping(false);
|
|
}
|
|
};
|
|
|
|
const handleStartServer = async () => {
|
|
setIsStarting(true);
|
|
try {
|
|
const profilerService = getProfilerService();
|
|
if (profilerService) {
|
|
await profilerService.manualStartServer();
|
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
await checkServerStatus();
|
|
}
|
|
} catch (error) {
|
|
console.error('[PortManager] Failed to start server:', error);
|
|
} finally {
|
|
setIsStarting(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="port-manager-overlay" onClick={onClose}>
|
|
<div className="port-manager" onClick={(e) => e.stopPropagation()}>
|
|
<div className="port-manager-header">
|
|
<div className="port-manager-title">
|
|
<Server size={20} />
|
|
<h2>Port Manager</h2>
|
|
</div>
|
|
<button className="port-manager-close" onClick={onClose} title="Close">
|
|
<X size={20} />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="port-manager-content">
|
|
<div className="port-section">
|
|
<h3>Profiler Server</h3>
|
|
<div className="port-info">
|
|
<div className="port-item">
|
|
<span className="port-label">Status:</span>
|
|
<span className={`port-status ${isServerRunning ? 'running' : 'stopped'}`}>
|
|
{isChecking ? 'Checking...' : isServerRunning ? 'Running' : 'Stopped'}
|
|
</span>
|
|
</div>
|
|
{isServerRunning && (
|
|
<div className="port-item">
|
|
<span className="port-label">Port:</span>
|
|
<span className="port-value">{serverPort}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{isServerRunning && (
|
|
<div className="port-actions">
|
|
<button
|
|
className="action-btn danger"
|
|
onClick={handleStopServer}
|
|
disabled={isStopping}
|
|
>
|
|
<WifiOff size={16} />
|
|
<span>{isStopping ? 'Stopping...' : 'Stop Server'}</span>
|
|
</button>
|
|
</div>
|
|
)}
|
|
|
|
{!isServerRunning && (
|
|
<>
|
|
<div className="port-actions">
|
|
<button
|
|
className="action-btn primary"
|
|
onClick={handleStartServer}
|
|
disabled={isStarting}
|
|
>
|
|
<Wifi size={16} />
|
|
<span>{isStarting ? 'Starting...' : 'Start Server'}</span>
|
|
</button>
|
|
</div>
|
|
<div className="port-hint">
|
|
<p>No server is currently running.</p>
|
|
<p className="hint-text">Click "Start Server" to start the profiler server.</p>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
<div className="port-tips">
|
|
<h4>Tips</h4>
|
|
<ul>
|
|
<li>Use this when the Profiler server port is stuck and cannot be restarted</li>
|
|
<li>The server will automatically stop when the Profiler window is closed</li>
|
|
<li>Current configured port: {serverPort}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|