Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/agentHost/common/agentHostClientResourceChannel.ts
13394 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { decodeBase64, encodeBase64, VSBuffer } from '../../../base/common/buffer.js';
7
import { Event } from '../../../base/common/event.js';
8
import { URI } from '../../../base/common/uri.js';
9
import { IChannel, IServerChannel } from '../../../base/parts/ipc/common/ipc.js';
10
import { IFileService } from '../../files/common/files.js';
11
import { IRemoteFilesystemConnection } from './agentHostFileSystemProvider.js';
12
import {
13
ContentEncoding, type DirectoryEntry, type ResourceDeleteParams, type ResourceDeleteResult,
14
type ResourceListResult, type ResourceMoveParams, type ResourceMoveResult,
15
type ResourceReadResult, type ResourceWriteParams, type ResourceWriteResult,
16
} from './state/protocol/commands.js';
17
18
/**
19
* IPC channel name used for in-process agent-host → renderer reverse
20
* filesystem RPCs. The renderer registers a server channel under this
21
* name on its `MessagePortClient`; the agent host reaches it via
22
* `connection.channelClient.getChannel(name)` on its `UtilityProcessServer`.
23
*
24
* Mirrors the WebSocket reverse-RPC handlers in
25
* {@link RemoteAgentHostProtocolClient._handleReverseRequest}.
26
*/
27
export const AGENT_HOST_CLIENT_RESOURCE_CHANNEL = 'agentHostClientResource';
28
29
/**
30
* Server-side channel implementation handling resource RPCs from the
31
* agent host. Backed by the local {@link IFileService} on the renderer.
32
*/
33
export class AgentHostClientResourceChannel implements IServerChannel {
34
35
constructor(private readonly _fileService: IFileService) { }
36
37
listen<T>(_ctx: unknown, event: string): Event<T> {
38
throw new Error(`No event '${event}' on AgentHostClientResourceChannel`);
39
}
40
41
async call<T>(_ctx: unknown, command: string, arg?: unknown): Promise<T> {
42
const a = (arg ?? {}) as Record<string, unknown>;
43
switch (command) {
44
case 'resourceList': {
45
const stat = await this._fileService.resolve(URI.parse(a.uri as string));
46
if (!stat.isDirectory) {
47
throw new Error(`Resource is not a directory: ${a.uri}`);
48
}
49
const entries: DirectoryEntry[] = (stat.children ?? []).map(c => ({
50
name: c.name,
51
type: c.isDirectory ? 'directory' : 'file',
52
}));
53
const result: ResourceListResult = { entries };
54
return result as T;
55
}
56
case 'resourceRead': {
57
const content = await this._fileService.readFile(URI.parse(a.uri as string));
58
const result: ResourceReadResult = {
59
data: encodeBase64(content.value),
60
encoding: ContentEncoding.Base64,
61
};
62
return result as T;
63
}
64
case 'resourceWrite': {
65
const params = a as unknown as ResourceWriteParams & { createOnly?: boolean };
66
const writeUri = URI.parse(params.uri as unknown as string);
67
const buf = params.encoding === ContentEncoding.Base64
68
? decodeBase64(params.data)
69
: VSBuffer.fromString(params.data);
70
if (params.createOnly) {
71
await this._fileService.createFile(writeUri, buf, { overwrite: false });
72
} else {
73
await this._fileService.writeFile(writeUri, buf);
74
}
75
const result: ResourceWriteResult = {};
76
return result as T;
77
}
78
case 'resourceDelete': {
79
const params = a as unknown as ResourceDeleteParams;
80
await this._fileService.del(URI.parse(params.uri as unknown as string), { recursive: !!params.recursive });
81
const result: ResourceDeleteResult = {};
82
return result as T;
83
}
84
case 'resourceMove': {
85
const params = a as unknown as ResourceMoveParams;
86
await this._fileService.move(URI.parse(params.source as unknown as string), URI.parse(params.destination as unknown as string), !params.failIfExists);
87
const result: ResourceMoveResult = {};
88
return result as T;
89
}
90
}
91
throw new Error(`Unknown command '${command}' on AgentHostClientResourceChannel`);
92
}
93
}
94
95
/**
96
* Wraps an {@link IChannel} (typically obtained from the agent host's
97
* `UtilityProcessServer.getChannel`) into an
98
* {@link IRemoteFilesystemConnection} suitable for registering with
99
* {@link AgentHostClientFileSystemProvider.registerAuthority}.
100
*/
101
export function createAgentHostClientResourceConnection(channel: IChannel): IRemoteFilesystemConnection {
102
return {
103
resourceList: (uri) => channel.call('resourceList', { uri: uri.toString() }) as Promise<ResourceListResult>,
104
resourceRead: (uri) => channel.call('resourceRead', { uri: uri.toString() }) as Promise<ResourceReadResult>,
105
resourceWrite: (params) => channel.call('resourceWrite', { ...params, uri: params.uri.toString() }) as Promise<ResourceWriteResult>,
106
resourceDelete: (params) => channel.call('resourceDelete', { ...params, uri: params.uri.toString() }) as Promise<ResourceDeleteResult>,
107
resourceMove: (params) => channel.call('resourceMove', { ...params, source: params.source.toString(), destination: params.destination.toString() }) as Promise<ResourceMoveResult>,
108
};
109
}
110
111