@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.
- package/README.md +18 -0
- package/dist/clients/download.d.ts +30 -0
- package/dist/clients/download.d.ts.map +1 -0
- package/dist/clients/helpers.d.ts +14 -0
- package/dist/clients/helpers.d.ts.map +1 -0
- package/dist/clients/logs.d.ts +26 -0
- package/dist/clients/logs.d.ts.map +1 -0
- package/dist/clients/ls_api.d.ts +13 -0
- package/dist/clients/ls_api.d.ts.map +1 -0
- package/dist/clients/progress.d.ts +25 -0
- package/dist/clients/progress.d.ts.map +1 -0
- package/dist/clients/upload.d.ts +38 -0
- package/dist/clients/upload.d.ts.map +1 -0
- package/dist/drivers/download_and_logs_blob.d.ts +106 -0
- package/dist/drivers/download_and_logs_blob.d.ts.map +1 -0
- package/dist/drivers/download_url.d.ts +70 -0
- package/dist/drivers/download_url.d.ts.map +1 -0
- package/dist/drivers/helpers/files_cache.d.ts +28 -0
- package/dist/drivers/helpers/files_cache.d.ts.map +1 -0
- package/dist/drivers/helpers/helpers.d.ts +34 -0
- package/dist/drivers/helpers/helpers.d.ts.map +1 -0
- package/dist/drivers/helpers/ls_list_entry.d.ts +49 -0
- package/dist/drivers/helpers/ls_list_entry.d.ts.map +1 -0
- package/dist/drivers/helpers/ls_storage_entry.d.ts +25 -0
- package/dist/drivers/helpers/ls_storage_entry.d.ts.map +1 -0
- package/dist/drivers/helpers/polling_ops.d.ts +8 -0
- package/dist/drivers/helpers/polling_ops.d.ts.map +1 -0
- package/dist/drivers/helpers/test_helpers.d.ts +2 -0
- package/dist/drivers/helpers/test_helpers.d.ts.map +1 -0
- package/dist/drivers/logs.d.ts +29 -0
- package/dist/drivers/logs.d.ts.map +1 -0
- package/dist/drivers/logs_stream.d.ts +50 -0
- package/dist/drivers/logs_stream.d.ts.map +1 -0
- package/dist/drivers/ls.d.ts +30 -0
- package/dist/drivers/ls.d.ts.map +1 -0
- package/dist/drivers/upload.d.ts +87 -0
- package/dist/drivers/upload.d.ts.map +1 -0
- package/dist/helpers/download.d.ts +15 -0
- package/dist/helpers/download.d.ts.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4627 -0
- package/dist/index.js.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.d.ts +36 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.d.ts.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts +103 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.d.ts.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.d.ts +42 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.d.ts.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.d.ts +165 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.d.ts.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.d.ts +44 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.d.ts.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts +171 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.d.ts.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.d.ts +122 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.d.ts.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.d.ts +315 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.d.ts.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.d.ts +98 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.d.ts.map +1 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.d.ts +337 -0
- package/dist/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.d.ts.map +1 -0
- package/dist/proto/google/api/http.d.ts +451 -0
- package/dist/proto/google/api/http.d.ts.map +1 -0
- package/dist/proto/google/protobuf/descriptor.d.ts +1646 -0
- package/dist/proto/google/protobuf/descriptor.d.ts.map +1 -0
- package/dist/proto/google/protobuf/duration.d.ts +106 -0
- package/dist/proto/google/protobuf/duration.d.ts.map +1 -0
- package/dist/proto/google/protobuf/timestamp.d.ts +151 -0
- package/dist/proto/google/protobuf/timestamp.d.ts.map +1 -0
- package/package.json +47 -0
- package/src/clients/download.test.ts +45 -0
- package/src/clients/download.ts +106 -0
- package/src/clients/helpers.ts +84 -0
- package/src/clients/logs.ts +68 -0
- package/src/clients/ls_api.ts +34 -0
- package/src/clients/progress.ts +86 -0
- package/src/clients/upload.test.ts +30 -0
- package/src/clients/upload.ts +199 -0
- package/src/drivers/download_and_logs_blob.ts +801 -0
- package/src/drivers/download_blob.test.ts +223 -0
- package/src/drivers/download_url.test.ts +90 -0
- package/src/drivers/download_url.ts +314 -0
- package/src/drivers/helpers/files_cache.test.ts +79 -0
- package/src/drivers/helpers/files_cache.ts +74 -0
- package/src/drivers/helpers/helpers.ts +136 -0
- package/src/drivers/helpers/ls_list_entry.test.ts +57 -0
- package/src/drivers/helpers/ls_list_entry.ts +152 -0
- package/src/drivers/helpers/ls_storage_entry.ts +135 -0
- package/src/drivers/helpers/polling_ops.ts +7 -0
- package/src/drivers/helpers/test_helpers.ts +5 -0
- package/src/drivers/logs.test.ts +337 -0
- package/src/drivers/logs.ts +214 -0
- package/src/drivers/logs_stream.ts +399 -0
- package/src/drivers/ls.test.ts +90 -0
- package/src/drivers/ls.ts +147 -0
- package/src/drivers/upload.test.ts +454 -0
- package/src/drivers/upload.ts +499 -0
- package/src/helpers/download.ts +43 -0
- package/src/index.ts +15 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.client.ts +60 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol.ts +442 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.client.ts +63 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/lsapi/protocol.ts +503 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.client.ts +84 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/progressapi/protocol.ts +697 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.client.ts +212 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/streamingapi/protocol.ts +1036 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.client.ts +170 -0
- package/src/proto/github.com/milaboratory/pl/controllers/shared/grpc/uploadapi/protocol.ts +1201 -0
- package/src/proto/google/api/http.ts +838 -0
- package/src/proto/google/protobuf/descriptor.ts +5173 -0
- package/src/proto/google/protobuf/duration.ts +272 -0
- 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
|
+
}
|