264 lines
9.2 KiB
TypeScript
264 lines
9.2 KiB
TypeScript
import { ToolDefinition, ToolResponse, ToolExecutor } from '../types';
|
||
|
||
export class BroadcastTools implements ToolExecutor {
|
||
private listeners: Map<string, Function[]> = new Map();
|
||
private messageLog: Array<{ message: string; data: any; timestamp: number }> = [];
|
||
|
||
constructor() {
|
||
this.setupBroadcastListeners();
|
||
}
|
||
|
||
getTools(): ToolDefinition[] {
|
||
return [
|
||
{
|
||
name: 'get_broadcast_log',
|
||
description: 'Get recent broadcast messages log',
|
||
inputSchema: {
|
||
type: 'object',
|
||
properties: {
|
||
limit: {
|
||
type: 'number',
|
||
description: 'Number of recent messages to return',
|
||
default: 50
|
||
},
|
||
messageType: {
|
||
type: 'string',
|
||
description: 'Filter by message type (optional)'
|
||
}
|
||
}
|
||
}
|
||
},
|
||
{
|
||
name: 'listen_broadcast',
|
||
description: 'Start listening for specific broadcast messages',
|
||
inputSchema: {
|
||
type: 'object',
|
||
properties: {
|
||
messageType: {
|
||
type: 'string',
|
||
description: 'Message type to listen for'
|
||
}
|
||
},
|
||
required: ['messageType']
|
||
}
|
||
},
|
||
{
|
||
name: 'stop_listening',
|
||
description: 'Stop listening for specific broadcast messages',
|
||
inputSchema: {
|
||
type: 'object',
|
||
properties: {
|
||
messageType: {
|
||
type: 'string',
|
||
description: 'Message type to stop listening for'
|
||
}
|
||
},
|
||
required: ['messageType']
|
||
}
|
||
},
|
||
{
|
||
name: 'clear_broadcast_log',
|
||
description: 'Clear the broadcast messages log',
|
||
inputSchema: {
|
||
type: 'object',
|
||
properties: {}
|
||
}
|
||
},
|
||
{
|
||
name: 'get_active_listeners',
|
||
description: 'Get list of active broadcast listeners',
|
||
inputSchema: {
|
||
type: 'object',
|
||
properties: {}
|
||
}
|
||
}
|
||
];
|
||
}
|
||
|
||
async execute(toolName: string, args: any): Promise<ToolResponse> {
|
||
switch (toolName) {
|
||
case 'get_broadcast_log':
|
||
return await this.getBroadcastLog(args.limit, args.messageType);
|
||
case 'listen_broadcast':
|
||
return await this.listenBroadcast(args.messageType);
|
||
case 'stop_listening':
|
||
return await this.stopListening(args.messageType);
|
||
case 'clear_broadcast_log':
|
||
return await this.clearBroadcastLog();
|
||
case 'get_active_listeners':
|
||
return await this.getActiveListeners();
|
||
default:
|
||
throw new Error(`Unknown tool: ${toolName}`);
|
||
}
|
||
}
|
||
|
||
private setupBroadcastListeners(): void {
|
||
// 设置预定义的重要广播消息监听
|
||
const importantMessages = [
|
||
'build-worker:ready',
|
||
'build-worker:closed',
|
||
'scene:ready',
|
||
'scene:close',
|
||
'scene:light-probe-edit-mode-changed',
|
||
'scene:light-probe-bounding-box-edit-mode-changed',
|
||
'asset-db:ready',
|
||
'asset-db:close',
|
||
'asset-db:asset-add',
|
||
'asset-db:asset-change',
|
||
'asset-db:asset-delete'
|
||
];
|
||
|
||
importantMessages.forEach(messageType => {
|
||
this.addBroadcastListener(messageType);
|
||
});
|
||
}
|
||
|
||
private addBroadcastListener(messageType: string): void {
|
||
const listener = (data: any) => {
|
||
this.messageLog.push({
|
||
message: messageType,
|
||
data: data,
|
||
timestamp: Date.now()
|
||
});
|
||
|
||
// 保持日志大小在合理范围内
|
||
if (this.messageLog.length > 1000) {
|
||
this.messageLog = this.messageLog.slice(-500);
|
||
}
|
||
|
||
console.log(`[Broadcast] ${messageType}:`, data);
|
||
};
|
||
|
||
if (!this.listeners.has(messageType)) {
|
||
this.listeners.set(messageType, []);
|
||
}
|
||
this.listeners.get(messageType)!.push(listener);
|
||
|
||
// 注册 Editor 消息监听 - 暂时注释掉,Editor.Message API可能不支持
|
||
// Editor.Message.on(messageType, listener);
|
||
console.log(`[BroadcastTools] Added listener for ${messageType} (simulated)`);
|
||
}
|
||
|
||
private removeBroadcastListener(messageType: string): void {
|
||
const listeners = this.listeners.get(messageType);
|
||
if (listeners) {
|
||
listeners.forEach(listener => {
|
||
// Editor.Message.off(messageType, listener);
|
||
console.log(`[BroadcastTools] Removed listener for ${messageType} (simulated)`);
|
||
});
|
||
this.listeners.delete(messageType);
|
||
}
|
||
}
|
||
|
||
private async getBroadcastLog(limit: number = 50, messageType?: string): Promise<ToolResponse> {
|
||
return new Promise((resolve) => {
|
||
let filteredLog = this.messageLog;
|
||
|
||
if (messageType) {
|
||
filteredLog = this.messageLog.filter(entry => entry.message === messageType);
|
||
}
|
||
|
||
const recentLog = filteredLog.slice(-limit).map(entry => ({
|
||
...entry,
|
||
timestamp: new Date(entry.timestamp).toISOString()
|
||
}));
|
||
|
||
resolve({
|
||
success: true,
|
||
data: {
|
||
log: recentLog,
|
||
count: recentLog.length,
|
||
totalCount: filteredLog.length,
|
||
filter: messageType || 'all',
|
||
message: 'Broadcast log retrieved successfully'
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
private async listenBroadcast(messageType: string): Promise<ToolResponse> {
|
||
return new Promise((resolve) => {
|
||
try {
|
||
if (!this.listeners.has(messageType)) {
|
||
this.addBroadcastListener(messageType);
|
||
resolve({
|
||
success: true,
|
||
data: {
|
||
messageType: messageType,
|
||
message: `Started listening for broadcast: ${messageType}`
|
||
}
|
||
});
|
||
} else {
|
||
resolve({
|
||
success: true,
|
||
data: {
|
||
messageType: messageType,
|
||
message: `Already listening for broadcast: ${messageType}`
|
||
}
|
||
});
|
||
}
|
||
} catch (err: any) {
|
||
resolve({ success: false, error: err.message });
|
||
}
|
||
});
|
||
}
|
||
|
||
private async stopListening(messageType: string): Promise<ToolResponse> {
|
||
return new Promise((resolve) => {
|
||
try {
|
||
if (this.listeners.has(messageType)) {
|
||
this.removeBroadcastListener(messageType);
|
||
resolve({
|
||
success: true,
|
||
data: {
|
||
messageType: messageType,
|
||
message: `Stopped listening for broadcast: ${messageType}`
|
||
}
|
||
});
|
||
} else {
|
||
resolve({
|
||
success: true,
|
||
data: {
|
||
messageType: messageType,
|
||
message: `Was not listening for broadcast: ${messageType}`
|
||
}
|
||
});
|
||
}
|
||
} catch (err: any) {
|
||
resolve({ success: false, error: err.message });
|
||
}
|
||
});
|
||
}
|
||
|
||
private async clearBroadcastLog(): Promise<ToolResponse> {
|
||
return new Promise((resolve) => {
|
||
const previousCount = this.messageLog.length;
|
||
this.messageLog = [];
|
||
resolve({
|
||
success: true,
|
||
data: {
|
||
clearedCount: previousCount,
|
||
message: 'Broadcast log cleared successfully'
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
private async getActiveListeners(): Promise<ToolResponse> {
|
||
return new Promise((resolve) => {
|
||
const activeListeners = Array.from(this.listeners.keys()).map(messageType => ({
|
||
messageType: messageType,
|
||
listenerCount: this.listeners.get(messageType)?.length || 0
|
||
}));
|
||
|
||
resolve({
|
||
success: true,
|
||
data: {
|
||
listeners: activeListeners,
|
||
count: activeListeners.length,
|
||
message: 'Active listeners retrieved successfully'
|
||
}
|
||
});
|
||
});
|
||
}
|
||
} |