@opensumi/ide-core-node 2.21.13 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/bootstrap/app.d.ts +2 -0
- package/lib/bootstrap/app.d.ts.map +1 -1
- package/lib/bootstrap/app.js +3 -3
- package/lib/bootstrap/app.js.map +1 -1
- package/lib/bootstrap/shell-path.js +1 -1
- package/lib/bootstrap/shell-path.js.map +1 -1
- package/lib/common-module/common.server.js.map +1 -1
- package/lib/common-module/credential.server.d.ts.map +1 -1
- package/lib/common-module/credential.server.js +3 -1
- package/lib/common-module/credential.server.js.map +1 -1
- package/lib/common-module/crypto.server.js.map +1 -1
- package/lib/common-module/index.js.map +1 -1
- package/lib/connection.d.ts +1 -0
- package/lib/connection.d.ts.map +1 -1
- package/lib/connection.js +3 -7
- package/lib/connection.js.map +1 -1
- package/lib/hash-calculate/hash-calculate.contribution.js.map +1 -1
- package/lib/logger/node-logger.d.ts +1 -1
- package/lib/logger/node-logger.d.ts.map +1 -1
- package/lib/logger/node-logger.js.map +1 -1
- package/lib/types.d.ts +4 -2
- package/lib/types.d.ts.map +1 -1
- package/package.json +8 -7
- package/src/bootstrap/app.ts +252 -0
- package/src/bootstrap/index.ts +2 -0
- package/src/bootstrap/inner-providers.ts +42 -0
- package/src/bootstrap/shell-path.ts +116 -0
- package/src/common-module/common.server.ts +9 -0
- package/src/common-module/credential.server.ts +92 -0
- package/src/common-module/crypto.server.ts +50 -0
- package/src/common-module/index.ts +49 -0
- package/src/connection.ts +142 -0
- package/src/hash-calculate/hash-calculate.contribution.ts +19 -0
- package/src/index.ts +12 -0
- package/src/logger/node-logger.ts +68 -0
- package/src/node-module.ts +3 -0
- package/src/types.ts +143 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Injector } from '@opensumi/di';
|
|
2
|
+
import {
|
|
3
|
+
IReporter,
|
|
4
|
+
DefaultReporter,
|
|
5
|
+
IReporterService,
|
|
6
|
+
ReporterService,
|
|
7
|
+
ReporterMetadata,
|
|
8
|
+
REPORT_HOST,
|
|
9
|
+
} from '@opensumi/ide-core-common';
|
|
10
|
+
import {
|
|
11
|
+
HashCalculateServiceImpl,
|
|
12
|
+
IHashCalculateService,
|
|
13
|
+
} from '@opensumi/ide-core-common/lib/hash-calculate/hash-calculate';
|
|
14
|
+
|
|
15
|
+
import { INodeLogger, NodeLogger } from '../logger/node-logger';
|
|
16
|
+
|
|
17
|
+
export function injectInnerProviders(injector: Injector) {
|
|
18
|
+
injector.addProviders(
|
|
19
|
+
{
|
|
20
|
+
token: INodeLogger,
|
|
21
|
+
useClass: NodeLogger,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
token: IReporter,
|
|
25
|
+
useClass: DefaultReporter,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
token: IReporterService,
|
|
29
|
+
useClass: ReporterService,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
token: ReporterMetadata,
|
|
33
|
+
useValue: {
|
|
34
|
+
host: REPORT_HOST.NODE,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
token: IHashCalculateService,
|
|
39
|
+
useClass: HashCalculateServiceImpl,
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
|
|
3
|
+
import { isWindows, stripAnsi } from '@opensumi/ide-core-common';
|
|
4
|
+
|
|
5
|
+
// 成功过一次后,取 PATH 的超时时间
|
|
6
|
+
const MAX_WAIT_AFTER_SUCCESS = 3 * 1000;
|
|
7
|
+
|
|
8
|
+
// Shell 执行的最大超时时间
|
|
9
|
+
// 即使 getShellPath 已经返回,在这个时间之内执行成功后还是会更新缓存,供下一次调用使用
|
|
10
|
+
const SHELL_TIMEOUT = 30 * 1000;
|
|
11
|
+
|
|
12
|
+
let shellPath = process.env.PATH;
|
|
13
|
+
const isJestTest = process.env.IS_JEST_TEST;
|
|
14
|
+
let updating: Promise<void> | undefined;
|
|
15
|
+
|
|
16
|
+
// 至少成功过一次
|
|
17
|
+
let hasSuccess = false;
|
|
18
|
+
|
|
19
|
+
// 某些用户的配置初始化时间较长,提前开始
|
|
20
|
+
// 测试环境下不执行,让测试快一点
|
|
21
|
+
if (!isJestTest) {
|
|
22
|
+
updateShellPath();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseEnv(env: string) {
|
|
26
|
+
env = env.split('_SHELL_ENV_DELIMITER_')[1];
|
|
27
|
+
const ret: { [key: string]: string } = {};
|
|
28
|
+
const lines = stripAnsi(env).split('\n').filter(Boolean);
|
|
29
|
+
for (const line of lines) {
|
|
30
|
+
const [key, ...values] = line.split('=');
|
|
31
|
+
ret[key] = values.join('=');
|
|
32
|
+
}
|
|
33
|
+
return ret;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function createUpdateShellPathPromise(): Promise<void> {
|
|
37
|
+
let pid: number;
|
|
38
|
+
const timer = setTimeout(() => {
|
|
39
|
+
if (pid) {
|
|
40
|
+
try {
|
|
41
|
+
process.kill(pid);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
// ignore
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}, SHELL_TIMEOUT);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
shellPath = await new Promise((resolve, reject) => {
|
|
50
|
+
const buf: Buffer[] = [];
|
|
51
|
+
const proc = spawn(
|
|
52
|
+
'/bin/bash',
|
|
53
|
+
['-ilc', 'echo -n "_SHELL_ENV_DELIMITER_"; env; echo -n "_SHELL_ENV_DELIMITER_"; exit;'],
|
|
54
|
+
{
|
|
55
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
56
|
+
detached: true, // 在有些场景 zsh 会卡住, detached 后正常
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
proc.on('error', (err) => {
|
|
60
|
+
reject(err);
|
|
61
|
+
});
|
|
62
|
+
proc.stdout.on('data', (chunk) => {
|
|
63
|
+
buf.push(chunk);
|
|
64
|
+
});
|
|
65
|
+
proc.stderr.on('data', (chunk) => {
|
|
66
|
+
// reject(chunk.toString());
|
|
67
|
+
});
|
|
68
|
+
proc.on('close', () => {
|
|
69
|
+
clearTimeout(timer);
|
|
70
|
+
|
|
71
|
+
if (buf.length) {
|
|
72
|
+
resolve(parseEnv(Buffer.concat(buf).toString()).PATH);
|
|
73
|
+
} else {
|
|
74
|
+
reject(new Error('Fail to get env.'));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
proc.unref();
|
|
78
|
+
pid = proc.pid;
|
|
79
|
+
});
|
|
80
|
+
hasSuccess = true;
|
|
81
|
+
} catch (err) {
|
|
82
|
+
// console.error('shell path error:', err);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function updateShellPath(): Promise<void> {
|
|
87
|
+
// 确保每次只有一个进程运行
|
|
88
|
+
// macOS 实测多个进程同时运行时,耗时成倍增加 <1s -> 6-10s
|
|
89
|
+
if (!updating) {
|
|
90
|
+
updating = createUpdateShellPathPromise().finally(() => {
|
|
91
|
+
updating = undefined;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return updating;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function getShellPath(): Promise<string | undefined> {
|
|
98
|
+
if (isWindows) {
|
|
99
|
+
return process.env['PATH'];
|
|
100
|
+
}
|
|
101
|
+
// 触发一次更新
|
|
102
|
+
await Promise.race([
|
|
103
|
+
updateShellPath(),
|
|
104
|
+
new Promise<void>((resolve) => {
|
|
105
|
+
// 第一次等待时间长一些,尽量拿到正确的 PATH
|
|
106
|
+
setTimeout(
|
|
107
|
+
() => {
|
|
108
|
+
resolve(undefined);
|
|
109
|
+
},
|
|
110
|
+
hasSuccess ? MAX_WAIT_AFTER_SUCCESS : SHELL_TIMEOUT,
|
|
111
|
+
);
|
|
112
|
+
}),
|
|
113
|
+
]);
|
|
114
|
+
// 不管有没有更新成功,都返回当前的最新结果
|
|
115
|
+
return shellPath;
|
|
116
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Injectable } from '@opensumi/di';
|
|
2
|
+
import { ICommonServer, OS, OperatingSystem } from '@opensumi/ide-core-common';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
5
|
+
export class CommonServer implements ICommonServer {
|
|
6
|
+
async getBackendOS(): Promise<OperatingSystem> {
|
|
7
|
+
return OS.type();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
import { Injectable, Autowired } from '@opensumi/di';
|
|
3
|
+
import { IChunkedPassword, INativeCredentialService, isWindows } from '@opensumi/ide-core-common';
|
|
4
|
+
|
|
5
|
+
import { AppConfig } from '../types';
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class CredentialService implements INativeCredentialService {
|
|
9
|
+
private static readonly MAX_PASSWORD_LENGTH = 2500;
|
|
10
|
+
private static readonly PASSWORD_CHUNK_SIZE = CredentialService.MAX_PASSWORD_LENGTH - 100;
|
|
11
|
+
|
|
12
|
+
@Autowired(AppConfig)
|
|
13
|
+
private readonly appConfig: AppConfig;
|
|
14
|
+
|
|
15
|
+
async setPassword(service: string, account: string, password: string): Promise<void> {
|
|
16
|
+
const keytar = await this.withKeytar();
|
|
17
|
+
if (isWindows && password.length > CredentialService.MAX_PASSWORD_LENGTH) {
|
|
18
|
+
let index = 0;
|
|
19
|
+
let chunk = 0;
|
|
20
|
+
let hasNextChunk = true;
|
|
21
|
+
while (hasNextChunk) {
|
|
22
|
+
const passwordChunk = password.substring(index, index + CredentialService.PASSWORD_CHUNK_SIZE);
|
|
23
|
+
index += CredentialService.PASSWORD_CHUNK_SIZE;
|
|
24
|
+
hasNextChunk = password.length - index > 0;
|
|
25
|
+
|
|
26
|
+
const content: IChunkedPassword = {
|
|
27
|
+
content: passwordChunk,
|
|
28
|
+
hasNextChunk,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
await keytar.setPassword(service, chunk ? `${account}-${chunk}` : account, JSON.stringify(content));
|
|
32
|
+
chunk++;
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
await keytar.setPassword(service, account, password);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async deletePassword(service: string, account: string) {
|
|
40
|
+
const keytar = await this.withKeytar();
|
|
41
|
+
const didDelete = await keytar.deletePassword(service, account);
|
|
42
|
+
return didDelete;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async getPassword(service: string, account: string) {
|
|
46
|
+
const keytar = await this.withKeytar();
|
|
47
|
+
const password = await keytar.getPassword(service, account);
|
|
48
|
+
if (password) {
|
|
49
|
+
try {
|
|
50
|
+
let { content, hasNextChunk }: IChunkedPassword = JSON.parse(password);
|
|
51
|
+
if (!content || !hasNextChunk) {
|
|
52
|
+
return password;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let index = 1;
|
|
56
|
+
while (hasNextChunk) {
|
|
57
|
+
const nextChunk = await keytar.getPassword(service, `${account}-${index++}`);
|
|
58
|
+
const result: IChunkedPassword = JSON.parse(nextChunk!);
|
|
59
|
+
content += result.content;
|
|
60
|
+
hasNextChunk = result.hasNextChunk;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return content;
|
|
64
|
+
} catch (_e) {
|
|
65
|
+
return password;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async findPassword(service: string) {
|
|
72
|
+
const keytar = await this.withKeytar();
|
|
73
|
+
const password = await keytar.findPassword(service);
|
|
74
|
+
if (password) {
|
|
75
|
+
return password;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async findCredentials(service: string): Promise<Array<{ account: string; password: string }>> {
|
|
81
|
+
const keytar = await this.withKeytar();
|
|
82
|
+
return keytar.findCredentials(service);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private async withKeytar(): Promise<typeof import('keytar')> {
|
|
86
|
+
if (this.appConfig.disableKeytar) {
|
|
87
|
+
throw new Error('keytar has been disabled via --disable-keytar option');
|
|
88
|
+
}
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
return await import('keytar');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
|
|
3
|
+
import { Injectable } from '@opensumi/di';
|
|
4
|
+
import { INativeCryptoService } from '@opensumi/ide-core-common';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class CryptoService implements INativeCryptoService {
|
|
8
|
+
private static SECRET_KEY = 'CryptoService';
|
|
9
|
+
private static IV_LENGTH = 16;
|
|
10
|
+
private static SALT_LENGTH = 64;
|
|
11
|
+
private static TAG_LENGTH = 16;
|
|
12
|
+
private static ALGORITHM = 'aes-256-gcm';
|
|
13
|
+
private static TAG_POSITION: number = CryptoService.SALT_LENGTH + CryptoService.IV_LENGTH;
|
|
14
|
+
private static ENCRYPTED_POSITION: number = CryptoService.TAG_POSITION + CryptoService.TAG_LENGTH;
|
|
15
|
+
|
|
16
|
+
private getKey(salt: string | Buffer) {
|
|
17
|
+
return crypto.pbkdf2Sync(CryptoService.SECRET_KEY, salt, 100000, 32, 'sha512');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async encrypt(password: string) {
|
|
21
|
+
const iv = crypto.randomBytes(CryptoService.IV_LENGTH);
|
|
22
|
+
const salt = crypto.randomBytes(CryptoService.SALT_LENGTH);
|
|
23
|
+
|
|
24
|
+
const key = this.getKey(salt);
|
|
25
|
+
|
|
26
|
+
const cipher = crypto.createCipheriv(CryptoService.ALGORITHM, key, iv);
|
|
27
|
+
const encrypted = Buffer.concat([cipher.update(password, 'utf8'), cipher.final()]);
|
|
28
|
+
|
|
29
|
+
const tag = (cipher as any).getAuthTag();
|
|
30
|
+
|
|
31
|
+
return Buffer.concat([salt, iv, tag, encrypted]).toString('hex');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async decrypt(hash: string) {
|
|
35
|
+
const stringValue = Buffer.from(String(hash), 'hex');
|
|
36
|
+
|
|
37
|
+
const salt = stringValue.slice(0, CryptoService.SALT_LENGTH);
|
|
38
|
+
const iv = stringValue.slice(CryptoService.SALT_LENGTH, CryptoService.TAG_POSITION);
|
|
39
|
+
const tag = stringValue.slice(CryptoService.TAG_POSITION, CryptoService.ENCRYPTED_POSITION);
|
|
40
|
+
const encrypted = stringValue.slice(CryptoService.ENCRYPTED_POSITION);
|
|
41
|
+
|
|
42
|
+
const key = this.getKey(salt);
|
|
43
|
+
|
|
44
|
+
const decipher = crypto.createDecipheriv(CryptoService.ALGORITHM, key, iv);
|
|
45
|
+
|
|
46
|
+
(decipher as any).setAuthTag(tag);
|
|
47
|
+
|
|
48
|
+
return decipher.update(encrypted) + decipher.final('utf8');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Injectable } from '@opensumi/di';
|
|
2
|
+
import {
|
|
3
|
+
ICommonServer,
|
|
4
|
+
CommonServerPath,
|
|
5
|
+
INativeCredentialService,
|
|
6
|
+
KeytarServicePath,
|
|
7
|
+
INativeCryptoService,
|
|
8
|
+
CryptoServicePath,
|
|
9
|
+
} from '@opensumi/ide-core-common';
|
|
10
|
+
|
|
11
|
+
import { HashCalculateContribution } from '../hash-calculate/hash-calculate.contribution';
|
|
12
|
+
import { NodeModule } from '../node-module';
|
|
13
|
+
|
|
14
|
+
import { CommonServer } from './common.server';
|
|
15
|
+
import { CredentialService } from './credential.server';
|
|
16
|
+
import { CryptoService } from './crypto.server';
|
|
17
|
+
|
|
18
|
+
@Injectable()
|
|
19
|
+
export class ServerCommonModule extends NodeModule {
|
|
20
|
+
providers = [
|
|
21
|
+
HashCalculateContribution,
|
|
22
|
+
{
|
|
23
|
+
token: ICommonServer,
|
|
24
|
+
useClass: CommonServer,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
token: INativeCredentialService,
|
|
28
|
+
useClass: CredentialService,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
token: INativeCryptoService,
|
|
32
|
+
useClass: CryptoService,
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
backServices = [
|
|
36
|
+
{
|
|
37
|
+
servicePath: CommonServerPath,
|
|
38
|
+
token: ICommonServer,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
servicePath: KeytarServicePath,
|
|
42
|
+
token: INativeCredentialService,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
servicePath: CryptoServicePath,
|
|
46
|
+
token: INativeCryptoService,
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import net from 'net';
|
|
3
|
+
|
|
4
|
+
import ws from 'ws';
|
|
5
|
+
|
|
6
|
+
import { Injector, InstanceCreator, ClassCreator, FactoryCreator } from '@opensumi/di';
|
|
7
|
+
import { WSChannel, initRPCService, RPCServiceCenter } from '@opensumi/ide-connection';
|
|
8
|
+
import { createWebSocketConnection } from '@opensumi/ide-connection/lib/common/message';
|
|
9
|
+
import {
|
|
10
|
+
WebSocketServerRoute,
|
|
11
|
+
WebSocketHandler,
|
|
12
|
+
CommonChannelHandler,
|
|
13
|
+
commonChannelPathHandler,
|
|
14
|
+
createSocketConnection,
|
|
15
|
+
} from '@opensumi/ide-connection/lib/node';
|
|
16
|
+
|
|
17
|
+
import { INodeLogger } from './logger/node-logger';
|
|
18
|
+
import { NodeModule } from './node-module';
|
|
19
|
+
import { IServerAppOpts } from './types';
|
|
20
|
+
|
|
21
|
+
export { RPCServiceCenter };
|
|
22
|
+
|
|
23
|
+
export function createServerConnection2(
|
|
24
|
+
server: http.Server,
|
|
25
|
+
injector,
|
|
26
|
+
modulesInstances,
|
|
27
|
+
handlerArr: WebSocketHandler[],
|
|
28
|
+
serverAppOpts: IServerAppOpts,
|
|
29
|
+
) {
|
|
30
|
+
const logger = injector.get(INodeLogger);
|
|
31
|
+
const socketRoute = new WebSocketServerRoute(server, logger);
|
|
32
|
+
const channelHandler = new CommonChannelHandler('/service', logger, {
|
|
33
|
+
pathMatchOptions: serverAppOpts.pathMatchOptions,
|
|
34
|
+
wsServerOptions: serverAppOpts.wsServerOptions,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// 事件由 connection 的时机来触发
|
|
38
|
+
commonChannelPathHandler.register('RPCService', {
|
|
39
|
+
handler: (connection: WSChannel, clientId: string) => {
|
|
40
|
+
logger.log(`New RPC connection ${clientId}`);
|
|
41
|
+
|
|
42
|
+
const serviceCenter = new RPCServiceCenter(undefined, logger);
|
|
43
|
+
const serviceChildInjector = bindModuleBackService(injector, modulesInstances, serviceCenter, clientId);
|
|
44
|
+
|
|
45
|
+
const serverConnection = createWebSocketConnection(connection);
|
|
46
|
+
connection.messageConnection = serverConnection;
|
|
47
|
+
serviceCenter.setConnection(serverConnection);
|
|
48
|
+
|
|
49
|
+
connection.onClose(() => {
|
|
50
|
+
serviceCenter.removeConnection(serverConnection);
|
|
51
|
+
serviceChildInjector.disposeAll();
|
|
52
|
+
|
|
53
|
+
logger.log(`Remove RPC connection ${clientId}`);
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
dispose: () => {},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
socketRoute.registerHandler(channelHandler);
|
|
60
|
+
if (handlerArr) {
|
|
61
|
+
for (const handler of handlerArr) {
|
|
62
|
+
socketRoute.registerHandler(handler);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
socketRoute.init();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function createNetServerConnection(server: net.Server, injector, modulesInstances) {
|
|
69
|
+
const logger = injector.get(INodeLogger);
|
|
70
|
+
const serviceCenter = new RPCServiceCenter(undefined, logger);
|
|
71
|
+
const serviceChildInjector = bindModuleBackService(
|
|
72
|
+
injector,
|
|
73
|
+
modulesInstances,
|
|
74
|
+
serviceCenter,
|
|
75
|
+
process.env.CODE_WINDOW_CLIENT_ID as string,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
server.on('connection', (connection) => {
|
|
79
|
+
const serverConnection = createSocketConnection(connection);
|
|
80
|
+
serviceCenter.setConnection(serverConnection);
|
|
81
|
+
|
|
82
|
+
connection.on('close', () => {
|
|
83
|
+
serviceCenter.removeConnection(serverConnection);
|
|
84
|
+
serviceChildInjector.disposeAll();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return serviceCenter;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function bindModuleBackService(
|
|
92
|
+
injector: Injector,
|
|
93
|
+
modules: NodeModule[],
|
|
94
|
+
serviceCenter: RPCServiceCenter,
|
|
95
|
+
clientId?: string,
|
|
96
|
+
) {
|
|
97
|
+
const { createRPCService } = initRPCService(serviceCenter);
|
|
98
|
+
|
|
99
|
+
const childInjector = injector.createChild();
|
|
100
|
+
for (const module of modules) {
|
|
101
|
+
if (module.backServices) {
|
|
102
|
+
for (const service of module.backServices) {
|
|
103
|
+
if (service.token) {
|
|
104
|
+
const serviceToken = service.token;
|
|
105
|
+
|
|
106
|
+
if (!injector.creatorMap.has(serviceToken)) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const creator = injector.creatorMap.get(serviceToken) as InstanceCreator;
|
|
111
|
+
|
|
112
|
+
if ((creator as FactoryCreator).useFactory) {
|
|
113
|
+
const serviceFactory = (creator as FactoryCreator).useFactory;
|
|
114
|
+
childInjector.addProviders({
|
|
115
|
+
token: serviceToken,
|
|
116
|
+
useValue: serviceFactory(childInjector),
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
const serviceClass = (creator as ClassCreator).useClass;
|
|
120
|
+
childInjector.addProviders({
|
|
121
|
+
token: serviceToken,
|
|
122
|
+
useClass: serviceClass,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const serviceInstance = childInjector.get(serviceToken);
|
|
126
|
+
|
|
127
|
+
if (serviceInstance.setConnectionClientId && clientId) {
|
|
128
|
+
serviceInstance.setConnectionClientId(clientId);
|
|
129
|
+
}
|
|
130
|
+
const servicePath = service.servicePath;
|
|
131
|
+
const createService = createRPCService(servicePath, serviceInstance);
|
|
132
|
+
|
|
133
|
+
if (!serviceInstance.rpcClient) {
|
|
134
|
+
serviceInstance.rpcClient = [createService];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return childInjector;
|
|
142
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Autowired } from '@opensumi/di';
|
|
2
|
+
import { Domain } from '@opensumi/ide-core-common/lib/di-helper';
|
|
3
|
+
import { IHashCalculateService } from '@opensumi/ide-core-common/lib/hash-calculate/hash-calculate';
|
|
4
|
+
|
|
5
|
+
import { ServerAppContribution } from '../types';
|
|
6
|
+
|
|
7
|
+
@Domain(ServerAppContribution)
|
|
8
|
+
export class HashCalculateContribution implements ServerAppContribution {
|
|
9
|
+
@Autowired(IHashCalculateService)
|
|
10
|
+
private readonly hashCalculateService: IHashCalculateService;
|
|
11
|
+
|
|
12
|
+
async initialize() {
|
|
13
|
+
try {
|
|
14
|
+
await this.hashCalculateService.initialize();
|
|
15
|
+
} catch (err) {
|
|
16
|
+
throw new Error(`hashCalculateService init fail: \n ${err.message}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Injectable, Autowired } from '@opensumi/di';
|
|
2
|
+
import { ILogServiceManager, SupportLogNamespace, ILogService, LogLevel } from '@opensumi/ide-core-common';
|
|
3
|
+
|
|
4
|
+
export type INodeLogger = ILogService;
|
|
5
|
+
export const INodeLogger = Symbol('INodeLogger');
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class NodeLogger implements INodeLogger {
|
|
9
|
+
@Autowired(ILogServiceManager)
|
|
10
|
+
private loggerManger: ILogServiceManager;
|
|
11
|
+
|
|
12
|
+
private logger: ILogService;
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
this.logger = this.loggerManger.getLogger(SupportLogNamespace.Node);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
error(...args) {
|
|
19
|
+
return this.logger.error(...args);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
warn(...args) {
|
|
23
|
+
return this.logger.warn(...args);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
log(...args) {
|
|
27
|
+
return this.logger.log(...args);
|
|
28
|
+
}
|
|
29
|
+
debug(...args) {
|
|
30
|
+
return this.logger.debug(...args);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
verbose(...args) {
|
|
34
|
+
return this.logger.verbose(...args);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
critical(...args) {
|
|
38
|
+
return this.logger.critical(...args);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
dispose() {
|
|
42
|
+
return this.logger.dispose();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setOptions(options) {
|
|
46
|
+
return this.logger.setOptions(options);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
sendLog(level: LogLevel, message: string) {
|
|
50
|
+
return this.logger.sendLog(level, message);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
drop() {
|
|
54
|
+
return this.logger.drop();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
flush() {
|
|
58
|
+
return this.logger.flush();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getLevel() {
|
|
62
|
+
return this.logger.getLevel();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
setLevel(level: LogLevel) {
|
|
66
|
+
return this.logger.setLevel(level);
|
|
67
|
+
}
|
|
68
|
+
}
|