@milaboratories/pl-drivers 1.11.24 → 1.11.26
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/clients/ls_api.cjs +16 -2
- package/dist/clients/ls_api.cjs.map +1 -1
- package/dist/clients/ls_api.d.ts.map +1 -1
- package/dist/clients/ls_api.js +16 -2
- package/dist/clients/ls_api.js.map +1 -1
- package/dist/drivers/download_blob/download_blob_task.cjs +1 -1
- package/dist/drivers/download_blob/download_blob_task.cjs.map +1 -1
- package/dist/drivers/download_blob/download_blob_task.js +1 -1
- package/dist/drivers/download_blob/download_blob_task.js.map +1 -1
- package/dist/drivers/logs_stream.cjs +1 -1
- package/dist/drivers/logs_stream.cjs.map +1 -1
- package/dist/drivers/logs_stream.js +1 -1
- package/dist/drivers/logs_stream.js.map +1 -1
- package/package.json +6 -6
- package/src/clients/ls_api.ts +19 -2
- package/src/drivers/download_blob/download_blob_task.ts +1 -1
- package/src/drivers/download_url/driver.test.ts +1 -1
- package/src/drivers/logs_stream.ts +1 -1
package/dist/clients/ls_api.cjs
CHANGED
|
@@ -43,8 +43,7 @@ class ClientLs {
|
|
|
43
43
|
isDir: item.isDir,
|
|
44
44
|
fullName: item.fullName,
|
|
45
45
|
directory: item.directory,
|
|
46
|
-
|
|
47
|
-
lastModified: { seconds: BigInt(item.lastModified), nanos: 0 },
|
|
46
|
+
lastModified: parseTimestamp(item.lastModified),
|
|
48
47
|
version: item.version,
|
|
49
48
|
}));
|
|
50
49
|
return {
|
|
@@ -54,6 +53,21 @@ class ClientLs {
|
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
}
|
|
56
|
+
function parseTimestamp(timestamp) {
|
|
57
|
+
// Parse ISO 8601 format: 2025-08-08T11:12:44.145635532Z
|
|
58
|
+
const date = new Date(timestamp);
|
|
59
|
+
const seconds = BigInt(Math.floor(date.getTime() / 1000));
|
|
60
|
+
// Extract fractional seconds from the original string
|
|
61
|
+
const fractionalMatch = timestamp.match(/\.(\d+)Z?$/);
|
|
62
|
+
let nanos = 0;
|
|
63
|
+
if (fractionalMatch) {
|
|
64
|
+
const fractionalPart = fractionalMatch[1];
|
|
65
|
+
// Pad or truncate to 9 digits (nanoseconds)
|
|
66
|
+
const padded = fractionalPart.padEnd(9, '0').slice(0, 9);
|
|
67
|
+
nanos = parseInt(padded, 10);
|
|
68
|
+
}
|
|
69
|
+
return { seconds, nanos };
|
|
70
|
+
}
|
|
57
71
|
|
|
58
72
|
exports.ClientLs = ClientLs;
|
|
59
73
|
//# sourceMappingURL=ls_api.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ls_api.cjs","sources":["../../src/clients/ls_api.ts"],"sourcesContent":["import type { MiLogger } from '@milaboratories/ts-helpers';\nimport type { RpcOptions } from '@protobuf-ts/runtime-rpc';\nimport type { WireClientProvider, WireClientProviderFactory } from '@milaboratories/pl-client';\nimport { RestAPI } from '@milaboratories/pl-client';\nimport { addRTypeToMetadata, createRTypeRoutingHeader } from '@milaboratories/pl-client';\nimport type { LsAPI_List_Response, LsAPI_ListItem } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol';\nimport { LSClient } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client';\nimport type { LsApiPaths, LsRestClientType } from '../proto-rest';\n\nimport type { ResourceInfo } from '@milaboratories/pl-tree';\n\nexport class ClientLs {\n private readonly wire: WireClientProvider<LsRestClientType | LSClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n private readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider(\n (wire) => {\n if (wire.type === 'grpc') {\n return new LSClient(wire.Transport);\n }\n\n return RestAPI.createClient<LsApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n },\n );\n }\n\n close() {}\n\n public async list(\n rInfo: ResourceInfo,\n path: string,\n options?: RpcOptions,\n ): Promise<LsAPI_List_Response> {\n const client = this.wire.get();\n\n if (client instanceof LSClient) {\n return await client.list(\n {\n resourceId: rInfo.id,\n location: path,\n },\n addRTypeToMetadata(rInfo.type, options),\n ).response;\n } else {\n const resp = (await client.POST('/v1/list', {\n body: {\n resourceId: rInfo.id.toString(),\n location: path,\n },\n headers: { ...createRTypeRoutingHeader(rInfo.type) },\n })).data!;\n\n const items: LsAPI_ListItem[] = resp.items.map((item) => ({\n name: item.name,\n size: BigInt(item.size),\n isDir: item.isDir,\n fullName: item.fullName,\n directory: item.directory,\n
|
|
1
|
+
{"version":3,"file":"ls_api.cjs","sources":["../../src/clients/ls_api.ts"],"sourcesContent":["import type { MiLogger } from '@milaboratories/ts-helpers';\nimport type { RpcOptions } from '@protobuf-ts/runtime-rpc';\nimport type { WireClientProvider, WireClientProviderFactory } from '@milaboratories/pl-client';\nimport { RestAPI } from '@milaboratories/pl-client';\nimport { addRTypeToMetadata, createRTypeRoutingHeader } from '@milaboratories/pl-client';\nimport type { LsAPI_List_Response, LsAPI_ListItem } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol';\nimport { LSClient } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client';\nimport type { LsApiPaths, LsRestClientType } from '../proto-rest';\n\nimport type { ResourceInfo } from '@milaboratories/pl-tree';\n\nexport class ClientLs {\n private readonly wire: WireClientProvider<LsRestClientType | LSClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n private readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider(\n (wire) => {\n if (wire.type === 'grpc') {\n return new LSClient(wire.Transport);\n }\n\n return RestAPI.createClient<LsApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n },\n );\n }\n\n close() {}\n\n public async list(\n rInfo: ResourceInfo,\n path: string,\n options?: RpcOptions,\n ): Promise<LsAPI_List_Response> {\n const client = this.wire.get();\n\n if (client instanceof LSClient) {\n return await client.list(\n {\n resourceId: rInfo.id,\n location: path,\n },\n addRTypeToMetadata(rInfo.type, options),\n ).response;\n } else {\n const resp = (await client.POST('/v1/list', {\n body: {\n resourceId: rInfo.id.toString(),\n location: path,\n },\n headers: { ...createRTypeRoutingHeader(rInfo.type) },\n })).data!;\n\n const items: LsAPI_ListItem[] = resp.items.map((item) => ({\n name: item.name,\n size: BigInt(item.size),\n isDir: item.isDir,\n fullName: item.fullName,\n directory: item.directory,\n lastModified: parseTimestamp(item.lastModified),\n version: item.version,\n }));\n\n return {\n items,\n delimiter: resp.delimiter,\n };\n }\n }\n}\n\nfunction parseTimestamp(timestamp: string): { seconds: bigint; nanos: number } {\n // Parse ISO 8601 format: 2025-08-08T11:12:44.145635532Z\n const date = new Date(timestamp);\n const seconds = BigInt(Math.floor(date.getTime() / 1000));\n\n // Extract fractional seconds from the original string\n const fractionalMatch = timestamp.match(/\\.(\\d+)Z?$/);\n let nanos = 0;\n if (fractionalMatch) {\n const fractionalPart = fractionalMatch[1];\n // Pad or truncate to 9 digits (nanoseconds)\n const padded = fractionalPart.padEnd(9, '0').slice(0, 9);\n nanos = parseInt(padded, 10);\n }\n\n return { seconds, nanos };\n}\n"],"names":["LSClient","RestAPI","addRTypeToMetadata","createRTypeRoutingHeader"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ls_api.d.ts","sourceRoot":"","sources":["../../src/clients/ls_api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAsB,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAG/F,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,iFAAiF,CAAC;AAI3I,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,qBAAa,QAAQ;IAKjB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkD;gBAGrE,yBAAyB,EAAE,yBAAyB,EACnC,MAAM,EAAE,QAAQ;IAkBnC,KAAK;IAEQ,IAAI,CACf,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"ls_api.d.ts","sourceRoot":"","sources":["../../src/clients/ls_api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAsB,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAG/F,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,iFAAiF,CAAC;AAI3I,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,qBAAa,QAAQ;IAKjB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkD;gBAGrE,yBAAyB,EAAE,yBAAyB,EACnC,MAAM,EAAE,QAAQ;IAkBnC,KAAK;IAEQ,IAAI,CACf,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,mBAAmB,CAAC;CAoChC"}
|
package/dist/clients/ls_api.js
CHANGED
|
@@ -41,8 +41,7 @@ class ClientLs {
|
|
|
41
41
|
isDir: item.isDir,
|
|
42
42
|
fullName: item.fullName,
|
|
43
43
|
directory: item.directory,
|
|
44
|
-
|
|
45
|
-
lastModified: { seconds: BigInt(item.lastModified), nanos: 0 },
|
|
44
|
+
lastModified: parseTimestamp(item.lastModified),
|
|
46
45
|
version: item.version,
|
|
47
46
|
}));
|
|
48
47
|
return {
|
|
@@ -52,6 +51,21 @@ class ClientLs {
|
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
}
|
|
54
|
+
function parseTimestamp(timestamp) {
|
|
55
|
+
// Parse ISO 8601 format: 2025-08-08T11:12:44.145635532Z
|
|
56
|
+
const date = new Date(timestamp);
|
|
57
|
+
const seconds = BigInt(Math.floor(date.getTime() / 1000));
|
|
58
|
+
// Extract fractional seconds from the original string
|
|
59
|
+
const fractionalMatch = timestamp.match(/\.(\d+)Z?$/);
|
|
60
|
+
let nanos = 0;
|
|
61
|
+
if (fractionalMatch) {
|
|
62
|
+
const fractionalPart = fractionalMatch[1];
|
|
63
|
+
// Pad or truncate to 9 digits (nanoseconds)
|
|
64
|
+
const padded = fractionalPart.padEnd(9, '0').slice(0, 9);
|
|
65
|
+
nanos = parseInt(padded, 10);
|
|
66
|
+
}
|
|
67
|
+
return { seconds, nanos };
|
|
68
|
+
}
|
|
55
69
|
|
|
56
70
|
export { ClientLs };
|
|
57
71
|
//# sourceMappingURL=ls_api.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ls_api.js","sources":["../../src/clients/ls_api.ts"],"sourcesContent":["import type { MiLogger } from '@milaboratories/ts-helpers';\nimport type { RpcOptions } from '@protobuf-ts/runtime-rpc';\nimport type { WireClientProvider, WireClientProviderFactory } from '@milaboratories/pl-client';\nimport { RestAPI } from '@milaboratories/pl-client';\nimport { addRTypeToMetadata, createRTypeRoutingHeader } from '@milaboratories/pl-client';\nimport type { LsAPI_List_Response, LsAPI_ListItem } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol';\nimport { LSClient } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client';\nimport type { LsApiPaths, LsRestClientType } from '../proto-rest';\n\nimport type { ResourceInfo } from '@milaboratories/pl-tree';\n\nexport class ClientLs {\n private readonly wire: WireClientProvider<LsRestClientType | LSClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n private readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider(\n (wire) => {\n if (wire.type === 'grpc') {\n return new LSClient(wire.Transport);\n }\n\n return RestAPI.createClient<LsApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n },\n );\n }\n\n close() {}\n\n public async list(\n rInfo: ResourceInfo,\n path: string,\n options?: RpcOptions,\n ): Promise<LsAPI_List_Response> {\n const client = this.wire.get();\n\n if (client instanceof LSClient) {\n return await client.list(\n {\n resourceId: rInfo.id,\n location: path,\n },\n addRTypeToMetadata(rInfo.type, options),\n ).response;\n } else {\n const resp = (await client.POST('/v1/list', {\n body: {\n resourceId: rInfo.id.toString(),\n location: path,\n },\n headers: { ...createRTypeRoutingHeader(rInfo.type) },\n })).data!;\n\n const items: LsAPI_ListItem[] = resp.items.map((item) => ({\n name: item.name,\n size: BigInt(item.size),\n isDir: item.isDir,\n fullName: item.fullName,\n directory: item.directory,\n
|
|
1
|
+
{"version":3,"file":"ls_api.js","sources":["../../src/clients/ls_api.ts"],"sourcesContent":["import type { MiLogger } from '@milaboratories/ts-helpers';\nimport type { RpcOptions } from '@protobuf-ts/runtime-rpc';\nimport type { WireClientProvider, WireClientProviderFactory } from '@milaboratories/pl-client';\nimport { RestAPI } from '@milaboratories/pl-client';\nimport { addRTypeToMetadata, createRTypeRoutingHeader } from '@milaboratories/pl-client';\nimport type { LsAPI_List_Response, LsAPI_ListItem } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol';\nimport { LSClient } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client';\nimport type { LsApiPaths, LsRestClientType } from '../proto-rest';\n\nimport type { ResourceInfo } from '@milaboratories/pl-tree';\n\nexport class ClientLs {\n private readonly wire: WireClientProvider<LsRestClientType | LSClient>;\n\n constructor(\n wireClientProviderFactory: WireClientProviderFactory,\n private readonly logger: MiLogger,\n ) {\n this.wire = wireClientProviderFactory.createWireClientProvider(\n (wire) => {\n if (wire.type === 'grpc') {\n return new LSClient(wire.Transport);\n }\n\n return RestAPI.createClient<LsApiPaths>({\n hostAndPort: wire.Config.hostAndPort,\n ssl: wire.Config.ssl,\n dispatcher: wire.Dispatcher,\n middlewares: wire.Middlewares,\n });\n },\n );\n }\n\n close() {}\n\n public async list(\n rInfo: ResourceInfo,\n path: string,\n options?: RpcOptions,\n ): Promise<LsAPI_List_Response> {\n const client = this.wire.get();\n\n if (client instanceof LSClient) {\n return await client.list(\n {\n resourceId: rInfo.id,\n location: path,\n },\n addRTypeToMetadata(rInfo.type, options),\n ).response;\n } else {\n const resp = (await client.POST('/v1/list', {\n body: {\n resourceId: rInfo.id.toString(),\n location: path,\n },\n headers: { ...createRTypeRoutingHeader(rInfo.type) },\n })).data!;\n\n const items: LsAPI_ListItem[] = resp.items.map((item) => ({\n name: item.name,\n size: BigInt(item.size),\n isDir: item.isDir,\n fullName: item.fullName,\n directory: item.directory,\n lastModified: parseTimestamp(item.lastModified),\n version: item.version,\n }));\n\n return {\n items,\n delimiter: resp.delimiter,\n };\n }\n }\n}\n\nfunction parseTimestamp(timestamp: string): { seconds: bigint; nanos: number } {\n // Parse ISO 8601 format: 2025-08-08T11:12:44.145635532Z\n const date = new Date(timestamp);\n const seconds = BigInt(Math.floor(date.getTime() / 1000));\n\n // Extract fractional seconds from the original string\n const fractionalMatch = timestamp.match(/\\.(\\d+)Z?$/);\n let nanos = 0;\n if (fractionalMatch) {\n const fractionalPart = fractionalMatch[1];\n // Pad or truncate to 9 digits (nanoseconds)\n const padded = fractionalPart.padEnd(9, '0').slice(0, 9);\n nanos = parseInt(padded, 10);\n }\n\n return { seconds, nanos };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -75,7 +75,7 @@ class DownloadBlobTask {
|
|
|
75
75
|
catch (e) {
|
|
76
76
|
this.logger.error(`blob ${plClient.stringifyWithResourceId(this.rInfo)} download failed, `
|
|
77
77
|
+ `state: ${JSON.stringify(this.state)}, `
|
|
78
|
-
+ `error: ${e}`);
|
|
78
|
+
+ `error: ${JSON.stringify(e)}`);
|
|
79
79
|
if (nonRecoverableError(e)) {
|
|
80
80
|
this.setError(e);
|
|
81
81
|
this.change.markChanged(`blob ${plClient.resourceIdToString(this.rInfo.id)} download failed`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download_blob_task.cjs","sources":["../../../src/drivers/download_blob/download_blob_task.ts"],"sourcesContent":["import type { Watcher } from '@milaboratories/computable';\nimport { ChangeSource } from '@milaboratories/computable';\nimport type { LocalBlobHandle, LocalBlobHandleAndSize } from '@milaboratories/pl-model-common';\nimport type { ResourceSnapshot } from '@milaboratories/pl-tree';\nimport type {\n ValueOrError,\n MiLogger,\n} from '@milaboratories/ts-helpers';\nimport {\n ensureDirExists,\n fileExists,\n createPathAtomically,\n CallersCounter,\n} from '@milaboratories/ts-helpers';\nimport fs from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { Writable } from 'node:stream';\nimport type { ClientDownload } from '../../clients/download';\nimport { UnknownStorageError, WrongLocalFileUrl } from '../../clients/download';\nimport { isDownloadNetworkError400 } from '../../helpers/download_errors';\nimport { resourceIdToString, stringifyWithResourceId } from '@milaboratories/pl-client';\n\n/** Downloads a blob and holds callers and watchers for the blob. */\nexport class DownloadBlobTask {\n readonly change = new ChangeSource();\n private readonly signalCtl = new AbortController();\n public readonly counter = new CallersCounter();\n private error: unknown | undefined;\n private done = false;\n public size = 0;\n private state: DownloadState = {};\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientDownload: ClientDownload,\n readonly rInfo: ResourceSnapshot,\n private readonly handle: LocalBlobHandle,\n readonly path: string,\n ) {}\n\n /** Returns a simple object that describes this task for debugging purposes. */\n public info() {\n return {\n rInfo: this.rInfo,\n fPath: this.path,\n done: this.done,\n error: this.error,\n state: this.state,\n };\n }\n\n public attach(w: Watcher, callerId: string) {\n this.counter.inc(callerId);\n if (!this.done) this.change.attachWatcher(w);\n }\n\n public async download() {\n try {\n const size = await this.ensureDownloaded();\n this.setDone(size);\n this.change.markChanged(`blob ${resourceIdToString(this.rInfo.id)} download finished`);\n } catch (e: any) {\n this.logger.error(\n `blob ${stringifyWithResourceId(this.rInfo)} download failed, `\n + `state: ${JSON.stringify(this.state)}, `\n + `error: ${e}`,\n );\n if (nonRecoverableError(e)) {\n this.setError(e);\n this.change.markChanged(`blob ${resourceIdToString(this.rInfo.id)} download failed`);\n // Just in case we were half-way extracting an archive.\n await fsp.rm(this.path, { force: true });\n }\n\n throw e;\n }\n }\n\n private async ensureDownloaded() {\n this.signalCtl.signal.throwIfAborted();\n\n this.state = {};\n this.state.filePath = this.path;\n await ensureDirExists(path.dirname(this.state.filePath));\n this.signalCtl.signal.throwIfAborted();\n this.state.dirExists = true;\n\n const alreadyExists = await fileExists(this.state.filePath);\n this.signalCtl.signal.throwIfAborted();\n if (alreadyExists) {\n this.state.fileExists = true;\n this.logger.info(\n `blob ${stringifyWithResourceId(this.rInfo)} was already downloaded, `\n + `path: ${this.state.filePath}`,\n );\n const stat = await fsp.stat(this.state.filePath);\n this.signalCtl.signal.throwIfAborted();\n this.state.fileSize = stat.size;\n\n return this.state.fileSize;\n }\n\n const fileSize = await this.clientDownload.withBlobContent(\n this.rInfo,\n {},\n { signal: this.signalCtl.signal },\n async (content, size) => {\n this.state.fileSize = size;\n this.state.downloaded = true;\n\n await createPathAtomically(this.logger, this.state.filePath!, async (fPath: string) => {\n const f = Writable.toWeb(fs.createWriteStream(fPath, { flags: 'wx' }));\n await content.pipeTo(f, { signal: this.signalCtl.signal });\n this.state.tempWritten = true;\n });\n\n this.state.done = true;\n return size;\n }\n );\n\n return fileSize;\n }\n\n public abort(reason: string) {\n this.signalCtl.abort(new DownloadAborted(reason));\n }\n\n public getBlob():\n | { done: false }\n | {\n done: true;\n result: ValueOrError<LocalBlobHandleAndSize>;\n } {\n if (!this.done) return { done: false };\n\n return {\n done: this.done,\n result: getDownloadedBlobResponse(this.handle, this.size, this.error),\n };\n }\n\n private setDone(sizeBytes: number) {\n this.done = true;\n this.size = sizeBytes;\n }\n\n private setError(e: unknown) {\n this.done = true;\n this.error = e;\n }\n}\n\nexport function nonRecoverableError(e: any) {\n return (\n e instanceof DownloadAborted\n || isDownloadNetworkError400(e)\n || e instanceof UnknownStorageError\n || e instanceof WrongLocalFileUrl\n // file that we downloads from was moved or deleted.\n || e?.code == 'ENOENT'\n // A resource was deleted.\n || (e.name == 'RpcError' && (e.code == 'NOT_FOUND' || e.code == 'ABORTED'))\n );\n}\n\n/** The downloading task was aborted by a signal.\n * It may happen when the computable is done, for example. */\nclass DownloadAborted extends Error {\n name = 'DownloadAborted';\n}\n\nexport function getDownloadedBlobResponse(\n handle: LocalBlobHandle | undefined,\n size: number,\n error?: unknown,\n): ValueOrError<LocalBlobHandleAndSize> {\n if (error) {\n return { ok: false, error };\n }\n\n if (!handle) {\n return { ok: false, error: new Error('No file or handle provided') };\n }\n\n return {\n ok: true,\n value: {\n handle,\n size,\n },\n };\n}\n\ntype DownloadState = {\n filePath?: string;\n dirExists?: boolean;\n fileExists?: boolean;\n fileSize?: number;\n downloaded?: boolean;\n tempWritten?: boolean;\n done?: boolean;\n}\n"],"names":["ChangeSource","CallersCounter","resourceIdToString","stringifyWithResourceId","fsp","ensureDirExists","path","fileExists","createPathAtomically","Writable","isDownloadNetworkError400","UnknownStorageError","WrongLocalFileUrl"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"download_blob_task.cjs","sources":["../../../src/drivers/download_blob/download_blob_task.ts"],"sourcesContent":["import type { Watcher } from '@milaboratories/computable';\nimport { ChangeSource } from '@milaboratories/computable';\nimport type { LocalBlobHandle, LocalBlobHandleAndSize } from '@milaboratories/pl-model-common';\nimport type { ResourceSnapshot } from '@milaboratories/pl-tree';\nimport type {\n ValueOrError,\n MiLogger,\n} from '@milaboratories/ts-helpers';\nimport {\n ensureDirExists,\n fileExists,\n createPathAtomically,\n CallersCounter,\n} from '@milaboratories/ts-helpers';\nimport fs from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { Writable } from 'node:stream';\nimport type { ClientDownload } from '../../clients/download';\nimport { UnknownStorageError, WrongLocalFileUrl } from '../../clients/download';\nimport { isDownloadNetworkError400 } from '../../helpers/download_errors';\nimport { resourceIdToString, stringifyWithResourceId } from '@milaboratories/pl-client';\n\n/** Downloads a blob and holds callers and watchers for the blob. */\nexport class DownloadBlobTask {\n readonly change = new ChangeSource();\n private readonly signalCtl = new AbortController();\n public readonly counter = new CallersCounter();\n private error: unknown | undefined;\n private done = false;\n public size = 0;\n private state: DownloadState = {};\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientDownload: ClientDownload,\n readonly rInfo: ResourceSnapshot,\n private readonly handle: LocalBlobHandle,\n readonly path: string,\n ) {}\n\n /** Returns a simple object that describes this task for debugging purposes. */\n public info() {\n return {\n rInfo: this.rInfo,\n fPath: this.path,\n done: this.done,\n error: this.error,\n state: this.state,\n };\n }\n\n public attach(w: Watcher, callerId: string) {\n this.counter.inc(callerId);\n if (!this.done) this.change.attachWatcher(w);\n }\n\n public async download() {\n try {\n const size = await this.ensureDownloaded();\n this.setDone(size);\n this.change.markChanged(`blob ${resourceIdToString(this.rInfo.id)} download finished`);\n } catch (e: any) {\n this.logger.error(\n `blob ${stringifyWithResourceId(this.rInfo)} download failed, `\n + `state: ${JSON.stringify(this.state)}, `\n + `error: ${JSON.stringify(e)}`,\n );\n if (nonRecoverableError(e)) {\n this.setError(e);\n this.change.markChanged(`blob ${resourceIdToString(this.rInfo.id)} download failed`);\n // Just in case we were half-way extracting an archive.\n await fsp.rm(this.path, { force: true });\n }\n\n throw e;\n }\n }\n\n private async ensureDownloaded() {\n this.signalCtl.signal.throwIfAborted();\n\n this.state = {};\n this.state.filePath = this.path;\n await ensureDirExists(path.dirname(this.state.filePath));\n this.signalCtl.signal.throwIfAborted();\n this.state.dirExists = true;\n\n const alreadyExists = await fileExists(this.state.filePath);\n this.signalCtl.signal.throwIfAborted();\n if (alreadyExists) {\n this.state.fileExists = true;\n this.logger.info(\n `blob ${stringifyWithResourceId(this.rInfo)} was already downloaded, `\n + `path: ${this.state.filePath}`,\n );\n const stat = await fsp.stat(this.state.filePath);\n this.signalCtl.signal.throwIfAborted();\n this.state.fileSize = stat.size;\n\n return this.state.fileSize;\n }\n\n const fileSize = await this.clientDownload.withBlobContent(\n this.rInfo,\n {},\n { signal: this.signalCtl.signal },\n async (content, size) => {\n this.state.fileSize = size;\n this.state.downloaded = true;\n\n await createPathAtomically(this.logger, this.state.filePath!, async (fPath: string) => {\n const f = Writable.toWeb(fs.createWriteStream(fPath, { flags: 'wx' }));\n await content.pipeTo(f, { signal: this.signalCtl.signal });\n this.state.tempWritten = true;\n });\n\n this.state.done = true;\n return size;\n }\n );\n\n return fileSize;\n }\n\n public abort(reason: string) {\n this.signalCtl.abort(new DownloadAborted(reason));\n }\n\n public getBlob():\n | { done: false }\n | {\n done: true;\n result: ValueOrError<LocalBlobHandleAndSize>;\n } {\n if (!this.done) return { done: false };\n\n return {\n done: this.done,\n result: getDownloadedBlobResponse(this.handle, this.size, this.error),\n };\n }\n\n private setDone(sizeBytes: number) {\n this.done = true;\n this.size = sizeBytes;\n }\n\n private setError(e: unknown) {\n this.done = true;\n this.error = e;\n }\n}\n\nexport function nonRecoverableError(e: any) {\n return (\n e instanceof DownloadAborted\n || isDownloadNetworkError400(e)\n || e instanceof UnknownStorageError\n || e instanceof WrongLocalFileUrl\n // file that we downloads from was moved or deleted.\n || e?.code == 'ENOENT'\n // A resource was deleted.\n || (e.name == 'RpcError' && (e.code == 'NOT_FOUND' || e.code == 'ABORTED'))\n );\n}\n\n/** The downloading task was aborted by a signal.\n * It may happen when the computable is done, for example. */\nclass DownloadAborted extends Error {\n name = 'DownloadAborted';\n}\n\nexport function getDownloadedBlobResponse(\n handle: LocalBlobHandle | undefined,\n size: number,\n error?: unknown,\n): ValueOrError<LocalBlobHandleAndSize> {\n if (error) {\n return { ok: false, error };\n }\n\n if (!handle) {\n return { ok: false, error: new Error('No file or handle provided') };\n }\n\n return {\n ok: true,\n value: {\n handle,\n size,\n },\n };\n}\n\ntype DownloadState = {\n filePath?: string;\n dirExists?: boolean;\n fileExists?: boolean;\n fileSize?: number;\n downloaded?: boolean;\n tempWritten?: boolean;\n done?: boolean;\n}\n"],"names":["ChangeSource","CallersCounter","resourceIdToString","stringifyWithResourceId","fsp","ensureDirExists","path","fileExists","createPathAtomically","Writable","isDownloadNetworkError400","UnknownStorageError","WrongLocalFileUrl"],"mappings":"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"}
|
|
@@ -53,7 +53,7 @@ class DownloadBlobTask {
|
|
|
53
53
|
catch (e) {
|
|
54
54
|
this.logger.error(`blob ${stringifyWithResourceId(this.rInfo)} download failed, `
|
|
55
55
|
+ `state: ${JSON.stringify(this.state)}, `
|
|
56
|
-
+ `error: ${e}`);
|
|
56
|
+
+ `error: ${JSON.stringify(e)}`);
|
|
57
57
|
if (nonRecoverableError(e)) {
|
|
58
58
|
this.setError(e);
|
|
59
59
|
this.change.markChanged(`blob ${resourceIdToString(this.rInfo.id)} download failed`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download_blob_task.js","sources":["../../../src/drivers/download_blob/download_blob_task.ts"],"sourcesContent":["import type { Watcher } from '@milaboratories/computable';\nimport { ChangeSource } from '@milaboratories/computable';\nimport type { LocalBlobHandle, LocalBlobHandleAndSize } from '@milaboratories/pl-model-common';\nimport type { ResourceSnapshot } from '@milaboratories/pl-tree';\nimport type {\n ValueOrError,\n MiLogger,\n} from '@milaboratories/ts-helpers';\nimport {\n ensureDirExists,\n fileExists,\n createPathAtomically,\n CallersCounter,\n} from '@milaboratories/ts-helpers';\nimport fs from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { Writable } from 'node:stream';\nimport type { ClientDownload } from '../../clients/download';\nimport { UnknownStorageError, WrongLocalFileUrl } from '../../clients/download';\nimport { isDownloadNetworkError400 } from '../../helpers/download_errors';\nimport { resourceIdToString, stringifyWithResourceId } from '@milaboratories/pl-client';\n\n/** Downloads a blob and holds callers and watchers for the blob. */\nexport class DownloadBlobTask {\n readonly change = new ChangeSource();\n private readonly signalCtl = new AbortController();\n public readonly counter = new CallersCounter();\n private error: unknown | undefined;\n private done = false;\n public size = 0;\n private state: DownloadState = {};\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientDownload: ClientDownload,\n readonly rInfo: ResourceSnapshot,\n private readonly handle: LocalBlobHandle,\n readonly path: string,\n ) {}\n\n /** Returns a simple object that describes this task for debugging purposes. */\n public info() {\n return {\n rInfo: this.rInfo,\n fPath: this.path,\n done: this.done,\n error: this.error,\n state: this.state,\n };\n }\n\n public attach(w: Watcher, callerId: string) {\n this.counter.inc(callerId);\n if (!this.done) this.change.attachWatcher(w);\n }\n\n public async download() {\n try {\n const size = await this.ensureDownloaded();\n this.setDone(size);\n this.change.markChanged(`blob ${resourceIdToString(this.rInfo.id)} download finished`);\n } catch (e: any) {\n this.logger.error(\n `blob ${stringifyWithResourceId(this.rInfo)} download failed, `\n + `state: ${JSON.stringify(this.state)}, `\n + `error: ${e}`,\n );\n if (nonRecoverableError(e)) {\n this.setError(e);\n this.change.markChanged(`blob ${resourceIdToString(this.rInfo.id)} download failed`);\n // Just in case we were half-way extracting an archive.\n await fsp.rm(this.path, { force: true });\n }\n\n throw e;\n }\n }\n\n private async ensureDownloaded() {\n this.signalCtl.signal.throwIfAborted();\n\n this.state = {};\n this.state.filePath = this.path;\n await ensureDirExists(path.dirname(this.state.filePath));\n this.signalCtl.signal.throwIfAborted();\n this.state.dirExists = true;\n\n const alreadyExists = await fileExists(this.state.filePath);\n this.signalCtl.signal.throwIfAborted();\n if (alreadyExists) {\n this.state.fileExists = true;\n this.logger.info(\n `blob ${stringifyWithResourceId(this.rInfo)} was already downloaded, `\n + `path: ${this.state.filePath}`,\n );\n const stat = await fsp.stat(this.state.filePath);\n this.signalCtl.signal.throwIfAborted();\n this.state.fileSize = stat.size;\n\n return this.state.fileSize;\n }\n\n const fileSize = await this.clientDownload.withBlobContent(\n this.rInfo,\n {},\n { signal: this.signalCtl.signal },\n async (content, size) => {\n this.state.fileSize = size;\n this.state.downloaded = true;\n\n await createPathAtomically(this.logger, this.state.filePath!, async (fPath: string) => {\n const f = Writable.toWeb(fs.createWriteStream(fPath, { flags: 'wx' }));\n await content.pipeTo(f, { signal: this.signalCtl.signal });\n this.state.tempWritten = true;\n });\n\n this.state.done = true;\n return size;\n }\n );\n\n return fileSize;\n }\n\n public abort(reason: string) {\n this.signalCtl.abort(new DownloadAborted(reason));\n }\n\n public getBlob():\n | { done: false }\n | {\n done: true;\n result: ValueOrError<LocalBlobHandleAndSize>;\n } {\n if (!this.done) return { done: false };\n\n return {\n done: this.done,\n result: getDownloadedBlobResponse(this.handle, this.size, this.error),\n };\n }\n\n private setDone(sizeBytes: number) {\n this.done = true;\n this.size = sizeBytes;\n }\n\n private setError(e: unknown) {\n this.done = true;\n this.error = e;\n }\n}\n\nexport function nonRecoverableError(e: any) {\n return (\n e instanceof DownloadAborted\n || isDownloadNetworkError400(e)\n || e instanceof UnknownStorageError\n || e instanceof WrongLocalFileUrl\n // file that we downloads from was moved or deleted.\n || e?.code == 'ENOENT'\n // A resource was deleted.\n || (e.name == 'RpcError' && (e.code == 'NOT_FOUND' || e.code == 'ABORTED'))\n );\n}\n\n/** The downloading task was aborted by a signal.\n * It may happen when the computable is done, for example. */\nclass DownloadAborted extends Error {\n name = 'DownloadAborted';\n}\n\nexport function getDownloadedBlobResponse(\n handle: LocalBlobHandle | undefined,\n size: number,\n error?: unknown,\n): ValueOrError<LocalBlobHandleAndSize> {\n if (error) {\n return { ok: false, error };\n }\n\n if (!handle) {\n return { ok: false, error: new Error('No file or handle provided') };\n }\n\n return {\n ok: true,\n value: {\n handle,\n size,\n },\n };\n}\n\ntype DownloadState = {\n filePath?: string;\n dirExists?: boolean;\n fileExists?: boolean;\n fileSize?: number;\n downloaded?: boolean;\n tempWritten?: boolean;\n done?: boolean;\n}\n"],"names":["fs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"download_blob_task.js","sources":["../../../src/drivers/download_blob/download_blob_task.ts"],"sourcesContent":["import type { Watcher } from '@milaboratories/computable';\nimport { ChangeSource } from '@milaboratories/computable';\nimport type { LocalBlobHandle, LocalBlobHandleAndSize } from '@milaboratories/pl-model-common';\nimport type { ResourceSnapshot } from '@milaboratories/pl-tree';\nimport type {\n ValueOrError,\n MiLogger,\n} from '@milaboratories/ts-helpers';\nimport {\n ensureDirExists,\n fileExists,\n createPathAtomically,\n CallersCounter,\n} from '@milaboratories/ts-helpers';\nimport fs from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { Writable } from 'node:stream';\nimport type { ClientDownload } from '../../clients/download';\nimport { UnknownStorageError, WrongLocalFileUrl } from '../../clients/download';\nimport { isDownloadNetworkError400 } from '../../helpers/download_errors';\nimport { resourceIdToString, stringifyWithResourceId } from '@milaboratories/pl-client';\n\n/** Downloads a blob and holds callers and watchers for the blob. */\nexport class DownloadBlobTask {\n readonly change = new ChangeSource();\n private readonly signalCtl = new AbortController();\n public readonly counter = new CallersCounter();\n private error: unknown | undefined;\n private done = false;\n public size = 0;\n private state: DownloadState = {};\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientDownload: ClientDownload,\n readonly rInfo: ResourceSnapshot,\n private readonly handle: LocalBlobHandle,\n readonly path: string,\n ) {}\n\n /** Returns a simple object that describes this task for debugging purposes. */\n public info() {\n return {\n rInfo: this.rInfo,\n fPath: this.path,\n done: this.done,\n error: this.error,\n state: this.state,\n };\n }\n\n public attach(w: Watcher, callerId: string) {\n this.counter.inc(callerId);\n if (!this.done) this.change.attachWatcher(w);\n }\n\n public async download() {\n try {\n const size = await this.ensureDownloaded();\n this.setDone(size);\n this.change.markChanged(`blob ${resourceIdToString(this.rInfo.id)} download finished`);\n } catch (e: any) {\n this.logger.error(\n `blob ${stringifyWithResourceId(this.rInfo)} download failed, `\n + `state: ${JSON.stringify(this.state)}, `\n + `error: ${JSON.stringify(e)}`,\n );\n if (nonRecoverableError(e)) {\n this.setError(e);\n this.change.markChanged(`blob ${resourceIdToString(this.rInfo.id)} download failed`);\n // Just in case we were half-way extracting an archive.\n await fsp.rm(this.path, { force: true });\n }\n\n throw e;\n }\n }\n\n private async ensureDownloaded() {\n this.signalCtl.signal.throwIfAborted();\n\n this.state = {};\n this.state.filePath = this.path;\n await ensureDirExists(path.dirname(this.state.filePath));\n this.signalCtl.signal.throwIfAborted();\n this.state.dirExists = true;\n\n const alreadyExists = await fileExists(this.state.filePath);\n this.signalCtl.signal.throwIfAborted();\n if (alreadyExists) {\n this.state.fileExists = true;\n this.logger.info(\n `blob ${stringifyWithResourceId(this.rInfo)} was already downloaded, `\n + `path: ${this.state.filePath}`,\n );\n const stat = await fsp.stat(this.state.filePath);\n this.signalCtl.signal.throwIfAborted();\n this.state.fileSize = stat.size;\n\n return this.state.fileSize;\n }\n\n const fileSize = await this.clientDownload.withBlobContent(\n this.rInfo,\n {},\n { signal: this.signalCtl.signal },\n async (content, size) => {\n this.state.fileSize = size;\n this.state.downloaded = true;\n\n await createPathAtomically(this.logger, this.state.filePath!, async (fPath: string) => {\n const f = Writable.toWeb(fs.createWriteStream(fPath, { flags: 'wx' }));\n await content.pipeTo(f, { signal: this.signalCtl.signal });\n this.state.tempWritten = true;\n });\n\n this.state.done = true;\n return size;\n }\n );\n\n return fileSize;\n }\n\n public abort(reason: string) {\n this.signalCtl.abort(new DownloadAborted(reason));\n }\n\n public getBlob():\n | { done: false }\n | {\n done: true;\n result: ValueOrError<LocalBlobHandleAndSize>;\n } {\n if (!this.done) return { done: false };\n\n return {\n done: this.done,\n result: getDownloadedBlobResponse(this.handle, this.size, this.error),\n };\n }\n\n private setDone(sizeBytes: number) {\n this.done = true;\n this.size = sizeBytes;\n }\n\n private setError(e: unknown) {\n this.done = true;\n this.error = e;\n }\n}\n\nexport function nonRecoverableError(e: any) {\n return (\n e instanceof DownloadAborted\n || isDownloadNetworkError400(e)\n || e instanceof UnknownStorageError\n || e instanceof WrongLocalFileUrl\n // file that we downloads from was moved or deleted.\n || e?.code == 'ENOENT'\n // A resource was deleted.\n || (e.name == 'RpcError' && (e.code == 'NOT_FOUND' || e.code == 'ABORTED'))\n );\n}\n\n/** The downloading task was aborted by a signal.\n * It may happen when the computable is done, for example. */\nclass DownloadAborted extends Error {\n name = 'DownloadAborted';\n}\n\nexport function getDownloadedBlobResponse(\n handle: LocalBlobHandle | undefined,\n size: number,\n error?: unknown,\n): ValueOrError<LocalBlobHandleAndSize> {\n if (error) {\n return { ok: false, error };\n }\n\n if (!handle) {\n return { ok: false, error: new Error('No file or handle provided') };\n }\n\n return {\n ok: true,\n value: {\n handle,\n size,\n },\n };\n}\n\ntype DownloadState = {\n filePath?: string;\n dirExists?: boolean;\n fileExists?: boolean;\n fileSize?: number;\n downloaded?: boolean;\n tempWritten?: boolean;\n done?: boolean;\n}\n"],"names":["fs"],"mappings":"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"}
|
|
@@ -222,7 +222,7 @@ class LogGetter {
|
|
|
222
222
|
this.change.markChanged();
|
|
223
223
|
return;
|
|
224
224
|
}
|
|
225
|
-
this.logger.error(`Stream log lines for ${plClient.stringifyWithResourceId(this.rInfo.id)} failed, reason: ${e}`);
|
|
225
|
+
this.logger.error(`Stream log lines for ${plClient.stringifyWithResourceId(this.rInfo.id)} failed, reason: ${JSON.stringify(e)}`);
|
|
226
226
|
throw e;
|
|
227
227
|
}
|
|
228
228
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logs_stream.cjs","sources":["../../src/drivers/logs_stream.ts"],"sourcesContent":["import type {\n ComputableCtx,\n Watcher,\n} from '@milaboratories/computable';\nimport {\n ChangeSource,\n Computable,\n PollingComputableHooks,\n} from '@milaboratories/computable';\nimport type {\n ResourceId,\n ResourceType } from '@milaboratories/pl-client';\nimport {\n resourceIdToString,\n stringifyWithResourceId,\n} from '@milaboratories/pl-client';\nimport type { MiLogger } from '@milaboratories/ts-helpers';\nimport { asyncPool, CallersCounter } from '@milaboratories/ts-helpers';\nimport type { ClientLogs } from '../clients/logs';\nimport { randomUUID } from 'node:crypto';\nimport type { PlTreeEntry, ResourceInfo } from '@milaboratories/pl-tree';\nimport { treeEntryToResourceInfo } from '@milaboratories/pl-tree';\nimport { scheduler } from 'node:timers/promises';\nimport type { StreamingAPI_Response } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol';\nimport type * as sdk from '@milaboratories/pl-model-common';\nimport type { PollingOps } from './helpers/polling_ops';\nimport type { RpcError } from '@protobuf-ts/runtime-rpc';\nimport { getResourceInfoFromLogHandle, isLiveLogHandle, newLogHandle } from './helpers/logs_handle';\nimport { WrongResourceTypeError } from './helpers/helpers';\n\nexport type LogsStreamDriverOps = PollingOps & {\n /** Max number of concurrent requests to log streaming backend while calculating computable states */\n nConcurrentGetLogs: number;\n};\n\nexport class LogsStreamDriver implements sdk.LogsDriver {\n /** Holds a map of StreamManager Resource Id to all logs of this stream. */\n private readonly idToLastLines: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to the last log line of this stream. */\n private readonly idToProgressLog: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to log id smart object. */\n private readonly hooks: PollingComputableHooks;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly opts: LogsStreamDriverOps = {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n ) {\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: opts.stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n getLastLogs(res: ResourceInfo | PlTreeEntry, lines: number): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx: ComputableCtx\n ): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined) return Computable.make((ctx) => this.getLastLogs(res, lines, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseLastLogs(r.id, callerId));\n\n const result = this.getLastLogsNoCtx(ctx.watcher, r, lines, callerId);\n ctx.markUnstable(\n 'The logs are from stream, so we consider them unstable. Final values will be got from blobs.',\n );\n\n return result;\n }\n\n private getLastLogsNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n lines: number,\n callerId: string,\n ): string | undefined {\n validateResourceType('getLastLogs', rInfo.type);\n\n let logGetter = this.idToLastLines.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, lines);\n this.idToLastLines.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error != undefined) throw result.error;\n\n return result.log;\n }\n\n /** Returns a last line that has patternToSearch.\n * Notifies when a new line appeared or EOF reached. */\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string\n ): Computable<string | undefined>;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx: ComputableCtx\n ): string | undefined;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined)\n return Computable.make((ctx) => this.getProgressLog(res, patternToSearch, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseProgressLog(r.id, callerId));\n\n const result = this.getProgressLogNoCtx(ctx.watcher, r, patternToSearch, callerId);\n ctx.markUnstable(\n 'The progress log is from the stream, so we consider it unstable. Final value will be got from blobs.',\n );\n\n return result;\n }\n\n private getProgressLogNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n patternToSearch: string,\n callerId: string,\n ): string | undefined {\n validateResourceType('getProgressLog', rInfo.type);\n\n let logGetter = this.idToProgressLog.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, 1, patternToSearch);\n this.idToProgressLog.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error) throw result.error;\n\n return result.log;\n }\n\n getLogHandle(res: ResourceInfo | PlTreeEntry): Computable<sdk.AnyLogHandle>;\n getLogHandle(res: ResourceInfo | PlTreeEntry, ctx: ComputableCtx): sdk.AnyLogHandle;\n getLogHandle(\n res: ResourceInfo | PlTreeEntry,\n ctx?: ComputableCtx,\n ): Computable<sdk.AnyLogHandle> | sdk.AnyLogHandle {\n if (ctx == undefined) return Computable.make((ctx) => this.getLogHandle(res, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n\n const result = this.getLogHandleNoCtx(r);\n\n // All logs from streams should be considered unstable,\n // final value will be got from blobs.\n ctx.markUnstable(`live_log:${resourceIdToString(r.id)}`);\n\n return result;\n }\n\n private getLogHandleNoCtx(rInfo: ResourceInfo): sdk.AnyLogHandle {\n validateResourceType('getLogHandle', rInfo.type);\n\n return newLogHandle(true, rInfo);\n }\n\n async lastLines(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.lastLines(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n async readText(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.readText(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n private async tryWithNotFound(\n handle: sdk.AnyLogHandle,\n method: () => Promise<StreamingAPI_Response>,\n ): Promise<sdk.StreamingApiResponse> {\n if (!isLiveLogHandle(handle))\n throw new Error(`Not live log handle was passed to live log driver, handle: ${handle}`);\n\n try {\n const resp = await method();\n return {\n live: true,\n shouldUpdateHandle: false,\n data: resp.data,\n size: Number(resp.size),\n newOffset: Number(resp.newOffset),\n };\n } catch (e: any) {\n if (e.name == 'RpcError' && e.code == 'NOT_FOUND') {\n return { shouldUpdateHandle: true };\n }\n\n throw e;\n }\n }\n\n private async releaseLastLogs(rId: ResourceId, callerId: string) {\n const deleted = this.idToLastLines.get(rId)?.release(callerId);\n if (deleted) this.idToLastLines.delete(rId);\n }\n\n private async releaseProgressLog(rId: ResourceId, callerId: string) {\n const deleted = this.idToProgressLog.get(rId)?.release(callerId);\n if (deleted) this.idToProgressLog.delete(rId);\n }\n\n async releaseAll() {}\n\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n this.scheduledOnNextState.push({ resolve, reject });\n }\n\n /** Called from observer */\n private startUpdating(): void {\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n private async mainLoop() {\n while (this.keepRunning) {\n const toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n\n try {\n const logs = this.getAllLogs();\n await asyncPool(\n this.opts.nConcurrentGetLogs,\n logs.map((getter) => async () => await getter.update()),\n );\n\n toNotify.forEach((n) => n.resolve());\n } catch (e: any) {\n console.error(e);\n toNotify.forEach((n) => n.reject(e));\n }\n\n if (!this.keepRunning) break;\n await scheduler.wait(this.opts.pollingInterval);\n }\n\n this.currentLoop = undefined;\n }\n\n private getAllLogs(): Array<LogGetter> {\n return Array.from(this.idToLastLines.entries())\n .concat(Array.from(this.idToProgressLog.entries()))\n .map(([_, getter]) => getter);\n }\n}\n\n/** A job that gets last lines from a StreamWorkdir resource. */\nclass LogGetter {\n private logs: string | undefined;\n private error: any | undefined = undefined;\n\n private readonly change: ChangeSource = new ChangeSource();\n private readonly counter: CallersCounter = new CallersCounter();\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly rInfo: ResourceInfo,\n private readonly lines: number,\n private readonly patternToSearch?: string,\n ) {}\n\n getLog(): {\n log: string | undefined;\n error?: any | undefined;\n } {\n return {\n log: this.logs,\n error: this.error,\n };\n }\n\n attach(w: Watcher, callerId: string) {\n this.change.attachWatcher(w);\n this.counter.inc(callerId);\n }\n\n release(callerId: string): boolean {\n return this.counter.dec(callerId);\n }\n\n async update() {\n try {\n const resp = await this.clientLogs.lastLines(\n this.rInfo,\n this.lines,\n 0n,\n this.patternToSearch,\n );\n\n const newLogs = new TextDecoder().decode(resp.data);\n if (this.logs != newLogs) this.change.markChanged(`logs for ${resourceIdToString(this.rInfo.id)} updated`);\n this.logs = newLogs;\n this.error = undefined;\n\n return;\n } catch (e: any) {\n e as RpcError;\n if (e.name == 'RpcError' && e.code == 'NOT_FOUND') {\n // No resource\n this.logs = '';\n this.error = e;\n this.change.markChanged();\n return;\n }\n\n this.logger.error(\n `Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${e}`,\n );\n throw e;\n }\n }\n}\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nfunction validateResourceType(methodName: string, rType: ResourceType) {\n if (!rType.name.startsWith('StreamWorkdir')) {\n throw new WrongResourceTypeError(\n `${methodName}: wrong resource type: ${rType.name}, `\n + `expected: a resource of type 'StreamWorkdir'.`,\n );\n }\n}\n"],"names":["PollingComputableHooks","Computable","treeEntryToResourceInfo","randomUUID","resourceIdToString","newLogHandle","getResourceInfoFromLogHandle","isLiveLogHandle","asyncPool","scheduler","ChangeSource","CallersCounter","stringifyWithResourceId","WrongResourceTypeError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logs_stream.cjs","sources":["../../src/drivers/logs_stream.ts"],"sourcesContent":["import type {\n ComputableCtx,\n Watcher,\n} from '@milaboratories/computable';\nimport {\n ChangeSource,\n Computable,\n PollingComputableHooks,\n} from '@milaboratories/computable';\nimport type {\n ResourceId,\n ResourceType } from '@milaboratories/pl-client';\nimport {\n resourceIdToString,\n stringifyWithResourceId,\n} from '@milaboratories/pl-client';\nimport type { MiLogger } from '@milaboratories/ts-helpers';\nimport { asyncPool, CallersCounter } from '@milaboratories/ts-helpers';\nimport type { ClientLogs } from '../clients/logs';\nimport { randomUUID } from 'node:crypto';\nimport type { PlTreeEntry, ResourceInfo } from '@milaboratories/pl-tree';\nimport { treeEntryToResourceInfo } from '@milaboratories/pl-tree';\nimport { scheduler } from 'node:timers/promises';\nimport type { StreamingAPI_Response } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol';\nimport type * as sdk from '@milaboratories/pl-model-common';\nimport type { PollingOps } from './helpers/polling_ops';\nimport type { RpcError } from '@protobuf-ts/runtime-rpc';\nimport { getResourceInfoFromLogHandle, isLiveLogHandle, newLogHandle } from './helpers/logs_handle';\nimport { WrongResourceTypeError } from './helpers/helpers';\n\nexport type LogsStreamDriverOps = PollingOps & {\n /** Max number of concurrent requests to log streaming backend while calculating computable states */\n nConcurrentGetLogs: number;\n};\n\nexport class LogsStreamDriver implements sdk.LogsDriver {\n /** Holds a map of StreamManager Resource Id to all logs of this stream. */\n private readonly idToLastLines: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to the last log line of this stream. */\n private readonly idToProgressLog: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to log id smart object. */\n private readonly hooks: PollingComputableHooks;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly opts: LogsStreamDriverOps = {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n ) {\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: opts.stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n getLastLogs(res: ResourceInfo | PlTreeEntry, lines: number): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx: ComputableCtx\n ): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined) return Computable.make((ctx) => this.getLastLogs(res, lines, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseLastLogs(r.id, callerId));\n\n const result = this.getLastLogsNoCtx(ctx.watcher, r, lines, callerId);\n ctx.markUnstable(\n 'The logs are from stream, so we consider them unstable. Final values will be got from blobs.',\n );\n\n return result;\n }\n\n private getLastLogsNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n lines: number,\n callerId: string,\n ): string | undefined {\n validateResourceType('getLastLogs', rInfo.type);\n\n let logGetter = this.idToLastLines.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, lines);\n this.idToLastLines.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error != undefined) throw result.error;\n\n return result.log;\n }\n\n /** Returns a last line that has patternToSearch.\n * Notifies when a new line appeared or EOF reached. */\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string\n ): Computable<string | undefined>;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx: ComputableCtx\n ): string | undefined;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined)\n return Computable.make((ctx) => this.getProgressLog(res, patternToSearch, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseProgressLog(r.id, callerId));\n\n const result = this.getProgressLogNoCtx(ctx.watcher, r, patternToSearch, callerId);\n ctx.markUnstable(\n 'The progress log is from the stream, so we consider it unstable. Final value will be got from blobs.',\n );\n\n return result;\n }\n\n private getProgressLogNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n patternToSearch: string,\n callerId: string,\n ): string | undefined {\n validateResourceType('getProgressLog', rInfo.type);\n\n let logGetter = this.idToProgressLog.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, 1, patternToSearch);\n this.idToProgressLog.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error) throw result.error;\n\n return result.log;\n }\n\n getLogHandle(res: ResourceInfo | PlTreeEntry): Computable<sdk.AnyLogHandle>;\n getLogHandle(res: ResourceInfo | PlTreeEntry, ctx: ComputableCtx): sdk.AnyLogHandle;\n getLogHandle(\n res: ResourceInfo | PlTreeEntry,\n ctx?: ComputableCtx,\n ): Computable<sdk.AnyLogHandle> | sdk.AnyLogHandle {\n if (ctx == undefined) return Computable.make((ctx) => this.getLogHandle(res, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n\n const result = this.getLogHandleNoCtx(r);\n\n // All logs from streams should be considered unstable,\n // final value will be got from blobs.\n ctx.markUnstable(`live_log:${resourceIdToString(r.id)}`);\n\n return result;\n }\n\n private getLogHandleNoCtx(rInfo: ResourceInfo): sdk.AnyLogHandle {\n validateResourceType('getLogHandle', rInfo.type);\n\n return newLogHandle(true, rInfo);\n }\n\n async lastLines(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.lastLines(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n async readText(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.readText(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n private async tryWithNotFound(\n handle: sdk.AnyLogHandle,\n method: () => Promise<StreamingAPI_Response>,\n ): Promise<sdk.StreamingApiResponse> {\n if (!isLiveLogHandle(handle))\n throw new Error(`Not live log handle was passed to live log driver, handle: ${handle}`);\n\n try {\n const resp = await method();\n return {\n live: true,\n shouldUpdateHandle: false,\n data: resp.data,\n size: Number(resp.size),\n newOffset: Number(resp.newOffset),\n };\n } catch (e: any) {\n if (e.name == 'RpcError' && e.code == 'NOT_FOUND') {\n return { shouldUpdateHandle: true };\n }\n\n throw e;\n }\n }\n\n private async releaseLastLogs(rId: ResourceId, callerId: string) {\n const deleted = this.idToLastLines.get(rId)?.release(callerId);\n if (deleted) this.idToLastLines.delete(rId);\n }\n\n private async releaseProgressLog(rId: ResourceId, callerId: string) {\n const deleted = this.idToProgressLog.get(rId)?.release(callerId);\n if (deleted) this.idToProgressLog.delete(rId);\n }\n\n async releaseAll() {}\n\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n this.scheduledOnNextState.push({ resolve, reject });\n }\n\n /** Called from observer */\n private startUpdating(): void {\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n private async mainLoop() {\n while (this.keepRunning) {\n const toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n\n try {\n const logs = this.getAllLogs();\n await asyncPool(\n this.opts.nConcurrentGetLogs,\n logs.map((getter) => async () => await getter.update()),\n );\n\n toNotify.forEach((n) => n.resolve());\n } catch (e: any) {\n console.error(e);\n toNotify.forEach((n) => n.reject(e));\n }\n\n if (!this.keepRunning) break;\n await scheduler.wait(this.opts.pollingInterval);\n }\n\n this.currentLoop = undefined;\n }\n\n private getAllLogs(): Array<LogGetter> {\n return Array.from(this.idToLastLines.entries())\n .concat(Array.from(this.idToProgressLog.entries()))\n .map(([_, getter]) => getter);\n }\n}\n\n/** A job that gets last lines from a StreamWorkdir resource. */\nclass LogGetter {\n private logs: string | undefined;\n private error: any | undefined = undefined;\n\n private readonly change: ChangeSource = new ChangeSource();\n private readonly counter: CallersCounter = new CallersCounter();\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly rInfo: ResourceInfo,\n private readonly lines: number,\n private readonly patternToSearch?: string,\n ) {}\n\n getLog(): {\n log: string | undefined;\n error?: any | undefined;\n } {\n return {\n log: this.logs,\n error: this.error,\n };\n }\n\n attach(w: Watcher, callerId: string) {\n this.change.attachWatcher(w);\n this.counter.inc(callerId);\n }\n\n release(callerId: string): boolean {\n return this.counter.dec(callerId);\n }\n\n async update() {\n try {\n const resp = await this.clientLogs.lastLines(\n this.rInfo,\n this.lines,\n 0n,\n this.patternToSearch,\n );\n\n const newLogs = new TextDecoder().decode(resp.data);\n if (this.logs != newLogs) this.change.markChanged(`logs for ${resourceIdToString(this.rInfo.id)} updated`);\n this.logs = newLogs;\n this.error = undefined;\n\n return;\n } catch (e: any) {\n e as RpcError;\n if (e.name == 'RpcError' && e.code == 'NOT_FOUND') {\n // No resource\n this.logs = '';\n this.error = e;\n this.change.markChanged();\n return;\n }\n\n this.logger.error(\n `Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${JSON.stringify(e)}`,\n );\n throw e;\n }\n }\n}\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nfunction validateResourceType(methodName: string, rType: ResourceType) {\n if (!rType.name.startsWith('StreamWorkdir')) {\n throw new WrongResourceTypeError(\n `${methodName}: wrong resource type: ${rType.name}, `\n + `expected: a resource of type 'StreamWorkdir'.`,\n );\n }\n}\n"],"names":["PollingComputableHooks","Computable","treeEntryToResourceInfo","randomUUID","resourceIdToString","newLogHandle","getResourceInfoFromLogHandle","isLiveLogHandle","asyncPool","scheduler","ChangeSource","CallersCounter","stringifyWithResourceId","WrongResourceTypeError"],"mappings":"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"}
|
|
@@ -220,7 +220,7 @@ class LogGetter {
|
|
|
220
220
|
this.change.markChanged();
|
|
221
221
|
return;
|
|
222
222
|
}
|
|
223
|
-
this.logger.error(`Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${e}`);
|
|
223
|
+
this.logger.error(`Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${JSON.stringify(e)}`);
|
|
224
224
|
throw e;
|
|
225
225
|
}
|
|
226
226
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logs_stream.js","sources":["../../src/drivers/logs_stream.ts"],"sourcesContent":["import type {\n ComputableCtx,\n Watcher,\n} from '@milaboratories/computable';\nimport {\n ChangeSource,\n Computable,\n PollingComputableHooks,\n} from '@milaboratories/computable';\nimport type {\n ResourceId,\n ResourceType } from '@milaboratories/pl-client';\nimport {\n resourceIdToString,\n stringifyWithResourceId,\n} from '@milaboratories/pl-client';\nimport type { MiLogger } from '@milaboratories/ts-helpers';\nimport { asyncPool, CallersCounter } from '@milaboratories/ts-helpers';\nimport type { ClientLogs } from '../clients/logs';\nimport { randomUUID } from 'node:crypto';\nimport type { PlTreeEntry, ResourceInfo } from '@milaboratories/pl-tree';\nimport { treeEntryToResourceInfo } from '@milaboratories/pl-tree';\nimport { scheduler } from 'node:timers/promises';\nimport type { StreamingAPI_Response } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol';\nimport type * as sdk from '@milaboratories/pl-model-common';\nimport type { PollingOps } from './helpers/polling_ops';\nimport type { RpcError } from '@protobuf-ts/runtime-rpc';\nimport { getResourceInfoFromLogHandle, isLiveLogHandle, newLogHandle } from './helpers/logs_handle';\nimport { WrongResourceTypeError } from './helpers/helpers';\n\nexport type LogsStreamDriverOps = PollingOps & {\n /** Max number of concurrent requests to log streaming backend while calculating computable states */\n nConcurrentGetLogs: number;\n};\n\nexport class LogsStreamDriver implements sdk.LogsDriver {\n /** Holds a map of StreamManager Resource Id to all logs of this stream. */\n private readonly idToLastLines: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to the last log line of this stream. */\n private readonly idToProgressLog: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to log id smart object. */\n private readonly hooks: PollingComputableHooks;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly opts: LogsStreamDriverOps = {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n ) {\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: opts.stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n getLastLogs(res: ResourceInfo | PlTreeEntry, lines: number): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx: ComputableCtx\n ): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined) return Computable.make((ctx) => this.getLastLogs(res, lines, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseLastLogs(r.id, callerId));\n\n const result = this.getLastLogsNoCtx(ctx.watcher, r, lines, callerId);\n ctx.markUnstable(\n 'The logs are from stream, so we consider them unstable. Final values will be got from blobs.',\n );\n\n return result;\n }\n\n private getLastLogsNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n lines: number,\n callerId: string,\n ): string | undefined {\n validateResourceType('getLastLogs', rInfo.type);\n\n let logGetter = this.idToLastLines.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, lines);\n this.idToLastLines.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error != undefined) throw result.error;\n\n return result.log;\n }\n\n /** Returns a last line that has patternToSearch.\n * Notifies when a new line appeared or EOF reached. */\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string\n ): Computable<string | undefined>;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx: ComputableCtx\n ): string | undefined;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined)\n return Computable.make((ctx) => this.getProgressLog(res, patternToSearch, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseProgressLog(r.id, callerId));\n\n const result = this.getProgressLogNoCtx(ctx.watcher, r, patternToSearch, callerId);\n ctx.markUnstable(\n 'The progress log is from the stream, so we consider it unstable. Final value will be got from blobs.',\n );\n\n return result;\n }\n\n private getProgressLogNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n patternToSearch: string,\n callerId: string,\n ): string | undefined {\n validateResourceType('getProgressLog', rInfo.type);\n\n let logGetter = this.idToProgressLog.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, 1, patternToSearch);\n this.idToProgressLog.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error) throw result.error;\n\n return result.log;\n }\n\n getLogHandle(res: ResourceInfo | PlTreeEntry): Computable<sdk.AnyLogHandle>;\n getLogHandle(res: ResourceInfo | PlTreeEntry, ctx: ComputableCtx): sdk.AnyLogHandle;\n getLogHandle(\n res: ResourceInfo | PlTreeEntry,\n ctx?: ComputableCtx,\n ): Computable<sdk.AnyLogHandle> | sdk.AnyLogHandle {\n if (ctx == undefined) return Computable.make((ctx) => this.getLogHandle(res, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n\n const result = this.getLogHandleNoCtx(r);\n\n // All logs from streams should be considered unstable,\n // final value will be got from blobs.\n ctx.markUnstable(`live_log:${resourceIdToString(r.id)}`);\n\n return result;\n }\n\n private getLogHandleNoCtx(rInfo: ResourceInfo): sdk.AnyLogHandle {\n validateResourceType('getLogHandle', rInfo.type);\n\n return newLogHandle(true, rInfo);\n }\n\n async lastLines(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.lastLines(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n async readText(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.readText(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n private async tryWithNotFound(\n handle: sdk.AnyLogHandle,\n method: () => Promise<StreamingAPI_Response>,\n ): Promise<sdk.StreamingApiResponse> {\n if (!isLiveLogHandle(handle))\n throw new Error(`Not live log handle was passed to live log driver, handle: ${handle}`);\n\n try {\n const resp = await method();\n return {\n live: true,\n shouldUpdateHandle: false,\n data: resp.data,\n size: Number(resp.size),\n newOffset: Number(resp.newOffset),\n };\n } catch (e: any) {\n if (e.name == 'RpcError' && e.code == 'NOT_FOUND') {\n return { shouldUpdateHandle: true };\n }\n\n throw e;\n }\n }\n\n private async releaseLastLogs(rId: ResourceId, callerId: string) {\n const deleted = this.idToLastLines.get(rId)?.release(callerId);\n if (deleted) this.idToLastLines.delete(rId);\n }\n\n private async releaseProgressLog(rId: ResourceId, callerId: string) {\n const deleted = this.idToProgressLog.get(rId)?.release(callerId);\n if (deleted) this.idToProgressLog.delete(rId);\n }\n\n async releaseAll() {}\n\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n this.scheduledOnNextState.push({ resolve, reject });\n }\n\n /** Called from observer */\n private startUpdating(): void {\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n private async mainLoop() {\n while (this.keepRunning) {\n const toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n\n try {\n const logs = this.getAllLogs();\n await asyncPool(\n this.opts.nConcurrentGetLogs,\n logs.map((getter) => async () => await getter.update()),\n );\n\n toNotify.forEach((n) => n.resolve());\n } catch (e: any) {\n console.error(e);\n toNotify.forEach((n) => n.reject(e));\n }\n\n if (!this.keepRunning) break;\n await scheduler.wait(this.opts.pollingInterval);\n }\n\n this.currentLoop = undefined;\n }\n\n private getAllLogs(): Array<LogGetter> {\n return Array.from(this.idToLastLines.entries())\n .concat(Array.from(this.idToProgressLog.entries()))\n .map(([_, getter]) => getter);\n }\n}\n\n/** A job that gets last lines from a StreamWorkdir resource. */\nclass LogGetter {\n private logs: string | undefined;\n private error: any | undefined = undefined;\n\n private readonly change: ChangeSource = new ChangeSource();\n private readonly counter: CallersCounter = new CallersCounter();\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly rInfo: ResourceInfo,\n private readonly lines: number,\n private readonly patternToSearch?: string,\n ) {}\n\n getLog(): {\n log: string | undefined;\n error?: any | undefined;\n } {\n return {\n log: this.logs,\n error: this.error,\n };\n }\n\n attach(w: Watcher, callerId: string) {\n this.change.attachWatcher(w);\n this.counter.inc(callerId);\n }\n\n release(callerId: string): boolean {\n return this.counter.dec(callerId);\n }\n\n async update() {\n try {\n const resp = await this.clientLogs.lastLines(\n this.rInfo,\n this.lines,\n 0n,\n this.patternToSearch,\n );\n\n const newLogs = new TextDecoder().decode(resp.data);\n if (this.logs != newLogs) this.change.markChanged(`logs for ${resourceIdToString(this.rInfo.id)} updated`);\n this.logs = newLogs;\n this.error = undefined;\n\n return;\n } catch (e: any) {\n e as RpcError;\n if (e.name == 'RpcError' && e.code == 'NOT_FOUND') {\n // No resource\n this.logs = '';\n this.error = e;\n this.change.markChanged();\n return;\n }\n\n this.logger.error(\n `Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${e}`,\n );\n throw e;\n }\n }\n}\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nfunction validateResourceType(methodName: string, rType: ResourceType) {\n if (!rType.name.startsWith('StreamWorkdir')) {\n throw new WrongResourceTypeError(\n `${methodName}: wrong resource type: ${rType.name}, `\n + `expected: a resource of type 'StreamWorkdir'.`,\n );\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logs_stream.js","sources":["../../src/drivers/logs_stream.ts"],"sourcesContent":["import type {\n ComputableCtx,\n Watcher,\n} from '@milaboratories/computable';\nimport {\n ChangeSource,\n Computable,\n PollingComputableHooks,\n} from '@milaboratories/computable';\nimport type {\n ResourceId,\n ResourceType } from '@milaboratories/pl-client';\nimport {\n resourceIdToString,\n stringifyWithResourceId,\n} from '@milaboratories/pl-client';\nimport type { MiLogger } from '@milaboratories/ts-helpers';\nimport { asyncPool, CallersCounter } from '@milaboratories/ts-helpers';\nimport type { ClientLogs } from '../clients/logs';\nimport { randomUUID } from 'node:crypto';\nimport type { PlTreeEntry, ResourceInfo } from '@milaboratories/pl-tree';\nimport { treeEntryToResourceInfo } from '@milaboratories/pl-tree';\nimport { scheduler } from 'node:timers/promises';\nimport type { StreamingAPI_Response } from '../proto-grpc/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol';\nimport type * as sdk from '@milaboratories/pl-model-common';\nimport type { PollingOps } from './helpers/polling_ops';\nimport type { RpcError } from '@protobuf-ts/runtime-rpc';\nimport { getResourceInfoFromLogHandle, isLiveLogHandle, newLogHandle } from './helpers/logs_handle';\nimport { WrongResourceTypeError } from './helpers/helpers';\n\nexport type LogsStreamDriverOps = PollingOps & {\n /** Max number of concurrent requests to log streaming backend while calculating computable states */\n nConcurrentGetLogs: number;\n};\n\nexport class LogsStreamDriver implements sdk.LogsDriver {\n /** Holds a map of StreamManager Resource Id to all logs of this stream. */\n private readonly idToLastLines: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to the last log line of this stream. */\n private readonly idToProgressLog: Map<ResourceId, LogGetter> = new Map();\n\n /** Holds a map of StreamManager Resource Id to log id smart object. */\n private readonly hooks: PollingComputableHooks;\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly opts: LogsStreamDriverOps = {\n nConcurrentGetLogs: 10,\n pollingInterval: 1000,\n stopPollingDelay: 1000,\n },\n ) {\n this.hooks = new PollingComputableHooks(\n () => this.startUpdating(),\n () => this.stopUpdating(),\n { stopDebounce: opts.stopPollingDelay },\n (resolve, reject) => this.scheduleOnNextState(resolve, reject),\n );\n }\n\n getLastLogs(res: ResourceInfo | PlTreeEntry, lines: number): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx: ComputableCtx\n ): Computable<string | undefined>;\n getLastLogs(\n res: ResourceInfo | PlTreeEntry,\n lines: number,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined) return Computable.make((ctx) => this.getLastLogs(res, lines, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseLastLogs(r.id, callerId));\n\n const result = this.getLastLogsNoCtx(ctx.watcher, r, lines, callerId);\n ctx.markUnstable(\n 'The logs are from stream, so we consider them unstable. Final values will be got from blobs.',\n );\n\n return result;\n }\n\n private getLastLogsNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n lines: number,\n callerId: string,\n ): string | undefined {\n validateResourceType('getLastLogs', rInfo.type);\n\n let logGetter = this.idToLastLines.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, lines);\n this.idToLastLines.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error != undefined) throw result.error;\n\n return result.log;\n }\n\n /** Returns a last line that has patternToSearch.\n * Notifies when a new line appeared or EOF reached. */\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string\n ): Computable<string | undefined>;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx: ComputableCtx\n ): string | undefined;\n getProgressLog(\n res: ResourceInfo | PlTreeEntry,\n patternToSearch: string,\n ctx?: ComputableCtx,\n ): Computable<string | undefined> | string | undefined {\n if (ctx == undefined)\n return Computable.make((ctx) => this.getProgressLog(res, patternToSearch, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n const callerId = randomUUID();\n ctx.attacheHooks(this.hooks);\n ctx.addOnDestroy(() => this.releaseProgressLog(r.id, callerId));\n\n const result = this.getProgressLogNoCtx(ctx.watcher, r, patternToSearch, callerId);\n ctx.markUnstable(\n 'The progress log is from the stream, so we consider it unstable. Final value will be got from blobs.',\n );\n\n return result;\n }\n\n private getProgressLogNoCtx(\n w: Watcher,\n rInfo: ResourceInfo,\n patternToSearch: string,\n callerId: string,\n ): string | undefined {\n validateResourceType('getProgressLog', rInfo.type);\n\n let logGetter = this.idToProgressLog.get(rInfo.id);\n\n if (logGetter == undefined) {\n const newLogGetter = new LogGetter(this.logger, this.clientLogs, rInfo, 1, patternToSearch);\n this.idToProgressLog.set(rInfo.id, newLogGetter);\n\n logGetter = newLogGetter;\n }\n\n logGetter.attach(w, callerId);\n const result = logGetter.getLog();\n if (result.error) throw result.error;\n\n return result.log;\n }\n\n getLogHandle(res: ResourceInfo | PlTreeEntry): Computable<sdk.AnyLogHandle>;\n getLogHandle(res: ResourceInfo | PlTreeEntry, ctx: ComputableCtx): sdk.AnyLogHandle;\n getLogHandle(\n res: ResourceInfo | PlTreeEntry,\n ctx?: ComputableCtx,\n ): Computable<sdk.AnyLogHandle> | sdk.AnyLogHandle {\n if (ctx == undefined) return Computable.make((ctx) => this.getLogHandle(res, ctx));\n\n const r = treeEntryToResourceInfo(res, ctx);\n\n const result = this.getLogHandleNoCtx(r);\n\n // All logs from streams should be considered unstable,\n // final value will be got from blobs.\n ctx.markUnstable(`live_log:${resourceIdToString(r.id)}`);\n\n return result;\n }\n\n private getLogHandleNoCtx(rInfo: ResourceInfo): sdk.AnyLogHandle {\n validateResourceType('getLogHandle', rInfo.type);\n\n return newLogHandle(true, rInfo);\n }\n\n async lastLines(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.lastLines(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n async readText(\n handle: sdk.AnyLogHandle,\n lineCount: number,\n offsetBytes?: number,\n searchStr?: string | undefined,\n ) {\n return await this.tryWithNotFound(handle, () =>\n this.clientLogs.readText(\n getResourceInfoFromLogHandle(handle),\n lineCount,\n BigInt(offsetBytes ?? 0),\n searchStr,\n ),\n );\n }\n\n private async tryWithNotFound(\n handle: sdk.AnyLogHandle,\n method: () => Promise<StreamingAPI_Response>,\n ): Promise<sdk.StreamingApiResponse> {\n if (!isLiveLogHandle(handle))\n throw new Error(`Not live log handle was passed to live log driver, handle: ${handle}`);\n\n try {\n const resp = await method();\n return {\n live: true,\n shouldUpdateHandle: false,\n data: resp.data,\n size: Number(resp.size),\n newOffset: Number(resp.newOffset),\n };\n } catch (e: any) {\n if (e.name == 'RpcError' && e.code == 'NOT_FOUND') {\n return { shouldUpdateHandle: true };\n }\n\n throw e;\n }\n }\n\n private async releaseLastLogs(rId: ResourceId, callerId: string) {\n const deleted = this.idToLastLines.get(rId)?.release(callerId);\n if (deleted) this.idToLastLines.delete(rId);\n }\n\n private async releaseProgressLog(rId: ResourceId, callerId: string) {\n const deleted = this.idToProgressLog.get(rId)?.release(callerId);\n if (deleted) this.idToProgressLog.delete(rId);\n }\n\n async releaseAll() {}\n\n private scheduledOnNextState: ScheduledRefresh[] = [];\n\n private scheduleOnNextState(resolve: () => void, reject: (err: any) => void): void {\n this.scheduledOnNextState.push({ resolve, reject });\n }\n\n /** Called from observer */\n private startUpdating(): void {\n this.keepRunning = true;\n if (this.currentLoop === undefined) this.currentLoop = this.mainLoop();\n }\n\n /** Called from observer */\n private stopUpdating(): void {\n this.keepRunning = false;\n }\n\n /** If true, main loop will continue polling pl state. */\n private keepRunning = false;\n /** Actual state of main loop. */\n private currentLoop: Promise<void> | undefined = undefined;\n\n private async mainLoop() {\n while (this.keepRunning) {\n const toNotify = this.scheduledOnNextState;\n this.scheduledOnNextState = [];\n\n try {\n const logs = this.getAllLogs();\n await asyncPool(\n this.opts.nConcurrentGetLogs,\n logs.map((getter) => async () => await getter.update()),\n );\n\n toNotify.forEach((n) => n.resolve());\n } catch (e: any) {\n console.error(e);\n toNotify.forEach((n) => n.reject(e));\n }\n\n if (!this.keepRunning) break;\n await scheduler.wait(this.opts.pollingInterval);\n }\n\n this.currentLoop = undefined;\n }\n\n private getAllLogs(): Array<LogGetter> {\n return Array.from(this.idToLastLines.entries())\n .concat(Array.from(this.idToProgressLog.entries()))\n .map(([_, getter]) => getter);\n }\n}\n\n/** A job that gets last lines from a StreamWorkdir resource. */\nclass LogGetter {\n private logs: string | undefined;\n private error: any | undefined = undefined;\n\n private readonly change: ChangeSource = new ChangeSource();\n private readonly counter: CallersCounter = new CallersCounter();\n\n constructor(\n private readonly logger: MiLogger,\n private readonly clientLogs: ClientLogs,\n private readonly rInfo: ResourceInfo,\n private readonly lines: number,\n private readonly patternToSearch?: string,\n ) {}\n\n getLog(): {\n log: string | undefined;\n error?: any | undefined;\n } {\n return {\n log: this.logs,\n error: this.error,\n };\n }\n\n attach(w: Watcher, callerId: string) {\n this.change.attachWatcher(w);\n this.counter.inc(callerId);\n }\n\n release(callerId: string): boolean {\n return this.counter.dec(callerId);\n }\n\n async update() {\n try {\n const resp = await this.clientLogs.lastLines(\n this.rInfo,\n this.lines,\n 0n,\n this.patternToSearch,\n );\n\n const newLogs = new TextDecoder().decode(resp.data);\n if (this.logs != newLogs) this.change.markChanged(`logs for ${resourceIdToString(this.rInfo.id)} updated`);\n this.logs = newLogs;\n this.error = undefined;\n\n return;\n } catch (e: any) {\n e as RpcError;\n if (e.name == 'RpcError' && e.code == 'NOT_FOUND') {\n // No resource\n this.logs = '';\n this.error = e;\n this.change.markChanged();\n return;\n }\n\n this.logger.error(\n `Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${JSON.stringify(e)}`,\n );\n throw e;\n }\n }\n}\n\ntype ScheduledRefresh = {\n resolve: () => void;\n reject: (err: any) => void;\n};\n\nfunction validateResourceType(methodName: string, rType: ResourceType) {\n if (!rType.name.startsWith('StreamWorkdir')) {\n throw new WrongResourceTypeError(\n `${methodName}: wrong resource type: ${rType.name}, `\n + `expected: a resource of type 'StreamWorkdir'.`,\n );\n }\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-drivers",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.26",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=22"
|
|
6
6
|
},
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"upath": "^2.0.1",
|
|
34
34
|
"zod": "~3.23.8",
|
|
35
35
|
"@milaboratories/computable": "2.7.4",
|
|
36
|
-
"@milaboratories/pl-
|
|
36
|
+
"@milaboratories/pl-tree": "1.8.20",
|
|
37
|
+
"@milaboratories/pl-client": "2.16.13",
|
|
37
38
|
"@milaboratories/ts-helpers": "1.5.4",
|
|
38
|
-
"@milaboratories/pl-client": "2.16.11",
|
|
39
39
|
"@milaboratories/helpers": "1.12.0",
|
|
40
|
-
"@milaboratories/pl-
|
|
40
|
+
"@milaboratories/pl-model-common": "1.21.10"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/decompress": "^4.2.7",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"eslint": "^9.25.1",
|
|
49
49
|
"typescript": "~5.6.3",
|
|
50
50
|
"vitest": "^4.0.7",
|
|
51
|
-
"@milaboratories/build-configs": "1.0.8",
|
|
52
51
|
"@milaboratories/eslint-config": "1.0.5",
|
|
53
|
-
"@milaboratories/
|
|
52
|
+
"@milaboratories/build-configs": "1.0.9",
|
|
53
|
+
"@milaboratories/ts-builder": "1.0.6",
|
|
54
54
|
"@milaboratories/ts-configs": "1.0.6",
|
|
55
55
|
"@milaboratories/test-helpers": "1.1.1"
|
|
56
56
|
},
|
package/src/clients/ls_api.ts
CHANGED
|
@@ -64,8 +64,7 @@ export class ClientLs {
|
|
|
64
64
|
isDir: item.isDir,
|
|
65
65
|
fullName: item.fullName,
|
|
66
66
|
directory: item.directory,
|
|
67
|
-
|
|
68
|
-
lastModified: { seconds: BigInt(item.lastModified), nanos: 0 },
|
|
67
|
+
lastModified: parseTimestamp(item.lastModified),
|
|
69
68
|
version: item.version,
|
|
70
69
|
}));
|
|
71
70
|
|
|
@@ -76,3 +75,21 @@ export class ClientLs {
|
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
77
|
}
|
|
78
|
+
|
|
79
|
+
function parseTimestamp(timestamp: string): { seconds: bigint; nanos: number } {
|
|
80
|
+
// Parse ISO 8601 format: 2025-08-08T11:12:44.145635532Z
|
|
81
|
+
const date = new Date(timestamp);
|
|
82
|
+
const seconds = BigInt(Math.floor(date.getTime() / 1000));
|
|
83
|
+
|
|
84
|
+
// Extract fractional seconds from the original string
|
|
85
|
+
const fractionalMatch = timestamp.match(/\.(\d+)Z?$/);
|
|
86
|
+
let nanos = 0;
|
|
87
|
+
if (fractionalMatch) {
|
|
88
|
+
const fractionalPart = fractionalMatch[1];
|
|
89
|
+
// Pad or truncate to 9 digits (nanoseconds)
|
|
90
|
+
const padded = fractionalPart.padEnd(9, '0').slice(0, 9);
|
|
91
|
+
nanos = parseInt(padded, 10);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { seconds, nanos };
|
|
95
|
+
}
|
|
@@ -64,7 +64,7 @@ export class DownloadBlobTask {
|
|
|
64
64
|
this.logger.error(
|
|
65
65
|
`blob ${stringifyWithResourceId(this.rInfo)} download failed, `
|
|
66
66
|
+ `state: ${JSON.stringify(this.state)}, `
|
|
67
|
-
+ `error: ${e}`,
|
|
67
|
+
+ `error: ${JSON.stringify(e)}`,
|
|
68
68
|
);
|
|
69
69
|
if (nonRecoverableError(e)) {
|
|
70
70
|
this.setError(e);
|
|
@@ -375,7 +375,7 @@ class LogGetter {
|
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
this.logger.error(
|
|
378
|
-
`Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${e}`,
|
|
378
|
+
`Stream log lines for ${stringifyWithResourceId(this.rInfo.id)} failed, reason: ${JSON.stringify(e)}`,
|
|
379
379
|
);
|
|
380
380
|
throw e;
|
|
381
381
|
}
|