@milaboratories/pl-drivers 1.2.16

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.
Files changed (117) hide show
  1. package/README.md +18 -0
  2. package/dist/clients/download.d.ts +30 -0
  3. package/dist/clients/download.d.ts.map +1 -0
  4. package/dist/clients/helpers.d.ts +14 -0
  5. package/dist/clients/helpers.d.ts.map +1 -0
  6. package/dist/clients/logs.d.ts +26 -0
  7. package/dist/clients/logs.d.ts.map +1 -0
  8. package/dist/clients/ls_api.d.ts +13 -0
  9. package/dist/clients/ls_api.d.ts.map +1 -0
  10. package/dist/clients/progress.d.ts +25 -0
  11. package/dist/clients/progress.d.ts.map +1 -0
  12. package/dist/clients/upload.d.ts +38 -0
  13. package/dist/clients/upload.d.ts.map +1 -0
  14. package/dist/drivers/download_and_logs_blob.d.ts +106 -0
  15. package/dist/drivers/download_and_logs_blob.d.ts.map +1 -0
  16. package/dist/drivers/download_url.d.ts +70 -0
  17. package/dist/drivers/download_url.d.ts.map +1 -0
  18. package/dist/drivers/helpers/files_cache.d.ts +28 -0
  19. package/dist/drivers/helpers/files_cache.d.ts.map +1 -0
  20. package/dist/drivers/helpers/helpers.d.ts +34 -0
  21. package/dist/drivers/helpers/helpers.d.ts.map +1 -0
  22. package/dist/drivers/helpers/ls_list_entry.d.ts +49 -0
  23. package/dist/drivers/helpers/ls_list_entry.d.ts.map +1 -0
  24. package/dist/drivers/helpers/ls_storage_entry.d.ts +25 -0
  25. package/dist/drivers/helpers/ls_storage_entry.d.ts.map +1 -0
  26. package/dist/drivers/helpers/polling_ops.d.ts +8 -0
  27. package/dist/drivers/helpers/polling_ops.d.ts.map +1 -0
  28. package/dist/drivers/helpers/test_helpers.d.ts +2 -0
  29. package/dist/drivers/helpers/test_helpers.d.ts.map +1 -0
  30. package/dist/drivers/logs.d.ts +29 -0
  31. package/dist/drivers/logs.d.ts.map +1 -0
  32. package/dist/drivers/logs_stream.d.ts +50 -0
  33. package/dist/drivers/logs_stream.d.ts.map +1 -0
  34. package/dist/drivers/ls.d.ts +30 -0
  35. package/dist/drivers/ls.d.ts.map +1 -0
  36. package/dist/drivers/upload.d.ts +87 -0
  37. package/dist/drivers/upload.d.ts.map +1 -0
  38. package/dist/helpers/download.d.ts +15 -0
  39. package/dist/helpers/download.d.ts.map +1 -0
  40. package/dist/index.cjs +2 -0
  41. package/dist/index.cjs.map +1 -0
  42. package/dist/index.d.ts +15 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +4627 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.d.ts +36 -0
  47. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.d.ts.map +1 -0
  48. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts +103 -0
  49. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts.map +1 -0
  50. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.d.ts +42 -0
  51. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.d.ts.map +1 -0
  52. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.d.ts +165 -0
  53. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.d.ts.map +1 -0
  54. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.d.ts +44 -0
  55. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.d.ts.map +1 -0
  56. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts +171 -0
  57. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts.map +1 -0
  58. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.d.ts +122 -0
  59. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.d.ts.map +1 -0
  60. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.d.ts +315 -0
  61. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.d.ts.map +1 -0
  62. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.d.ts +98 -0
  63. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.d.ts.map +1 -0
  64. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.d.ts +337 -0
  65. package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.d.ts.map +1 -0
  66. package/dist/proto/google/api/http.d.ts +451 -0
  67. package/dist/proto/google/api/http.d.ts.map +1 -0
  68. package/dist/proto/google/protobuf/descriptor.d.ts +1646 -0
  69. package/dist/proto/google/protobuf/descriptor.d.ts.map +1 -0
  70. package/dist/proto/google/protobuf/duration.d.ts +106 -0
  71. package/dist/proto/google/protobuf/duration.d.ts.map +1 -0
  72. package/dist/proto/google/protobuf/timestamp.d.ts +151 -0
  73. package/dist/proto/google/protobuf/timestamp.d.ts.map +1 -0
  74. package/package.json +47 -0
  75. package/src/clients/download.test.ts +45 -0
  76. package/src/clients/download.ts +106 -0
  77. package/src/clients/helpers.ts +84 -0
  78. package/src/clients/logs.ts +68 -0
  79. package/src/clients/ls_api.ts +34 -0
  80. package/src/clients/progress.ts +86 -0
  81. package/src/clients/upload.test.ts +30 -0
  82. package/src/clients/upload.ts +199 -0
  83. package/src/drivers/download_and_logs_blob.ts +801 -0
  84. package/src/drivers/download_blob.test.ts +223 -0
  85. package/src/drivers/download_url.test.ts +90 -0
  86. package/src/drivers/download_url.ts +314 -0
  87. package/src/drivers/helpers/files_cache.test.ts +79 -0
  88. package/src/drivers/helpers/files_cache.ts +74 -0
  89. package/src/drivers/helpers/helpers.ts +136 -0
  90. package/src/drivers/helpers/ls_list_entry.test.ts +57 -0
  91. package/src/drivers/helpers/ls_list_entry.ts +152 -0
  92. package/src/drivers/helpers/ls_storage_entry.ts +135 -0
  93. package/src/drivers/helpers/polling_ops.ts +7 -0
  94. package/src/drivers/helpers/test_helpers.ts +5 -0
  95. package/src/drivers/logs.test.ts +337 -0
  96. package/src/drivers/logs.ts +214 -0
  97. package/src/drivers/logs_stream.ts +399 -0
  98. package/src/drivers/ls.test.ts +90 -0
  99. package/src/drivers/ls.ts +147 -0
  100. package/src/drivers/upload.test.ts +454 -0
  101. package/src/drivers/upload.ts +499 -0
  102. package/src/helpers/download.ts +43 -0
  103. package/src/index.ts +15 -0
  104. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.ts +60 -0
  105. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.ts +442 -0
  106. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.ts +63 -0
  107. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.ts +503 -0
  108. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.ts +84 -0
  109. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.ts +697 -0
  110. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.ts +212 -0
  111. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.ts +1036 -0
  112. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.ts +170 -0
  113. package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.ts +1201 -0
  114. package/src/proto/google/api/http.ts +838 -0
  115. package/src/proto/google/protobuf/descriptor.ts +5173 -0
  116. package/src/proto/google/protobuf/duration.ts +272 -0
  117. package/src/proto/google/protobuf/timestamp.ts +354 -0
