@milaboratories/pl-drivers 1.3.6 → 1.3.8
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/dist/drivers/logs.d.ts +3 -1
- package/dist/drivers/logs.d.ts.map +1 -1
- package/dist/drivers/logs_stream.d.ts +4 -2
- package/dist/drivers/logs_stream.d.ts.map +1 -1
- package/dist/drivers/virtual_storages.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +110 -107
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/drivers/logs.test.ts +7 -6
- package/src/drivers/logs.ts +3 -1
- package/src/drivers/logs_stream.ts +22 -13
- package/src/drivers/ls.test.ts +12 -34
- package/src/drivers/virtual_storages.ts +8 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-drivers",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.8",
|
|
4
4
|
"description": "Drivers and a low-level clients for log streaming, downloading and uploading files from and to pl",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -27,16 +27,16 @@
|
|
|
27
27
|
"undici": "^6.20.1",
|
|
28
28
|
"zod": "^3.23.8",
|
|
29
29
|
"@milaboratories/ts-helpers": "^1.1.0",
|
|
30
|
-
"@milaboratories/pl-tree": "^1.4.6",
|
|
31
|
-
"@milaboratories/computable": "^2.2.0",
|
|
32
30
|
"@milaboratories/pl-client": "^2.5.5",
|
|
33
|
-
"@milaboratories/
|
|
31
|
+
"@milaboratories/computable": "^2.2.0",
|
|
32
|
+
"@milaboratories/pl-tree": "^1.4.6",
|
|
33
|
+
"@milaboratories/pl-model-common": "^1.5.2"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"typescript": "~5.5.4",
|
|
37
37
|
"vite": "^5.4.10",
|
|
38
|
-
"@types/node": "~20.16.
|
|
39
|
-
"@types/jest": "^29.5.
|
|
38
|
+
"@types/node": "~20.16.15",
|
|
39
|
+
"@types/jest": "^29.5.14",
|
|
40
40
|
"@types/tar-fs": "^2.0.4",
|
|
41
41
|
"jest": "^29.7.0",
|
|
42
42
|
"@jest/globals": "^29.7.0",
|
package/src/drivers/logs.test.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { DownloadDriver } from './download_and_logs_blob';
|
|
|
22
22
|
import { createDownloadClient, createLogsClient } from '../clients/helpers';
|
|
23
23
|
import { LogsStreamDriver } from './logs_stream';
|
|
24
24
|
import { LogsDriver } from './logs';
|
|
25
|
+
import { test, expect } from '@jest/globals';
|
|
25
26
|
|
|
26
27
|
test('should get all logs', async () => {
|
|
27
28
|
await TestHelpers.withTempRoot(async (client) => {
|
|
@@ -31,7 +32,7 @@ test('should get all logs', async () => {
|
|
|
31
32
|
stopPollingDelay: 10,
|
|
32
33
|
pollingInterval: 10
|
|
33
34
|
});
|
|
34
|
-
const logsStream = new LogsStreamDriver(createLogsClient(client, logger));
|
|
35
|
+
const logsStream = new LogsStreamDriver(logger, createLogsClient(client, logger));
|
|
35
36
|
const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test-logs-1-'));
|
|
36
37
|
const download = new DownloadDriver(
|
|
37
38
|
logger,
|
|
@@ -41,7 +42,7 @@ test('should get all logs', async () => {
|
|
|
41
42
|
new HmacSha256Signer(HmacSha256Signer.generateSecret()),
|
|
42
43
|
{ cacheSoftSizeBytes: 700 * 1024, nConcurrentDownloads: 10 }
|
|
43
44
|
);
|
|
44
|
-
const logs = new LogsDriver(logsStream, download);
|
|
45
|
+
const logs = new LogsDriver(logger, logsStream, download);
|
|
45
46
|
|
|
46
47
|
await createRunCommandWithStdoutStream(client, 'bash', ['-c', 'echo 1; sleep 1; echo 2']);
|
|
47
48
|
|
|
@@ -76,7 +77,7 @@ test('should get last line with a prefix', async () => {
|
|
|
76
77
|
stopPollingDelay: 10,
|
|
77
78
|
pollingInterval: 10
|
|
78
79
|
});
|
|
79
|
-
const logsStream = new LogsStreamDriver(createLogsClient(client, logger));
|
|
80
|
+
const logsStream = new LogsStreamDriver(logger, createLogsClient(client, logger));
|
|
80
81
|
const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test-logs-2-'));
|
|
81
82
|
const download = new DownloadDriver(
|
|
82
83
|
logger,
|
|
@@ -86,7 +87,7 @@ test('should get last line with a prefix', async () => {
|
|
|
86
87
|
new HmacSha256Signer(HmacSha256Signer.generateSecret()),
|
|
87
88
|
{ cacheSoftSizeBytes: 700 * 1024, nConcurrentDownloads: 10 }
|
|
88
89
|
);
|
|
89
|
-
const logs = new LogsDriver(logsStream, download);
|
|
90
|
+
const logs = new LogsDriver(logger, logsStream, download);
|
|
90
91
|
|
|
91
92
|
const c = Computable.make((ctx) => {
|
|
92
93
|
const streamManager = ctx.accessor(tree.entry()).node().traverse('result')?.persist();
|
|
@@ -126,7 +127,7 @@ test('should get log smart object and get log lines from that', async () => {
|
|
|
126
127
|
stopPollingDelay: 10,
|
|
127
128
|
pollingInterval: 10
|
|
128
129
|
});
|
|
129
|
-
const logsStream = new LogsStreamDriver(createLogsClient(client, logger));
|
|
130
|
+
const logsStream = new LogsStreamDriver(logger, createLogsClient(client, logger));
|
|
130
131
|
const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test-logs-3-'));
|
|
131
132
|
const download = new DownloadDriver(
|
|
132
133
|
logger,
|
|
@@ -136,7 +137,7 @@ test('should get log smart object and get log lines from that', async () => {
|
|
|
136
137
|
new HmacSha256Signer(HmacSha256Signer.generateSecret()),
|
|
137
138
|
{ cacheSoftSizeBytes: 700 * 1024, nConcurrentDownloads: 10 }
|
|
138
139
|
);
|
|
139
|
-
const logs = new LogsDriver(logsStream, download);
|
|
140
|
+
const logs = new LogsDriver(logger, logsStream, download);
|
|
140
141
|
|
|
141
142
|
const c = Computable.make((ctx) => {
|
|
142
143
|
const streamManager = ctx.accessor(tree.entry()).node().traverse('result')?.persist();
|
package/src/drivers/logs.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Computable, ComputableCtx } from '@milaboratories/computable';
|
|
2
2
|
import { PlTreeEntry, ResourceInfo } from '@milaboratories/pl-tree';
|
|
3
|
-
import { bigintToResourceId } from '@milaboratories/pl-client';
|
|
3
|
+
import { bigintToResourceId, stringifyWithResourceId } from '@milaboratories/pl-client';
|
|
4
4
|
import { LogsStreamDriver } from './logs_stream';
|
|
5
5
|
import { DownloadDriver } from './download_and_logs_blob';
|
|
6
6
|
import * as sdk from '@milaboratories/pl-model-common';
|
|
7
|
+
import { ConsoleLoggerAdapter, MiLogger } from '@milaboratories/ts-helpers';
|
|
7
8
|
|
|
8
9
|
export class LogsDriver implements sdk.LogsDriver {
|
|
9
10
|
constructor(
|
|
11
|
+
private readonly logger: MiLogger,
|
|
10
12
|
private readonly logsStreamDriver: LogsStreamDriver,
|
|
11
13
|
private readonly downloadDriver: DownloadDriver
|
|
12
14
|
) {}
|
|
@@ -5,8 +5,14 @@ import {
|
|
|
5
5
|
PollingComputableHooks,
|
|
6
6
|
Watcher
|
|
7
7
|
} from '@milaboratories/computable';
|
|
8
|
-
import { ResourceId } from '@milaboratories/pl-client';
|
|
9
|
-
import {
|
|
8
|
+
import { ResourceId, stringifyWithResourceId } from '@milaboratories/pl-client';
|
|
9
|
+
import {
|
|
10
|
+
asyncPool,
|
|
11
|
+
CallersCounter,
|
|
12
|
+
ConsoleLoggerAdapter,
|
|
13
|
+
MiLogger,
|
|
14
|
+
ValueOrError
|
|
15
|
+
} from '@milaboratories/ts-helpers';
|
|
10
16
|
import { ClientLogs } from '../clients/logs';
|
|
11
17
|
import { randomUUID } from 'node:crypto';
|
|
12
18
|
import { PlTreeEntry, ResourceInfo, treeEntryToResourceInfo } from '@milaboratories/pl-tree';
|
|
@@ -15,6 +21,7 @@ import { scheduler } from 'node:timers/promises';
|
|
|
15
21
|
import { StreamingAPI_Response } from '../proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol';
|
|
16
22
|
import * as sdk from '@milaboratories/pl-model-common';
|
|
17
23
|
import { PollingOps } from './helpers/polling_ops';
|
|
24
|
+
import { RpcError } from '@protobuf-ts/runtime-rpc';
|
|
18
25
|
|
|
19
26
|
export type LogsStreamDriverOps = PollingOps & {
|
|
20
27
|
/** Max number of concurrent requests to log streaming backend while calculating computable states */
|
|
@@ -32,6 +39,7 @@ export class LogsStreamDriver implements sdk.LogsDriver {
|
|
|
32
39
|
private readonly hooks: PollingComputableHooks;
|
|
33
40
|
|
|
34
41
|
constructor(
|
|
42
|
+
private readonly logger: MiLogger,
|
|
35
43
|
private readonly clientLogs: ClientLogs,
|
|
36
44
|
private readonly opts: LogsStreamDriverOps = {
|
|
37
45
|
nConcurrentGetLogs: 10,
|
|
@@ -82,7 +90,7 @@ export class LogsStreamDriver implements sdk.LogsDriver {
|
|
|
82
90
|
let logGetter = this.idToLastLines.get(rInfo.id);
|
|
83
91
|
|
|
84
92
|
if (logGetter == undefined) {
|
|
85
|
-
const newLogGetter = new LogGetter(this.clientLogs, rInfo, lines);
|
|
93
|
+
const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, lines);
|
|
86
94
|
this.idToLastLines.set(rInfo.id, newLogGetter);
|
|
87
95
|
|
|
88
96
|
logGetter = newLogGetter;
|
|
@@ -120,7 +128,6 @@ export class LogsStreamDriver implements sdk.LogsDriver {
|
|
|
120
128
|
ctx.addOnDestroy(() => this.releaseProgressLog(r.id, callerId));
|
|
121
129
|
|
|
122
130
|
const result = this.getProgressLogNoCtx(ctx.watcher, r, patternToSearch, callerId);
|
|
123
|
-
|
|
124
131
|
ctx.markUnstable(
|
|
125
132
|
'The progress log is from the stream, so we consider it unstable. Final value will be got from blobs.'
|
|
126
133
|
);
|
|
@@ -137,7 +144,7 @@ export class LogsStreamDriver implements sdk.LogsDriver {
|
|
|
137
144
|
let logGetter = this.idToProgressLog.get(rInfo.id);
|
|
138
145
|
|
|
139
146
|
if (logGetter == undefined) {
|
|
140
|
-
const newLogGetter = new LogGetter(this.clientLogs, rInfo, 1, patternToSearch);
|
|
147
|
+
const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, 1, patternToSearch);
|
|
141
148
|
this.idToProgressLog.set(rInfo.id, newLogGetter);
|
|
142
149
|
|
|
143
150
|
logGetter = newLogGetter;
|
|
@@ -264,9 +271,10 @@ export class LogsStreamDriver implements sdk.LogsDriver {
|
|
|
264
271
|
this.scheduledOnNextState = [];
|
|
265
272
|
|
|
266
273
|
try {
|
|
274
|
+
const logs = this.getAllLogs();
|
|
267
275
|
await asyncPool(
|
|
268
276
|
this.opts.nConcurrentGetLogs,
|
|
269
|
-
|
|
277
|
+
logs.map((getter) => async () => await getter.update())
|
|
270
278
|
);
|
|
271
279
|
|
|
272
280
|
toNotify.forEach((n) => n.resolve());
|
|
@@ -282,10 +290,9 @@ export class LogsStreamDriver implements sdk.LogsDriver {
|
|
|
282
290
|
this.currentLoop = undefined;
|
|
283
291
|
}
|
|
284
292
|
|
|
285
|
-
private
|
|
293
|
+
private getAllLogs(): Array<LogGetter> {
|
|
286
294
|
return Array.from(this.idToLastLines.entries())
|
|
287
295
|
.concat(Array.from(this.idToProgressLog.entries()))
|
|
288
|
-
.filter(([_, getter]) => !getter.getLog().done)
|
|
289
296
|
.map(([_, getter]) => getter);
|
|
290
297
|
}
|
|
291
298
|
}
|
|
@@ -294,12 +301,12 @@ export class LogsStreamDriver implements sdk.LogsDriver {
|
|
|
294
301
|
class LogGetter {
|
|
295
302
|
private logs: string | undefined;
|
|
296
303
|
private error: any | undefined = undefined;
|
|
297
|
-
private done = false;
|
|
298
304
|
|
|
299
305
|
private readonly change: ChangeSource = new ChangeSource();
|
|
300
306
|
private readonly counter: CallersCounter = new CallersCounter();
|
|
301
307
|
|
|
302
308
|
constructor(
|
|
309
|
+
private readonly logger: MiLogger,
|
|
303
310
|
private readonly clientLogs: ClientLogs,
|
|
304
311
|
private readonly rInfo: ResourceInfo,
|
|
305
312
|
private readonly lines: number,
|
|
@@ -309,12 +316,10 @@ class LogGetter {
|
|
|
309
316
|
getLog(): {
|
|
310
317
|
log: string | undefined;
|
|
311
318
|
error?: any | undefined;
|
|
312
|
-
done: boolean;
|
|
313
319
|
} {
|
|
314
320
|
return {
|
|
315
321
|
log: this.logs,
|
|
316
|
-
error: this.error
|
|
317
|
-
done: this.done
|
|
322
|
+
error: this.error
|
|
318
323
|
};
|
|
319
324
|
}
|
|
320
325
|
|
|
@@ -340,18 +345,22 @@ class LogGetter {
|
|
|
340
345
|
|
|
341
346
|
if (this.logs != newLogs) this.change.markChanged();
|
|
342
347
|
this.logs = newLogs;
|
|
348
|
+
this.error = undefined;
|
|
343
349
|
|
|
344
350
|
return;
|
|
345
351
|
} catch (e: any) {
|
|
352
|
+
e as RpcError;
|
|
346
353
|
if (e.name == 'RpcError' && e.code == 'NOT_FOUND') {
|
|
347
354
|
// No resource
|
|
348
355
|
this.logs = '';
|
|
349
356
|
this.error = e;
|
|
350
|
-
this.done = true;
|
|
351
357
|
this.change.markChanged();
|
|
352
358
|
return;
|
|
353
359
|
}
|
|
354
360
|
|
|
361
|
+
this.logger.error(
|
|
362
|
+
`Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${e}`
|
|
363
|
+
);
|
|
355
364
|
throw e;
|
|
356
365
|
}
|
|
357
366
|
}
|
package/src/drivers/ls.test.ts
CHANGED
|
@@ -15,15 +15,9 @@ test('should ok when get all storages from ls driver', async () => {
|
|
|
15
15
|
const logger = new ConsoleLoggerAdapter();
|
|
16
16
|
await TestHelpers.withTempRoot(async (client) => {
|
|
17
17
|
const lsClient = createLsFilesClient(client, logger);
|
|
18
|
-
const driver = await LsDriver.init(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
signer,
|
|
22
|
-
[],
|
|
23
|
-
() => {
|
|
24
|
-
throw Error();
|
|
25
|
-
}
|
|
26
|
-
);
|
|
18
|
+
const driver = await LsDriver.init(logger, client, signer, [], () => {
|
|
19
|
+
throw Error();
|
|
20
|
+
});
|
|
27
21
|
|
|
28
22
|
const got = await driver.getStorageList();
|
|
29
23
|
|
|
@@ -41,15 +35,9 @@ test('should ok when list files from remote storage in ls driver', async () => {
|
|
|
41
35
|
const signer = new HmacSha256Signer('abc');
|
|
42
36
|
const logger = new ConsoleLoggerAdapter();
|
|
43
37
|
await TestHelpers.withTempRoot(async (client) => {
|
|
44
|
-
const driver = await LsDriver.init(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
signer,
|
|
48
|
-
[],
|
|
49
|
-
() => {
|
|
50
|
-
throw Error();
|
|
51
|
-
}
|
|
52
|
-
);
|
|
38
|
+
const driver = await LsDriver.init(logger, client, signer, [], () => {
|
|
39
|
+
throw Error();
|
|
40
|
+
});
|
|
53
41
|
|
|
54
42
|
const storages = await driver.getStorageList();
|
|
55
43
|
const library = storages.find((se) => se.name == 'library')!.handle;
|
|
@@ -82,15 +70,9 @@ test('should ok when list files from local storage in ls driver', async () => {
|
|
|
82
70
|
const signer = new HmacSha256Signer('abc');
|
|
83
71
|
const logger = new ConsoleLoggerAdapter();
|
|
84
72
|
await TestHelpers.withTempRoot(async (client) => {
|
|
85
|
-
const driver = await LsDriver.init(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
signer,
|
|
89
|
-
[],
|
|
90
|
-
() => {
|
|
91
|
-
throw Error();
|
|
92
|
-
}
|
|
93
|
-
);
|
|
73
|
+
const driver = await LsDriver.init(logger, client, signer, [], () => {
|
|
74
|
+
throw Error();
|
|
75
|
+
});
|
|
94
76
|
|
|
95
77
|
const storages = await driver.getStorageList();
|
|
96
78
|
const local = storages.find((se) => se.name == 'local')!;
|
|
@@ -146,13 +128,9 @@ test('should ok when get file using local dialog, and read its content', async (
|
|
|
146
128
|
const signer = new HmacSha256Signer('abc');
|
|
147
129
|
const logger = new ConsoleLoggerAdapter();
|
|
148
130
|
await TestHelpers.withTempRoot(async (client) => {
|
|
149
|
-
const driver = await LsDriver.init(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
signer,
|
|
153
|
-
[],
|
|
154
|
-
async () => [path.join(assetsPath, 'answer_to_the_ultimate_question.txt')]
|
|
155
|
-
);
|
|
131
|
+
const driver = await LsDriver.init(logger, client, signer, [], async () => [
|
|
132
|
+
path.join(assetsPath, 'answer_to_the_ultimate_question.txt')
|
|
133
|
+
]);
|
|
156
134
|
|
|
157
135
|
const result = await driver.showOpenSingleFileDialog();
|
|
158
136
|
expect(result.file).toBeDefined();
|
|
@@ -36,14 +36,16 @@ export async function DefaultVirtualLocalStorages(): Promise<VirtualLocalStorage
|
|
|
36
36
|
name: `local_disk_${drive}`,
|
|
37
37
|
root: `${drive}:\\`,
|
|
38
38
|
initialPath: isHomeDrive ? home : `${drive}:\\`
|
|
39
|
-
}
|
|
39
|
+
};
|
|
40
40
|
});
|
|
41
41
|
} catch (e: any) {
|
|
42
|
-
return [
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
name: `local_disk_${homeDrive}`,
|
|
45
|
+
root: `${homeDrive}:\\`,
|
|
46
|
+
initialPath: home
|
|
47
|
+
}
|
|
48
|
+
];
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
}
|