实现 test 的 vscode webview adapter
This commit is contained in:
parent
1ac997f8df
commit
2e1454281d
@ -19,14 +19,14 @@ const { postMessage, onMessage, isConnected } = useMessageBridge();
|
||||
|
||||
// 监听所有消息
|
||||
onMessage((message) => {
|
||||
console.log('Received:', message.command, message.payload);
|
||||
console.log('Received:', message.command, message.data);
|
||||
});
|
||||
|
||||
// 发送消息
|
||||
const sendPing = () => {
|
||||
postMessage({
|
||||
command: 'ping',
|
||||
payload: { timestamp: Date.now() }
|
||||
data: { timestamp: Date.now() }
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { onUnmounted, ref } from 'vue';
|
||||
|
||||
export interface VSCodeMessage {
|
||||
command: string;
|
||||
payload?: unknown;
|
||||
data?: unknown;
|
||||
callbackId?: string;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
|
||||
## init
|
||||
|
||||
```bash
|
||||
uv sync
|
||||
```
|
||||
|
61
test/src/adapter.ts
Normal file
61
test/src/adapter.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { WebSocket } from 'ws';
|
||||
|
||||
// WebSocket 消息格式
|
||||
export interface WebSocketMessage {
|
||||
command: string;
|
||||
data: any;
|
||||
}
|
||||
|
||||
// 服务器返回的消息格式
|
||||
export interface WebSocketResponse {
|
||||
result?: any;
|
||||
timeCost?: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// 监听器回调类型
|
||||
export type MessageHandler = (message: any) => void;
|
||||
|
||||
export class VSCodeWebViewLike {
|
||||
private ws: WebSocket;
|
||||
private messageHandlers: Set<MessageHandler>;
|
||||
|
||||
constructor(ws: WebSocket) {
|
||||
this.ws = ws;
|
||||
this.messageHandlers = new Set();
|
||||
|
||||
// 监听消息并触发回调
|
||||
this.ws.on('message', (rawData: Buffer | string) => {
|
||||
try {
|
||||
const message: any = JSON.parse(rawData.toString());
|
||||
this.messageHandlers.forEach((handler) => handler(message));
|
||||
} catch (error) {
|
||||
console.error('Failed to parse WebSocket message:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息(模拟 vscode.webview.postMessage)
|
||||
* @param message - 包含 command 和 args 的消息
|
||||
*/
|
||||
postMessage(message: WebSocketMessage): void {
|
||||
if (this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(JSON.stringify(message));
|
||||
} else {
|
||||
console.error('WebSocket is not open, cannot send message');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收消息(模拟 vscode.webview.onDidReceiveMessage)
|
||||
* @param callback - 消息回调
|
||||
* @returns {{ dispose: () => void }} - 可销毁的监听器
|
||||
*/
|
||||
onDidReceiveMessage(callback: MessageHandler): { dispose: () => void } {
|
||||
this.messageHandlers.add(callback);
|
||||
return {
|
||||
dispose: () => this.messageHandlers.delete(callback),
|
||||
};
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ type ConnectionType = 'STDIO' | 'SSE';
|
||||
type McpTransport = StdioClientTransport | SSEClientTransport;
|
||||
|
||||
// 定义命令行参数接口
|
||||
interface MCPOptions {
|
||||
export interface MCPOptions {
|
||||
connectionType: ConnectionType;
|
||||
// STDIO 特定选项
|
||||
command?: string;
|
||||
@ -31,8 +31,8 @@ class MCPClient {
|
||||
|
||||
this.client = new Client(
|
||||
{
|
||||
name: "example-client",
|
||||
version: "1.0.0"
|
||||
name: "openmcp test local client",
|
||||
version: "0.0.1"
|
||||
},
|
||||
{
|
||||
capabilities: {
|
31
test/src/controller/index.ts
Normal file
31
test/src/controller/index.ts
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
import { VSCodeWebViewLike } from '../adapter';
|
||||
import { connect, type MCPOptions } from './connect';
|
||||
|
||||
async function connectHandler(option: MCPOptions, webview: VSCodeWebViewLike) {
|
||||
try {
|
||||
const client = await connect(option);
|
||||
const connectResult = {
|
||||
code: 200,
|
||||
msg: 'connect success'
|
||||
};
|
||||
webview.postMessage({ command: 'connect', data: connectResult });
|
||||
} catch (error) {
|
||||
const connectResult = {
|
||||
code: 500,
|
||||
msg: error
|
||||
};
|
||||
webview.postMessage({ command: 'connect', data: connectResult });
|
||||
}
|
||||
}
|
||||
|
||||
export function messageController(command: string, data: any, webview: VSCodeWebViewLike) {
|
||||
switch (command) {
|
||||
case 'connect':
|
||||
connectHandler(data, webview);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
@ -1,37 +1,35 @@
|
||||
// server/wsServer.ts
|
||||
import WebSocket from 'ws';
|
||||
import { messageController } from './controller';
|
||||
import { VSCodeWebViewLike } from './adapter';
|
||||
|
||||
export interface VSCodeMessage {
|
||||
command: string;
|
||||
payload?: unknown;
|
||||
data?: unknown;
|
||||
callbackId?: string;
|
||||
}
|
||||
|
||||
export type MessageHandler = (message: VSCodeMessage) => void;
|
||||
|
||||
const wss = new WebSocket.Server({ port: 8080 });
|
||||
|
||||
wss.on('connection', (ws) => {
|
||||
// 转换普通消息为 VS Code 格式
|
||||
ws.on('message', (data) => {
|
||||
console.log('receive data from frontend: ' + data.toString());
|
||||
wss.on('connection', ws => {
|
||||
|
||||
// const rawMessage = data.toString();
|
||||
// const vscodeMessage: VSCodeMessage = {
|
||||
// command: 'ws-message',
|
||||
// payload: rawMessage,
|
||||
// callbackId: Math.random().toString(36).slice(2)
|
||||
// };
|
||||
// ws.send(JSON.stringify(vscodeMessage));
|
||||
// 仿造 webview 进行统一接口访问
|
||||
const webview = new VSCodeWebViewLike(ws);
|
||||
|
||||
// 先发送成功建立的消息
|
||||
webview.postMessage({
|
||||
command: 'hello',
|
||||
data: 'hello'
|
||||
});
|
||||
|
||||
// 连接后发送一个消息
|
||||
const vscodeMessage: VSCodeMessage = {
|
||||
command: 'ws-message',
|
||||
payload: {
|
||||
text: 'connection completed'
|
||||
},
|
||||
callbackId: Math.random().toString(36).slice(2)
|
||||
};
|
||||
ws.send(JSON.stringify(vscodeMessage));
|
||||
// 注册消息接受的管线
|
||||
webview.onDidReceiveMessage(message => {
|
||||
try {
|
||||
const { command, data } = message;
|
||||
messageController(command, data, webview);
|
||||
} catch (error) {
|
||||
console.log('backend, meet error during [message], ', error);
|
||||
}
|
||||
});
|
||||
});
|
@ -1,61 +0,0 @@
|
||||
// server/src/wsHandler.ts
|
||||
import { WebSocketServer, WebSocket } from 'ws';
|
||||
import { IMessage } from './types';
|
||||
|
||||
export class WSServer {
|
||||
private wss: WebSocketServer;
|
||||
private clients = new Set<WebSocket>();
|
||||
|
||||
constructor(port: number) {
|
||||
this.wss = new WebSocketServer({ port });
|
||||
this.setupConnection();
|
||||
}
|
||||
|
||||
private setupConnection() {
|
||||
this.wss.on('connection', (ws) => {
|
||||
this.clients.add(ws);
|
||||
console.log('Client connected');
|
||||
|
||||
ws.on('message', (data) => {
|
||||
try {
|
||||
const message: IMessage = JSON.parse(data.toString());
|
||||
this.handleMessage(ws, message);
|
||||
} catch (err) {
|
||||
console.error('Message parse error:', err);
|
||||
}
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
this.clients.delete(ws);
|
||||
console.log('Client disconnected');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private handleMessage(ws: WebSocket, message: IMessage) {
|
||||
console.log('Received:', message);
|
||||
|
||||
// 模拟 VS Code 的 postMessage 响应
|
||||
if (message.type === 'client-message') {
|
||||
this.send(ws, {
|
||||
type: 'server-response',
|
||||
data: {
|
||||
original: message.data,
|
||||
response: 'Message received at ' + new Date().toISOString()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public send(ws: WebSocket, message: IMessage) {
|
||||
if (ws.readyState === ws.OPEN) {
|
||||
ws.send(JSON.stringify(message));
|
||||
}
|
||||
}
|
||||
|
||||
public broadcast(message: IMessage) {
|
||||
this.clients.forEach(client => {
|
||||
this.send(client, message);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user