refactor(arch): 改进 ServiceToken 设计,统一服务获取模式 (#300)

* 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"原则,统一服务访问模式
This commit is contained in:
YHH
2025-12-09 11:07:44 +08:00
committed by GitHub
parent c71a47f2b0
commit 995fa2d514
31 changed files with 1024 additions and 210 deletions

View File

@@ -3,6 +3,7 @@ import * as ReactDOM from 'react-dom';
import * as ReactJSXRuntime from 'react/jsx-runtime';
import { Core, createLogger, Scene } from '@esengine/ecs-framework';
import * as ECSFramework from '@esengine/ecs-framework';
import { getProfilerService } from './services/getService';
// 将 React 暴露到全局,供动态加载的插件使用
// editor-runtime.js 将 React 设为 external需要从全局获取
@@ -207,14 +208,15 @@ function App() {
}, [messageHub, showToast]);
// 监听远程连接状态
// Monitor remote connection status
useEffect(() => {
const checkConnection = () => {
const profilerService = (window as any).__PROFILER_SERVICE__;
const connected = profilerService && profilerService.isConnected();
const profilerService = getProfilerService();
const connected = !!(profilerService && profilerService.isConnected());
setIsRemoteConnected((prevConnected) => {
if (connected !== prevConnected) {
// 状态发生变化
// 状态发生变化 | State has changed
if (connected) {
setStatus(t('header.status.remoteConnected'));
} else {
@@ -246,7 +248,8 @@ function App() {
initRef.current = true;
try {
(window as any).__ECS_FRAMEWORK__ = ECSFramework;
// ECS Framework 已通过 PluginSDKRegistry 暴露到全局
// ECS Framework is exposed globally via PluginSDKRegistry
const editorScene = new Scene();
Core.setScene(editorScene);
@@ -775,7 +778,7 @@ function App() {
const Component = panelDesc.component;
return {
id: panelDesc.id,
title: (panelDesc as any).titleZh && locale === 'zh' ? (panelDesc as any).titleZh : panelDesc.title,
title: panelDesc.titleZh && locale === 'zh' ? panelDesc.titleZh : panelDesc.title,
content: <Component key={`${panelDesc.id}-${pluginUpdateTrigger}`} projectPath={currentProjectPath} />,
closable: panelDesc.closable ?? true
};
@@ -791,7 +794,7 @@ function App() {
const panelDesc = uiRegistry.getPanel(panelId)!;
// 优先使用动态标题,否则使用默认标题
const customTitle = dynamicPanelTitles.get(panelId);
const defaultTitle = (panelDesc as any).titleZh && locale === 'zh' ? (panelDesc as any).titleZh : panelDesc.title;
const defaultTitle = panelDesc.titleZh && locale === 'zh' ? panelDesc.titleZh : panelDesc.title;
// 支持 component 或 render 两种方式
let content: React.ReactNode;

View File

@@ -1,6 +1,7 @@
import { useState, useEffect, useCallback } from 'react';
import { X, BarChart3, Maximize2, Minimize2 } from 'lucide-react';
import { ProfilerService } from '../services/ProfilerService';
import { Core } from '@esengine/ecs-framework';
import { ProfilerServiceToken, type IProfilerService } from '../services/tokens';
import { AdvancedProfiler } from './AdvancedProfiler';
import '../styles/ProfilerWindow.css';
@@ -8,19 +9,19 @@ interface AdvancedProfilerWindowProps {
onClose: () => void;
}
interface WindowWithProfiler extends Window {
__PROFILER_SERVICE__?: ProfilerService;
}
export function AdvancedProfilerWindow({ onClose }: AdvancedProfilerWindowProps) {
const [profilerService, setProfilerService] = useState<ProfilerService | null>(null);
const [profilerService, setProfilerService] = useState<IProfilerService | null>(null);
const [isConnected, setIsConnected] = useState(false);
const [isFullscreen, setIsFullscreen] = useState(false);
useEffect(() => {
const service = (window as WindowWithProfiler).__PROFILER_SERVICE__;
if (service) {
setProfilerService(service);
try {
const service = Core.pluginServices.get(ProfilerServiceToken);
if (service) {
setProfilerService(service);
}
} catch {
// Core 可能还没有初始化
}
}, []);

View File

@@ -40,22 +40,13 @@ import {
AlertTriangle
} from 'lucide-react';
import { Core } from '@esengine/ecs-framework';
import { MessageHub, FileActionRegistry, AssetRegistryService, type FileCreationTemplate } from '@esengine/editor-core';
import { MessageHub, FileActionRegistry, AssetRegistryService, MANAGED_ASSET_DIRECTORIES, type FileCreationTemplate } from '@esengine/editor-core';
import { TauriAPI, DirectoryEntry } from '../api/tauri';
import { SettingsService } from '../services/SettingsService';
import { ContextMenu, ContextMenuItem } from './ContextMenu';
import { PromptDialog } from './PromptDialog';
import '../styles/ContentBrowser.css';
/**
* Directories managed by asset registry (GUID system)
* 被资产注册表GUID 系统)管理的目录
*
* Note: This is duplicated from AssetRegistryService to avoid build dependency issues.
* Keep in sync with MANAGED_ASSET_DIRECTORIES in AssetRegistryService.ts
*/
const MANAGED_ASSET_DIRECTORIES = ['assets', 'scripts', 'scenes'] as const;
interface AssetItem {
name: string;
path: string;

View File

@@ -2,7 +2,7 @@ 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 { ProfilerService } from '../services/ProfilerService';
import { getProfilerService } from '../services/getService';
import '../styles/PortManager.css';
interface PortManagerProps {
@@ -58,7 +58,7 @@ export function PortManager({ onClose }: PortManagerProps) {
const handleStopServer = async () => {
setIsStopping(true);
try {
const profilerService = (window as any).__PROFILER_SERVICE__ as ProfilerService | undefined;
const profilerService = getProfilerService();
if (profilerService) {
await profilerService.manualStopServer();
setIsServerRunning(false);
@@ -73,7 +73,7 @@ export function PortManager({ onClose }: PortManagerProps) {
const handleStartServer = async () => {
setIsStarting(true);
try {
const profilerService = (window as any).__PROFILER_SERVICE__ as ProfilerService | undefined;
const profilerService = getProfilerService();
if (profilerService) {
await profilerService.manualStartServer();
await new Promise((resolve) => setTimeout(resolve, 500));

View File

@@ -1,9 +1,10 @@
import { useState, useEffect } from 'react';
import { Activity, Cpu, Layers, Package, Wifi, WifiOff, Maximize2, Pause, Play, BarChart3 } from 'lucide-react';
import { ProfilerService, ProfilerData } from '../services/ProfilerService';
import type { ProfilerData } from '../services/tokens';
import { SettingsService } from '../services/SettingsService';
import { Core } from '@esengine/ecs-framework';
import { MessageHub } from '@esengine/editor-core';
import { getProfilerService } from '../services/getService';
import '../styles/ProfilerDockPanel.css';
export function ProfilerDockPanel() {
@@ -32,7 +33,7 @@ export function ProfilerDockPanel() {
}, []);
useEffect(() => {
const profilerService = (window as any).__PROFILER_SERVICE__ as ProfilerService | undefined;
const profilerService = getProfilerService();
if (!profilerService) {
console.warn('[ProfilerDockPanel] ProfilerService not available - plugin may be disabled');

View File

@@ -3,6 +3,7 @@ import { Core } from '@esengine/ecs-framework';
import { Activity, BarChart3, Clock, Cpu, RefreshCw, Pause, Play, X, Wifi, WifiOff, Server, Search, Table2, TreePine } from 'lucide-react';
import { ProfilerService } from '../services/ProfilerService';
import { SettingsService } from '../services/SettingsService';
import { getProfilerService } from '../services/getService';
import '../styles/ProfilerWindow.css';
interface SystemPerformanceData {
@@ -59,7 +60,7 @@ export function ProfilerWindow({ onClose }: ProfilerWindowProps) {
// Check ProfilerService connection status
useEffect(() => {
const profilerService = (window as any).__PROFILER_SERVICE__ as ProfilerService | undefined;
const profilerService = getProfilerService();
if (!profilerService) {
return;
@@ -186,7 +187,7 @@ export function ProfilerWindow({ onClose }: ProfilerWindowProps) {
useEffect(() => {
if (dataSource !== 'remote') return;
const profilerService = (window as any).__PROFILER_SERVICE__ as ProfilerService | undefined;
const profilerService = getProfilerService();
if (!profilerService) {
console.warn('[ProfilerWindow] ProfilerService not available');

View File

@@ -8,7 +8,8 @@ import {
Eye, Star, Lock, Settings, Filter, Folder, Sun, Cloud, Mountain, Flag,
SquareStack, FolderPlus
} from 'lucide-react';
import { ProfilerService, RemoteEntity } from '../services/ProfilerService';
import type { RemoteEntity } from '../services/tokens';
import { getProfilerService } from '../services/getService';
import { confirm } from '@tauri-apps/plugin-dialog';
import { CreateEntityCommand, DeleteEntityCommand, ReparentEntityCommand, DropPosition } from '../application/commands/entity';
import '../styles/SceneHierarchy.css';
@@ -264,7 +265,7 @@ export function SceneHierarchy({ entityStore, messageHub, commandManager, isProf
// Subscribe to remote entity data from ProfilerService
useEffect(() => {
const profilerService = (window as any).__PROFILER_SERVICE__ as ProfilerService | undefined;
const profilerService = getProfilerService();
if (!profilerService) {
return;
@@ -444,7 +445,7 @@ export function SceneHierarchy({ entityStore, messageHub, commandManager, isProf
const handleRemoteEntityClick = (entity: RemoteEntity) => {
setSelectedIds(new Set([entity.id]));
const profilerService = (window as any).__PROFILER_SERVICE__ as ProfilerService | undefined;
const profilerService = getProfilerService();
if (profilerService) {
profilerService.requestEntityDetails(entity.id);
}

View File

@@ -1,18 +1,10 @@
import React, { useState, useEffect, useMemo, useCallback } from 'react';
import { X, Search, Folder, FolderOpen, File, Image, FileText, Music, Video, Database, AlertTriangle } from 'lucide-react';
import { Core } from '@esengine/ecs-framework';
import { ProjectService, AssetRegistryService } from '@esengine/editor-core';
import { ProjectService, AssetRegistryService, MANAGED_ASSET_DIRECTORIES } from '@esengine/editor-core';
import { TauriFileSystemService } from '../../services/TauriFileSystemService';
import './AssetPickerDialog.css';
/**
* Directories managed by asset registry (GUID system)
* Only files in these directories can be selected
*
* Note: Keep in sync with MANAGED_ASSET_DIRECTORIES in AssetRegistryService.ts
*/
const MANAGED_ASSET_DIRECTORIES = ['assets', 'scripts', 'scenes'] as const;
interface AssetPickerDialogProps {
isOpen: boolean;
onClose: () => void;

View File

@@ -4,18 +4,15 @@
*/
import React, { useState, useEffect, useRef, useCallback } from 'react';
/**
* 碰撞层配置接口(用于获取自定义层名称)
*/
interface CollisionLayerConfigAPI {
getLayers(): Array<{ name: string }>;
addListener(callback: () => void): void;
removeListener(callback: () => void): void;
}
import { Core } from '@esengine/ecs-framework';
import {
CollisionLayerConfigToken,
type ICollisionLayerConfig
} from '@esengine/physics-rapier2d';
/**
* 默认层名称(当 CollisionLayerConfig 不可用时使用)
* Default layer names (used when CollisionLayerConfig is unavailable)
*/
const DEFAULT_LAYER_NAMES = [
'Default', 'Player', 'Enemy', 'Projectile',
@@ -24,25 +21,18 @@ const DEFAULT_LAYER_NAMES = [
'Layer12', 'Layer13', 'Layer14', 'Layer15',
];
let cachedConfig: CollisionLayerConfigAPI | null = null;
/**
* 尝试获取 CollisionLayerConfig 实例
* Try to get CollisionLayerConfig instance
*/
function getCollisionConfig(): CollisionLayerConfigAPI | null {
if (cachedConfig) return cachedConfig;
function getCollisionConfig(): ICollisionLayerConfig | undefined {
try {
// 动态导入以避免循环依赖
const physicsModule = (window as any).__PHYSICS_RAPIER2D__;
if (physicsModule?.CollisionLayerConfig) {
cachedConfig = physicsModule.CollisionLayerConfig.getInstance();
return cachedConfig;
}
return Core.pluginServices.get(CollisionLayerConfigToken);
} catch {
// 忽略错误
// Core 可能还没有初始化
// Core might not be initialized yet
return undefined;
}
return null;
}
interface CollisionLayerFieldProps {

View File

@@ -1,4 +1,6 @@
import { Core } from '@esengine/ecs-framework';
import { ComponentData } from './types';
import { ProfilerServiceToken, type IProfilerService } from '../../services/tokens';
export function formatNumber(value: number, decimalPlaces: number): string {
if (decimalPlaces < 0) {
@@ -10,13 +12,21 @@ export function formatNumber(value: number, decimalPlaces: number): string {
return value.toFixed(decimalPlaces);
}
export interface ProfilerService {
requestEntityDetails(entityId: number): void;
subscribe(callback: () => void): () => void;
}
export function getProfilerService(): ProfilerService | undefined {
return (window as any).__PROFILER_SERVICE__;
/**
* 获取 ProfilerService 实例
* Get ProfilerService instance
*
* 使用 ServiceToken 从 Core.pluginServices 获取服务。
* Uses ServiceToken to get service from Core.pluginServices.
*/
export function getProfilerService(): IProfilerService | undefined {
try {
return Core.pluginServices.get(ProfilerServiceToken);
} catch {
// Core 可能还没有初始化
// Core might not be initialized yet
return undefined;
}
}
export function isComponentData(value: unknown): value is ComponentData {

View File

@@ -1,14 +1,22 @@
import { useMemo } from 'react';
import * as LucideIcons from 'lucide-react';
type LucideIconName = keyof typeof LucideIcons;
/**
* 动态获取 Lucide 图标组件
* Dynamically get Lucide icon component by name
*
* @param iconName - 图标名称(如 'Package', 'Settings'
* @param fallback - 找不到时的回退组件
* @returns Lucide 图标组件
*/
export function useDynamicIcon(iconName?: string, fallback?: React.ComponentType) {
return useMemo(() => {
if (!iconName) {
return fallback || LucideIcons.Package;
}
// 动态图标查找需要使用 any因为 lucide-react 的类型定义不支持动态索引
// Dynamic icon lookup requires any, as lucide-react types don't support dynamic indexing
const IconComponent = (LucideIcons as any)[iconName];
return IconComponent || fallback || LucideIcons.Package;
}, [iconName, fallback]);

View File

@@ -1,23 +1,52 @@
/**
* ProfilerService Hook
*
* 通过 ServiceToken 获取 ProfilerService 实例。
* Get ProfilerService instance via ServiceToken.
*/
import { useEffect, useState } from 'react';
import { Core } from '@esengine/ecs-framework';
import { ProfilerServiceToken, type IProfilerService } from '../services/tokens';
export interface ProfilerService {
connect(port: number): void;
disconnect(): void;
isConnected(): boolean;
requestEntityList(): void;
requestEntityDetails(entityId: number): void;
}
export function useProfilerService(): ProfilerService | undefined {
const [service, setService] = useState<ProfilerService | undefined>(() => {
return (window as any).__PROFILER_SERVICE__;
/**
* 获取 ProfilerService 实例的 Hook
* Hook to get ProfilerService instance
*
* 使用 ServiceToken 从 Core.pluginServices 获取服务,
* 提供类型安全的服务访问。
*
* Uses ServiceToken to get service from Core.pluginServices,
* providing type-safe service access.
*
* @returns ProfilerService 实例,如果未注册则返回 undefined
*/
export function useProfilerService(): IProfilerService | undefined {
const [service, setService] = useState<IProfilerService | undefined>(() => {
try {
return Core.pluginServices.get(ProfilerServiceToken);
} catch {
// Core 可能还没有初始化
// Core might not be initialized yet
return undefined;
}
});
useEffect(() => {
// 定期检查服务是否可用(处理服务延迟注册的情况)
// Periodically check if service is available (handles delayed service registration)
const checkService = () => {
const newService = (window as any).__PROFILER_SERVICE__;
if (newService !== service) {
setService(newService);
try {
const newService = Core.pluginServices.get(ProfilerServiceToken);
if (newService !== service) {
setService(newService);
}
} catch {
// Core 可能还没有初始化
// Core might not be initialized yet
if (service !== undefined) {
setService(undefined);
}
}
};

View File

@@ -4,6 +4,7 @@
*/
import type { ServiceContainer } from '@esengine/ecs-framework';
import { Core } from '@esengine/ecs-framework';
import type {
IPlugin,
IEditorModuleLoader,
@@ -12,6 +13,7 @@ import type {
} from '@esengine/editor-core';
import { MessageHub, SettingsRegistry } from '@esengine/editor-core';
import { ProfilerService } from '../../services/ProfilerService';
import { ProfilerServiceToken } from '../../services/tokens';
/**
* Profiler 编辑器模块
@@ -87,15 +89,21 @@ class ProfilerEditorModule implements IEditorModuleLoader {
});
this.profilerService = new ProfilerService();
(window as any).__PROFILER_SERVICE__ = this.profilerService;
// 使用 ServiceToken 注册服务(类型安全)
// Register service using ServiceToken (type-safe)
Core.pluginServices.register(ProfilerServiceToken, this.profilerService);
}
async uninstall(): Promise<void> {
// 从服务注册表注销
// Unregister from service registry
Core.pluginServices.unregister(ProfilerServiceToken);
if (this.profilerService) {
this.profilerService.destroy();
this.profilerService = null;
}
delete (window as any).__PROFILER_SERVICE__;
}
getMenuItems(): MenuItemDescriptor[] {

View File

@@ -1,29 +1,13 @@
import { invoke } from '@tauri-apps/api/core';
import { SettingsService } from './SettingsService';
import { LogLevel } from '@esengine/ecs-framework';
export interface SystemPerformanceData {
name: string;
executionTime: number;
entityCount: number;
averageTime: number;
percentage: number;
}
export interface RemoteEntity {
id: number;
name: string;
enabled: boolean;
active: boolean;
activeInHierarchy: boolean;
componentCount: number;
componentTypes: string[];
parentId: number | null;
childIds: number[];
depth: number;
tag: number;
updateOrder: number;
}
import type {
IProfilerService,
ProfilerData,
SystemPerformanceData,
RemoteEntity,
AdvancedProfilerDataPayload
} from './tokens';
export interface RemoteComponentDetail {
typeName: string;
@@ -45,29 +29,10 @@ export interface RemoteEntityDetails {
parentName: string | null;
}
export interface ProfilerData {
totalFrameTime: number;
systems: SystemPerformanceData[];
entityCount: number;
componentCount: number;
fps: number;
entities?: RemoteEntity[];
}
type ProfilerDataListener = (data: ProfilerData) => void;
/**
* 高级性能数据结构(用于高级性能分析器)
*/
export interface AdvancedProfilerDataPayload {
advancedProfiler?: any;
performance?: any;
systems?: any;
}
type AdvancedProfilerDataListener = (data: AdvancedProfilerDataPayload) => void;
export class ProfilerService {
export class ProfilerService implements IProfilerService {
private ws: WebSocket | null = null;
private isServerRunning = false;
private wsPort: number;

View File

@@ -0,0 +1,36 @@
/**
* 服务获取辅助函数
* Service getter helper functions
*
* 提供类型安全的服务获取,避免直接访问全局变量。
* Provides type-safe service access, avoiding direct global variable access.
*/
import { Core } from '@esengine/ecs-framework';
import type { ServiceToken } from '@esengine/engine-core';
import { ProfilerServiceToken, type IProfilerService } from './tokens';
/**
* 安全获取插件服务
* Safely get plugin service
*
* 在 Core 未初始化时返回 undefined 而非抛出异常。
* Returns undefined instead of throwing when Core is not initialized.
*/
export function getPluginService<T>(token: ServiceToken<T>): T | undefined {
try {
return Core.pluginServices.get(token);
} catch {
// Core 可能还没有初始化
// Core might not be initialized yet
return undefined;
}
}
/**
* 获取 ProfilerService 实例
* Get ProfilerService instance
*/
export function getProfilerService(): IProfilerService | undefined {
return getPluginService(ProfilerServiceToken);
}

View File

@@ -0,0 +1,114 @@
/**
* 编辑器服务令牌
* Editor Service Tokens
*
* 遵循"谁定义接口,谁导出 Token"原则。
* 这些服务定义在 editor-app 中,所以 Token 也在这里定义。
*
* Following "who defines interface, who exports Token" principle.
* These services are defined in editor-app, so Tokens are also defined here.
*/
import { createServiceToken } from '@esengine/engine-core';
// ============================================================================
// Profiler Data Types (定义在这里以避免循环依赖)
// ============================================================================
export interface SystemPerformanceData {
name: string;
executionTime: number;
entityCount: number;
averageTime: number;
percentage: number;
}
export interface RemoteEntity {
id: number;
name: string;
enabled: boolean;
active: boolean;
activeInHierarchy: boolean;
componentCount: number;
componentTypes: string[];
parentId: number | null;
childIds: number[];
depth: number;
tag: number;
updateOrder: number;
}
export interface ProfilerData {
totalFrameTime: number;
systems: SystemPerformanceData[];
entityCount: number;
componentCount: number;
fps: number;
entities?: RemoteEntity[];
}
/**
* 高级性能数据结构(用于高级性能分析器)
* Advanced profiler data structure
*/
export interface AdvancedProfilerDataPayload {
advancedProfiler?: any;
performance?: any;
systems?: any;
}
// ============================================================================
// Profiler Service Token
// ============================================================================
/**
* ProfilerService 接口(用于类型检查)
* ProfilerService interface (for type checking)
*
* 提供远程性能分析功能,包括:
* - WebSocket 连接管理
* - 性能数据收集和分发
* - 远程日志接收
*
* Provides remote profiling capabilities including:
* - WebSocket connection management
* - Performance data collection and distribution
* - Remote log reception
*/
export interface IProfilerService {
/** 检查是否已连接 | Check if connected */
isConnected(): boolean;
/** 检查服务器是否运行 | Check if server is running */
isServerActive(): boolean;
/** 手动启动服务器 | Manually start server */
manualStartServer(): Promise<void>;
/** 手动停止服务器 | Manually stop server */
manualStopServer(): Promise<void>;
/** 订阅数据更新 | Subscribe to data updates */
subscribe(callback: (data: ProfilerData) => void): () => void;
/** 订阅高级数据更新 | Subscribe to advanced data updates */
subscribeAdvanced(callback: (data: AdvancedProfilerDataPayload) => void): () => void;
/** 请求实体详情 | Request entity details */
requestEntityDetails(entityId: number): void;
/** 请求高级性能分析数据 | Request advanced profiler data */
requestAdvancedProfilerData(): void;
/** 设置选中的函数 | Set selected function */
setProfilerSelectedFunction(functionName: string | null): void;
/** 销毁服务 | Destroy service */
destroy(): void;
}
/**
* ProfilerService 的服务令牌
* Service token for ProfilerService
*/
export const ProfilerServiceToken = createServiceToken<IProfilerService>('profilerService');