-
-
Notifications
You must be signed in to change notification settings - Fork 439
/
Copy pathcore-client-provider-impl.ts
135 lines (118 loc) · 5.54 KB
/
core-client-provider-impl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import { inject, injectable } from 'inversify';
import * as grpc from '@grpc/grpc-js';
import { ArduinoCoreClient } from './cli-protocol/commands_grpc_pb';
import { InitResp, InitReq, Configuration, UpdateIndexReq, UpdateIndexResp } from './cli-protocol/commands_pb';
import { WorkspaceServiceExt } from '../browser/workspace-service-ext';
import { FileSystem } from '@theia/filesystem/lib/common';
import URI from '@theia/core/lib/common/uri';
import { CoreClientProvider, Client } from './core-client-provider';
import * as PQueue from 'p-queue';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
import { Instance } from './cli-protocol/common_pb';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as os from 'os';
@injectable()
export class CoreClientProviderImpl implements CoreClientProvider {
protected clients = new Map<string, Client>();
protected readonly clientRequestQueue = new PQueue({ autoStart: true, concurrency: 1 });
@inject(FileSystem)
protected readonly fileSystem: FileSystem;
@inject(WorkspaceServiceExt)
protected readonly workspaceServiceExt: WorkspaceServiceExt;
@inject(ToolOutputServiceServer)
protected readonly toolOutputService: ToolOutputServiceServer;
async getClient(workspaceRootOrResourceUri?: string): Promise<Client | undefined> {
return this.clientRequestQueue.add(() => new Promise<Client | undefined>(async resolve => {
const roots = await this.workspaceServiceExt.roots();
if (!workspaceRootOrResourceUri) {
resolve(this.getOrCreateClient(roots[0]));
return;
}
const root = roots
.sort((left, right) => right.length - left.length) // Longest "paths" first
.map(uri => new URI(uri))
.find(uri => uri.isEqualOrParent(new URI(workspaceRootOrResourceUri)));
if (!root) {
console.warn(`Could not retrieve the container workspace root for URI: ${workspaceRootOrResourceUri}.`);
console.warn(`Falling back to ${roots[0]}`);
resolve(this.getOrCreateClient(roots[0]));
return;
}
resolve(this.getOrCreateClient(root.toString()));
}));
}
protected async getOrCreateClient(rootUri: string | undefined): Promise<Client | undefined> {
if (!rootUri) {
return undefined;
}
const existing = this.clients.get(rootUri);
if (existing) {
console.debug(`Reusing existing client for ${rootUri}.`);
return existing;
}
console.info(` >>> Creating and caching a new client for ${rootUri}...`);
const client = new ArduinoCoreClient('localhost:50051', grpc.credentials.createInsecure());
const config = new Configuration();
const rootPath = await this.fileSystem.getFsPath(rootUri);
if (!rootPath) {
throw new Error(`Could not resolve filesystem path of URI: ${rootUri}.`);
}
const defaultDownloadsDirPath = path.resolve(os.homedir(), 'Arduino-PoC', 'downloads');
if (!fs.existsSync(defaultDownloadsDirPath)) {
fs.mkdirpSync(defaultDownloadsDirPath);
}
const defaultDataDirPath = path.resolve(os.homedir(), 'Arduino-PoC', 'data')
if (!fs.existsSync(defaultDataDirPath)) {
fs.mkdirpSync(defaultDataDirPath);
}
config.setSketchbookdir(rootPath);
config.setDatadir(defaultDataDirPath);
config.setDownloadsdir(defaultDownloadsDirPath);
const initReq = new InitReq();
initReq.setConfiguration(config);
const initResp = await new Promise<InitResp>((resolve, reject) => client.init(initReq, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp)));
const instance = initResp.getInstance();
if (!instance) {
throw new Error(`Could not retrieve instance from the initialize response.`);
}
// in a seperate promise, try and update the index
let succeeded = true;
for (let i = 0; i < 10; i++) {
try {
await this.updateIndex(client, instance);
succeeded = true;
break;
} catch (e) {
this.toolOutputService.publishNewOutput("daemon", `Error while updating index in attempt ${i}: ${e}`);
}
}
if (!succeeded) {
this.toolOutputService.publishNewOutput("daemon", `Was unable to update the index. Please restart to try again.`);
}
const result = {
client,
instance
}
this.clients.set(rootUri, result);
console.info(` <<< New client has been successfully created and cached for ${rootUri}.`);
return result;
}
protected async updateIndex(client: ArduinoCoreClient, instance: Instance): Promise<void> {
const updateReq = new UpdateIndexReq();
updateReq.setInstance(instance);
const updateResp = client.updateIndex(updateReq);
updateResp.on('data', (o: UpdateIndexResp) => {
const progress = o.getDownloadProgress();
if (progress) {
if (progress.getCompleted()) {
this.toolOutputService.publishNewOutput("daemon", `Download${progress.getFile() ? ` of ${progress.getFile()}` : ''} completed.\n`);
}
}
});
await new Promise<void>((resolve, reject) => {
updateResp.on('error', reject);
updateResp.on('end', resolve);
});
}
}