@@ -0,0 +1,34 @@
1
+ import { MiLogger } from '@milaboratories/ts-helpers';
2
+ import type { LsAPI_List_Response } from '../proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol';
3
+ import { LSClient } from '../proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client';
4
+ import { GrpcTransport } from '@protobuf-ts/grpc-transport';
5
+ import type { RpcOptions } from '@protobuf-ts/runtime-rpc';
6
+ import { addRTypeToMetadata } from '@milaboratories/pl-client';
7
+ import { ResourceInfo } from '@milaboratories/pl-tree';
8
+
9
+ export class ClientLs {
10
+ private readonly grpcClient: LSClient;
11
+
12
+ constructor(
13
+ grpcTransport: GrpcTransport,
14
+ private readonly logger: MiLogger
15
+ ) {
16
+ this.grpcClient = new LSClient(grpcTransport);
17
+ }
18
+
19
+ close() {}
20
+
21
+ public async list(
22
+ rInfo: ResourceInfo,
23
+ path: string,
24
+ options?: RpcOptions
25
+ ): Promise<LsAPI_List_Response> {
26
+ return await this.grpcClient.list(
27
+ {
28
+ resourceId: rInfo.id,
29
+ location: path
30
+ },
31
+ addRTypeToMetadata(rInfo.type, options)
32
+ ).response;
33
+ }
34
+ }
@@ -0,0 +1,86 @@
1
+ import { ProgressClient } from '../proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client';
2
+ import { GrpcTransport } from '@protobuf-ts/grpc-transport';
3
+ import type { RpcOptions } from '@protobuf-ts/runtime-rpc';
4
+ import { Duration } from '../proto/google/protobuf/duration';
5
+ import { PlClient, addRTypeToMetadata } from '@milaboratories/pl-client';
6
+ import { MiLogger, notEmpty } from '@milaboratories/ts-helpers';
7
+ import { Dispatcher } from 'undici';
8
+ import { ResourceInfo } from '@milaboratories/pl-tree';
9
+
10
+ export type ProgressStatus = {
11
+ done: boolean;
12
+ progress: number;
13
+ bytesProcessed?: string;
14
+ bytesTotal?: string;
15
+ };
16
+
17
+ // ClientProgress holds a grpc connection to the platform
18
+ // but for Progress API service.
19
+ // When blobs are transfered, one can got a status of transfering
20
+ // using this API.
21
+ export class ClientProgress {
22
+ public readonly grpcClient: ProgressClient;
23
+
24
+ constructor(
25
+ public readonly grpcTransport: GrpcTransport,
26
+ _: Dispatcher,
27
+ public readonly client: PlClient,
28
+ public readonly logger: MiLogger
29
+ ) {
30
+ this.grpcClient = new ProgressClient(this.grpcTransport);
31
+ }
32
+
33
+ close() {}
34
+
35
+ /** getStatus gets a progress status by given rId and rType. */
36
+ async getStatus(
37
+ { id, type }: ResourceInfo,
38
+ options?: RpcOptions
39
+ ): Promise<ProgressStatus> {
40
+ const status = await this.grpcClient.getStatus(
41
+ { resourceId: id },
42
+ addRTypeToMetadata(type, options)
43
+ );
44
+
45
+ const report = notEmpty(status.response.report);
46
+
47
+ return {
48
+ done: report.done,
49
+ progress: report.progress,
50
+ bytesProcessed: String(report.bytesProcessed),
51
+ bytesTotal: String(report.bytesTotal)
52
+ };
53
+ }
54
+
55
+ // realtimeStatus returns a async generator that takes statuses from
56
+ // GRPC stream every updateIntervalMs milliseconds.
57
+ async *realtimeStatus(
58
+ { id, type }: ResourceInfo,
59
+ updateIntervalMs: number = 100,
60
+ options?: RpcOptions
61
+ ) {
62
+ options = addRTypeToMetadata(type, options);
63
+
64
+ const secs = Math.floor(updateIntervalMs / 1000);
65
+ const nanos = (updateIntervalMs - secs * 1000) * 1000000;
66
+ const updateInterval = Duration.create({
67
+ seconds: BigInt(secs),
68
+ nanos: nanos
69
+ });
70
+
71
+ try {
72
+ const { responses } = this.grpcClient.realtimeStatus(
73
+ {
74
+ resourceId: id,
75
+ updateInterval: updateInterval
76
+ },
77
+ options
78
+ );
79
+
80
+ yield* responses;
81
+ } catch (e) {
82
+ this.logger.warn('Failed to get realtime status' + e);
83
+ throw e;
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,30 @@
1
+ import { PlClient, ResourceId, TestHelpers } from '@milaboratories/pl-client';
2
+ import { ClientUpload } from '../clients/upload';
3
+ import { Dispatcher } from 'undici';
4
+ import { GrpcTransport } from '@protobuf-ts/grpc-transport';
5
+ import { ConsoleLoggerAdapter } from '@milaboratories/ts-helpers';
6
+
7
+ test('integration test, grpc upload blob should throw error on NOT_FOUND', async () => {
8
+ await TestHelpers.withTempRoot(async (client) => {
9
+ const logger = new ConsoleLoggerAdapter();
10
+ const clientBlob = client.getDriver({
11
+ name: 'UploadBlob',
12
+ init: (
13
+ pl: PlClient,
14
+ grpcTransport: GrpcTransport,
15
+ httpDispatcher: Dispatcher
16
+ ) => new ClientUpload(grpcTransport, httpDispatcher, client, logger)
17
+ });
18
+
19
+ try {
20
+ await clientBlob.initUpload({
21
+ id: 1n as ResourceId,
22
+ type: { name: 'BlobUpload/primary', version: '1' }
23
+ });
24
+ fail('should throw NOT_FOUND');
25
+ } catch (e) {
26
+ const err = e as any;
27
+ expect(err.code).toBe('NOT_FOUND');
28
+ }
29
+ });
30
+ });
@@ -0,0 +1,199 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import { GrpcTransport } from '@protobuf-ts/grpc-transport';
3
+ import type { RpcOptions } from '@protobuf-ts/runtime-rpc';
4
+ import { PlClient, addRTypeToMetadata } from '@milaboratories/pl-client';
5
+ import { UploadClient } from '../proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client';
6
+ import { MiLogger } from '@milaboratories/ts-helpers';
7
+ import { Dispatcher, request } from 'undici';
8
+ import { uploadapi_GetPartURL_Response } from '../proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol';
9
+ import { ResourceInfo } from '@milaboratories/pl-tree';
10
+
11
+ export class MTimeError extends Error {}
12
+
13
+ export class UnexpectedEOF extends Error {}
14
+
15
+ export class NetworkError extends Error {}
16
+
17
+ export class NoFileForUploading extends Error {}
18
+
19
+ /** Low-level client for grpc uploadapi.
20
+ * The user should pass here a concrete BlobUpload/<storageId> resource,
21
+ * it can be got from handle field of BlobUpload. */
22
+ export class ClientUpload {
23
+ private readonly grpcClient: UploadClient;
24
+
25
+ constructor(
26
+ public readonly grpcTransport: GrpcTransport,
27
+ public readonly httpClient: Dispatcher,
28
+ _: PlClient,
29
+ public readonly logger: MiLogger
30
+ ) {
31
+ this.grpcClient = new UploadClient(this.grpcTransport);
32
+ }
33
+
34
+ close() {}
35
+
36
+ public async initUpload(
37
+ { id, type }: ResourceInfo,
38
+ options?: RpcOptions
39
+ ): Promise<bigint[]> {
40
+ const init = await this.grpcClient.init(
41
+ { resourceId: id },
42
+ addRTypeToMetadata(type, options)
43
+ );
44
+ return this.partsToUpload(init.response);
45
+ }
46
+
47
+ public async partUpload(
48
+ { id, type }: ResourceInfo,
49
+ path: string,
50
+ partNumber: bigint,
51
+ partsOverall: number,
52
+ expectedMTimeUnix: bigint,
53
+ options?: RpcOptions
54
+ ) {
55
+ const info = await this.grpcClient.getPartURL(
56
+ {
57
+ resourceId: id,
58
+ partNumber: partNumber,
59
+ uploadedPartSize: 0n // we update progress as a separate call later.
60
+ },
61
+ addRTypeToMetadata(type, options)
62
+ ).response;
63
+
64
+ const { chunk, mTime } = await this.readChunk(
65
+ path,
66
+ info.chunkStart,
67
+ info.chunkEnd
68
+ );
69
+ if (mTime > expectedMTimeUnix) {
70
+ throw new MTimeError(
71
+ 'file was modified, expected mtime: ' +
72
+ expectedMTimeUnix +
73
+ ', got: ' +
74
+ mTime +
75
+ '.'
76
+ );
77
+ }
78
+
79
+ const resp = await request(
80
+ info.uploadUrl,
81
+ this.prepareUploadOpts(info, chunk)
82
+ );
83
+
84
+ const body = await (await resp.body.blob()).text();
85
+ this.logger.info(
86
+ `uploaded chunk ${partNumber} from ${partsOverall} of resource: ${id},` +
87
+ ` response: '${body.toString()}', ` +
88
+ `status code: ${resp.statusCode}`
89
+ );
90
+
91
+ if (resp.statusCode != 200) {
92
+ throw new NetworkError(
93
+ `response is not ok, status code: ${resp.statusCode},` +
94
+ ` body: ${body}, headers: ${resp.headers}, url: ${info.uploadUrl}`
95
+ );
96
+ }
97
+
98
+ await this.grpcClient.updateProgress(
99
+ {
100
+ resourceId: id,
101
+ bytesProcessed: info.chunkEnd - info.chunkStart
102
+ },
103
+ addRTypeToMetadata(type, options)
104
+ );
105
+ }
106
+
107
+ public async finalizeUpload(
108
+ { id, type }: ResourceInfo,
109
+ options?: RpcOptions
110
+ ) {
111
+ return await this.grpcClient.finalize(
112
+ { resourceId: id },
113
+ addRTypeToMetadata(type, options)
114
+ );
115
+ }
116
+
117
+ private async readChunk(
118
+ path: string,
119
+ chunkStart: bigint,
120
+ chunkEnd: bigint
121
+ ): Promise<{ chunk: Buffer; mTime: bigint }> {
122
+ let f: fs.FileHandle | undefined;
123
+ try {
124
+ f = await fs.open(path);
125
+ const len = Number(chunkEnd - chunkStart);
126
+ const pos = Number(chunkStart);
127
+ const b = Buffer.alloc(len);
128
+ const bytesRead = await this.readBytesFromPosition(f, b, len, pos);
129
+
130
+ const stat = await fs.stat(path);
131
+
132
+ return {
133
+ chunk: b.subarray(0, bytesRead),
134
+ mTime: BigInt(Math.floor(stat.mtimeMs / 1000))
135
+ };
136
+ } catch (e: any) {
137
+ if (e.code == 'ENOENT')
138
+ throw new NoFileForUploading(`there is no file ${path} for uploading`);
139
+ throw e;
140
+ } finally {
141
+ f?.close();
142
+ }
143
+ }
144
+
145
+ /** Read len bytes from a given position. The reason the method exists
146
+ is that FileHandle.read can read less bytes than it's needed. */
147
+ async readBytesFromPosition(
148
+ f: fs.FileHandle,
149
+ b: Buffer,
150
+ len: number,
151
+ position: number
152
+ ) {
153
+ let bytesReadTotal = 0;
154
+ while (bytesReadTotal < len) {
155
+ const { bytesRead } = await f.read(
156
+ b,
157
+ bytesReadTotal,
158
+ len - bytesReadTotal,
159
+ position + bytesReadTotal
160
+ );
161
+ if (bytesRead === 0) {
162
+ throw new UnexpectedEOF('file ended earlier than expected.');
163
+ }
164
+ bytesReadTotal += bytesRead;
165
+ }
166
+
167
+ return bytesReadTotal;
168
+ }
169
+
170
+ /** Calculates parts that need to be uploaded from the parts that were
171
+ * already uploaded. */
172
+ private partsToUpload(info: {
173
+ partsCount: bigint;
174
+ uploadedParts: bigint[];
175
+ }): bigint[] {
176
+ const toUpload: bigint[] = [];
177
+ const uploaded = new Set(info.uploadedParts);
178
+
179
+ for (let i = 1n; i <= info.partsCount; i++) {
180
+ if (!uploaded.has(i)) toUpload.push(i);
181
+ }
182
+
183
+ return toUpload;
184
+ }
185
+
186
+ private prepareUploadOpts(
187
+ info: uploadapi_GetPartURL_Response,
188
+ chunk: Buffer
189
+ ): any {
190
+ const headers = info.headers.map(({ name, value }) => [name, value]);
191
+
192
+ return {
193
+ dispatcher: this.httpClient,
194
+ body: chunk,
195
+ headers: Object.fromEntries(headers),
196
+ method: info.method.toUpperCase() as Dispatcher.HttpMethod
197
+ };
198
+ }
199
+ }