Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/git/src/ipc/ipcServer.ts
3320 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 { Disposable } from 'vscode';
7
import { ITerminalEnvironmentProvider } from '../terminal';
8
import { toDisposable } from '../util';
9
import * as path from 'path';
10
import * as http from 'http';
11
import * as os from 'os';
12
import * as fs from 'fs';
13
import * as crypto from 'crypto';
14
15
function getIPCHandlePath(id: string): string {
16
if (process.platform === 'win32') {
17
return `\\\\.\\pipe\\vscode-git-${id}-sock`;
18
}
19
20
if (process.platform !== 'darwin' && process.env['XDG_RUNTIME_DIR']) {
21
return path.join(process.env['XDG_RUNTIME_DIR'] as string, `vscode-git-${id}.sock`);
22
}
23
24
return path.join(os.tmpdir(), `vscode-git-${id}.sock`);
25
}
26
27
export interface IIPCHandler {
28
handle(request: any): Promise<any>;
29
}
30
31
export async function createIPCServer(context?: string): Promise<IPCServer> {
32
const server = http.createServer();
33
const hash = crypto.createHash('sha256');
34
35
if (!context) {
36
const buffer = await new Promise<Buffer>((c, e) => crypto.randomBytes(20, (err, buf) => err ? e(err) : c(buf)));
37
hash.update(buffer);
38
} else {
39
hash.update(context);
40
}
41
42
const ipcHandlePath = getIPCHandlePath(hash.digest('hex').substring(0, 10));
43
44
if (process.platform !== 'win32') {
45
try {
46
await fs.promises.unlink(ipcHandlePath);
47
} catch {
48
// noop
49
}
50
}
51
52
return new Promise((c, e) => {
53
try {
54
server.on('error', err => e(err));
55
server.listen(ipcHandlePath);
56
c(new IPCServer(server, ipcHandlePath));
57
} catch (err) {
58
e(err);
59
}
60
});
61
}
62
63
export interface IIPCServer extends Disposable {
64
readonly ipcHandlePath: string | undefined;
65
getEnv(): { [key: string]: string };
66
registerHandler(name: string, handler: IIPCHandler): Disposable;
67
}
68
69
export class IPCServer implements IIPCServer, ITerminalEnvironmentProvider, Disposable {
70
71
private handlers = new Map<string, IIPCHandler>();
72
get ipcHandlePath(): string { return this._ipcHandlePath; }
73
74
constructor(private server: http.Server, private _ipcHandlePath: string) {
75
this.server.on('request', this.onRequest.bind(this));
76
}
77
78
registerHandler(name: string, handler: IIPCHandler): Disposable {
79
this.handlers.set(`/${name}`, handler);
80
return toDisposable(() => this.handlers.delete(name));
81
}
82
83
private onRequest(req: http.IncomingMessage, res: http.ServerResponse): void {
84
if (!req.url) {
85
console.warn(`Request lacks url`);
86
return;
87
}
88
89
const handler = this.handlers.get(req.url);
90
91
if (!handler) {
92
console.warn(`IPC handler for ${req.url} not found`);
93
return;
94
}
95
96
const chunks: Buffer[] = [];
97
req.on('data', d => chunks.push(d));
98
req.on('end', () => {
99
const request = JSON.parse(Buffer.concat(chunks).toString('utf8'));
100
handler.handle(request).then(result => {
101
res.writeHead(200);
102
res.end(JSON.stringify(result));
103
}, () => {
104
res.writeHead(500);
105
res.end();
106
});
107
});
108
}
109
110
getEnv(): { [key: string]: string } {
111
return { VSCODE_GIT_IPC_HANDLE: this.ipcHandlePath };
112
}
113
114
getTerminalEnv(): { [key: string]: string } {
115
return { VSCODE_GIT_IPC_HANDLE: this.ipcHandlePath };
116
}
117
118
dispose(): void {
119
this.handlers.clear();
120
this.server.close();
121
122
if (this._ipcHandlePath && process.platform !== 'win32') {
123
fs.unlinkSync(this._ipcHandlePath);
124
}
125
}
126
}
127
128