实现 test 的 vscode webview adapter
This commit is contained in:
parent
1ac997f8df
commit
2e1454281d
@ -19,14 +19,14 @@ const { postMessage, onMessage, isConnected } = useMessageBridge();
|
|||||||
|
|
||||||
// 监听所有消息
|
// 监听所有消息
|
||||||
onMessage((message) => {
|
onMessage((message) => {
|
||||||
console.log('Received:', message.command, message.payload);
|
console.log('Received:', message.command, message.data);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
const sendPing = () => {
|
const sendPing = () => {
|
||||||
postMessage({
|
postMessage({
|
||||||
command: 'ping',
|
command: 'ping',
|
||||||
payload: { timestamp: Date.now() }
|
data: { timestamp: Date.now() }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { onUnmounted, ref } from 'vue';
|
|||||||
|
|
||||||
export interface VSCodeMessage {
|
export interface VSCodeMessage {
|
||||||
command: string;
|
command: string;
|
||||||
payload?: unknown;
|
data?: unknown;
|
||||||
callbackId?: string;
|
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;
|
type McpTransport = StdioClientTransport | SSEClientTransport;
|
||||||
|
|
||||||
// 定义命令行参数接口
|
// 定义命令行参数接口
|
||||||
interface MCPOptions {
|
export interface MCPOptions {
|
||||||
connectionType: ConnectionType;
|
connectionType: ConnectionType;
|
||||||
// STDIO 特定选项
|
// STDIO 特定选项
|
||||||
command?: string;
|
command?: string;
|
||||||
@ -31,8 +31,8 @@ class MCPClient {
|
|||||||
|
|
||||||
this.client = new Client(
|
this.client = new Client(
|
||||||
{
|
{
|
||||||
name: "example-client",
|
name: "openmcp test local client",
|
||||||
version: "1.0.0"
|
version: "0.0.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
capabilities: {
|
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
|
// server/wsServer.ts
|
||||||
import WebSocket from 'ws';
|
import WebSocket from 'ws';
|
||||||
|
import { messageController } from './controller';
|
||||||
|
import { VSCodeWebViewLike } from './adapter';
|
||||||
|
|
||||||
export interface VSCodeMessage {
|
export interface VSCodeMessage {
|
||||||
command: string;
|
command: string;
|
||||||
payload?: unknown;
|
data?: unknown;
|
||||||
callbackId?: string;
|
callbackId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MessageHandler = (message: VSCodeMessage) => void;
|
export type MessageHandler = (message: VSCodeMessage) => void;
|
||||||
|
|
||||||
const wss = new WebSocket.Server({ port: 8080 });
|
const wss = new WebSocket.Server({ port: 8080 });
|
||||||
|
|
||||||
wss.on('connection', (ws) => {
|
wss.on('connection', ws => {
|
||||||
// 转换普通消息为 VS Code 格式
|
|
||||||
ws.on('message', (data) => {
|
|
||||||
console.log('receive data from frontend: ' + data.toString());
|
|
||||||
|
|
||||||
// const rawMessage = data.toString();
|
// 仿造 webview 进行统一接口访问
|
||||||
// const vscodeMessage: VSCodeMessage = {
|
const webview = new VSCodeWebViewLike(ws);
|
||||||
// command: 'ws-message',
|
|
||||||
// payload: rawMessage,
|
// 先发送成功建立的消息
|
||||||
// callbackId: Math.random().toString(36).slice(2)
|
webview.postMessage({
|
||||||
// };
|
command: 'hello',
|
||||||
// ws.send(JSON.stringify(vscodeMessage));
|
data: 'hello'
|
||||||
});
|
});
|
||||||
|
|
||||||
// 连接后发送一个消息
|
// 注册消息接受的管线
|
||||||
const vscodeMessage: VSCodeMessage = {
|
webview.onDidReceiveMessage(message => {
|
||||||
command: 'ws-message',
|
try {
|
||||||
payload: {
|
const { command, data } = message;
|
||||||
text: 'connection completed'
|
messageController(command, data, webview);
|
||||||
},
|
} catch (error) {
|
||||||
callbackId: Math.random().toString(36).slice(2)
|
console.log('backend, meet error during [message], ', error);
|
||||||
};
|
}
|
||||||
ws.send(JSON.stringify(vscodeMessage));
|
});
|
||||||
});
|
});
|
@ -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