@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,454 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FieldId,
|
|
3
|
+
isNotNullResourceId,
|
|
4
|
+
PlTransaction,
|
|
5
|
+
PollTxAccessor,
|
|
6
|
+
ResourceId,
|
|
7
|
+
TestHelpers
|
|
8
|
+
} from '@milaboratories/pl-client';
|
|
9
|
+
import {
|
|
10
|
+
ConsoleLoggerAdapter,
|
|
11
|
+
HmacSha256Signer,
|
|
12
|
+
Signer
|
|
13
|
+
} from '@milaboratories/ts-helpers';
|
|
14
|
+
import * as fs from 'node:fs';
|
|
15
|
+
import * as fsp from 'node:fs/promises';
|
|
16
|
+
import * as os from 'node:os';
|
|
17
|
+
import * as path from 'node:path';
|
|
18
|
+
import { PlClient } from '@milaboratories/pl-client';
|
|
19
|
+
import { poll } from '@milaboratories/pl-client';
|
|
20
|
+
import { UploadOpts, UploadDriver, UploadResourceSnapshot } from './upload';
|
|
21
|
+
import {
|
|
22
|
+
createUploadBlobClient,
|
|
23
|
+
createUploadProgressClient
|
|
24
|
+
} from '../clients/helpers';
|
|
25
|
+
import { Writable, Readable } from 'node:stream';
|
|
26
|
+
|
|
27
|
+
test('upload a blob', async () => {
|
|
28
|
+
await withTest(async ({ client, uploader, signer }: TestArg) => {
|
|
29
|
+
const stats = await writeFile('42', signer);
|
|
30
|
+
const uploadId = await createBlobUpload(client, stats);
|
|
31
|
+
const handleRes = await getHandleField(client, uploadId);
|
|
32
|
+
|
|
33
|
+
const c = uploader.getProgressId(handleRes);
|
|
34
|
+
|
|
35
|
+
while (true) {
|
|
36
|
+
const p = await c.getValue();
|
|
37
|
+
|
|
38
|
+
expect(p.isUpload).toBeTruthy();
|
|
39
|
+
expect(p.isUploadSignMatch).toBeTruthy();
|
|
40
|
+
if (p.done) {
|
|
41
|
+
expect(p.lastError).toBeUndefined();
|
|
42
|
+
expect(p.status?.bytesProcessed).toBe(2);
|
|
43
|
+
expect(p.status?.bytesTotal).toBe(2);
|
|
44
|
+
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
await c.awaitChange();
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('upload a big blob', async () => {
|
|
54
|
+
const lotsOfNumbers: number[] = [];
|
|
55
|
+
for (let i = 0; i < 5000000; i++) {
|
|
56
|
+
lotsOfNumbers.push(i);
|
|
57
|
+
}
|
|
58
|
+
const hugeString = lotsOfNumbers.join(' ');
|
|
59
|
+
|
|
60
|
+
await withTest(async ({ client, uploader, signer }: TestArg) => {
|
|
61
|
+
const stats = await writeFile(hugeString, signer);
|
|
62
|
+
const uploadId = await createBlobUpload(client, stats);
|
|
63
|
+
const handleRes = await getHandleField(client, uploadId);
|
|
64
|
+
|
|
65
|
+
const c = uploader.getProgressId(handleRes);
|
|
66
|
+
|
|
67
|
+
while (true) {
|
|
68
|
+
const p = await c.getValue();
|
|
69
|
+
console.log('got progress of big blob: ', p);
|
|
70
|
+
|
|
71
|
+
expect(p.isUpload).toBeTruthy();
|
|
72
|
+
if (p.done) {
|
|
73
|
+
expect(p.isUploadSignMatch).toBeTruthy();
|
|
74
|
+
expect(p.lastError).toBeUndefined();
|
|
75
|
+
expect(p.status?.bytesProcessed).toStrictEqual(p.status?.bytesTotal);
|
|
76
|
+
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await c.awaitChange();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// unskip if you need to test uploads of big files
|
|
86
|
+
test.skip('upload a very big blob', async () => {
|
|
87
|
+
await withTest(async ({ client, uploader, signer }: TestArg) => {
|
|
88
|
+
// const size = 4 * (1 << 30); // 4 GB
|
|
89
|
+
// const anAnswer = Buffer.from(new TextEncoder().encode(`
|
|
90
|
+
// "Good morning," said Deep Thought at last.
|
|
91
|
+
// "do you have... er, that is..."
|
|
92
|
+
// "An answer for you?" interrupted Deep Thought majestically. "Yes. I have."
|
|
93
|
+
// ...
|
|
94
|
+
// "Forty-two," said Deep Thought, with infinite majesty and calm.
|
|
95
|
+
// ...
|
|
96
|
+
// "We're going to get lynched aren't we?" he whispered.
|
|
97
|
+
// `));
|
|
98
|
+
// const tmpDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test'));
|
|
99
|
+
// const fPath = path.join(tmpDir, 'verybig.txt');
|
|
100
|
+
// const fileToWrite = await fsp.open(fPath, 'w')
|
|
101
|
+
|
|
102
|
+
// for (let i = 0; i <= (size / anAnswer.length); i++) {
|
|
103
|
+
// await fileToWrite.write(anAnswer)
|
|
104
|
+
// if (i % 100 == 0)
|
|
105
|
+
// console.log(`wrote ${i/(size / anAnswer.length)}`);
|
|
106
|
+
// }
|
|
107
|
+
// await fileToWrite.close();
|
|
108
|
+
|
|
109
|
+
// const stats = await getFileStats(signer, fPath)
|
|
110
|
+
const stats = await getFileStats(
|
|
111
|
+
signer,
|
|
112
|
+
'/home/snyssfx/Downloads/Kung Fu Hustle (2004) Open Matte 1080p.mkv'
|
|
113
|
+
);
|
|
114
|
+
const uploadId = await createBlobUpload(client, stats);
|
|
115
|
+
const handleRes = await getHandleField(client, uploadId);
|
|
116
|
+
|
|
117
|
+
const c = uploader.getProgressId(handleRes);
|
|
118
|
+
|
|
119
|
+
while (true) {
|
|
120
|
+
const p = await c.getValue();
|
|
121
|
+
console.log('got progress of a very big blob: ', p);
|
|
122
|
+
|
|
123
|
+
expect(p.isUpload).toBeTruthy();
|
|
124
|
+
if (p.done) {
|
|
125
|
+
expect(p.isUploadSignMatch).toBeTruthy();
|
|
126
|
+
expect(p.status?.bytesProcessed).toStrictEqual(p.status?.bytesTotal);
|
|
127
|
+
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
await c.awaitChange();
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}, 1000000000);
|
|
135
|
+
|
|
136
|
+
test('upload a blob with wrong modification time', async () => {
|
|
137
|
+
await withTest(async ({ client, uploader, signer }: TestArg) => {
|
|
138
|
+
const stats = await writeFile('42', signer);
|
|
139
|
+
stats.mtime -= 1000n;
|
|
140
|
+
const uploadId = await createBlobUpload(client, stats);
|
|
141
|
+
const handleRes = await getHandleField(client, uploadId);
|
|
142
|
+
|
|
143
|
+
const c = uploader.getProgressId(handleRes);
|
|
144
|
+
|
|
145
|
+
while (true) {
|
|
146
|
+
try {
|
|
147
|
+
await c.getValue();
|
|
148
|
+
} catch (e: any) {
|
|
149
|
+
if (String(e).includes('file was modified')) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
throw e;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
await c.awaitChange();
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('upload a duplicate blob', async () => {
|
|
161
|
+
await withTest(async ({ client, uploader, signer }: TestArg) => {
|
|
162
|
+
const stats = await writeFile('42', signer);
|
|
163
|
+
const uploadId = await createBlobUpload(client, stats);
|
|
164
|
+
const handleRes = await getHandleField(client, uploadId);
|
|
165
|
+
|
|
166
|
+
const cOrig = uploader.getProgressId(handleRes);
|
|
167
|
+
const cDupl = uploader.getProgressId(handleRes);
|
|
168
|
+
|
|
169
|
+
while (true) {
|
|
170
|
+
const pOrig = await cOrig.getValue();
|
|
171
|
+
const pDupl = await cDupl.getValue();
|
|
172
|
+
|
|
173
|
+
expect(pDupl).toStrictEqual(pOrig);
|
|
174
|
+
expect(pDupl.isUpload).toBeTruthy();
|
|
175
|
+
if (pDupl.done) {
|
|
176
|
+
expect(pDupl.isUploadSignMatch).toBeTruthy();
|
|
177
|
+
expect(pDupl.lastError).toBeUndefined();
|
|
178
|
+
expect(pDupl.status?.bytesProcessed).toBe(2);
|
|
179
|
+
expect(pDupl.status?.bytesTotal).toBe(2);
|
|
180
|
+
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
await cDupl.awaitChange();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('upload lots of duplicate blobs concurrently', async () => {
|
|
190
|
+
await TestHelpers.withTempRoot(async (client) => {
|
|
191
|
+
const signer = new HmacSha256Signer(HmacSha256Signer.generateSecret());
|
|
192
|
+
const logger = new ConsoleLoggerAdapter();
|
|
193
|
+
const uploader = new UploadDriver(
|
|
194
|
+
logger,
|
|
195
|
+
signer,
|
|
196
|
+
createUploadBlobClient(client, logger),
|
|
197
|
+
createUploadProgressClient(client, logger)
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const tmpDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test'));
|
|
201
|
+
const n = 100;
|
|
202
|
+
|
|
203
|
+
const settings: FileStat[] = [];
|
|
204
|
+
for (let i = 0; i < n; i++) {
|
|
205
|
+
const stat = await writeFile(
|
|
206
|
+
'DuplicateBlobsFileContent',
|
|
207
|
+
signer,
|
|
208
|
+
tmpDir,
|
|
209
|
+
`testUploadABlob_${i}.txt`
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
settings.push(stat);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const { uploadIds } = await createMapOfUploads(client, n, settings);
|
|
216
|
+
|
|
217
|
+
const handles = await Promise.all(
|
|
218
|
+
uploadIds.map((id) => getHandleField(client, id))
|
|
219
|
+
);
|
|
220
|
+
const computables = handles.map((handle) => uploader.getProgressId(handle));
|
|
221
|
+
|
|
222
|
+
for (const c of computables) {
|
|
223
|
+
while (true) {
|
|
224
|
+
const p = await c.getValue();
|
|
225
|
+
|
|
226
|
+
if (p.done) {
|
|
227
|
+
expect(p.isUploadSignMatch).toBeTruthy();
|
|
228
|
+
expect(p.lastError).toBeUndefined();
|
|
229
|
+
expect(p.status?.bytesProcessed).toBe(25);
|
|
230
|
+
expect(p.status?.bytesTotal).toBe(25);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
await c.awaitChange();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
await uploader.releaseAll();
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test('index a blob', async () => {
|
|
243
|
+
await withTest(async ({ client, uploader }: TestArg) => {
|
|
244
|
+
const uploadId = await createBlobIndex(
|
|
245
|
+
client,
|
|
246
|
+
'another_answer_to_the_ultimate_question.txt',
|
|
247
|
+
'library'
|
|
248
|
+
);
|
|
249
|
+
const handleRes = await getHandleField(client, uploadId);
|
|
250
|
+
|
|
251
|
+
const c = uploader.getProgressId(handleRes);
|
|
252
|
+
|
|
253
|
+
while (true) {
|
|
254
|
+
const p = await c.getValue();
|
|
255
|
+
console.log('got index progress: ', p);
|
|
256
|
+
|
|
257
|
+
expect(p.isUpload).toBeFalsy();
|
|
258
|
+
expect(p.isUploadSignMatch).toBeUndefined();
|
|
259
|
+
if (p.done) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
await c.awaitChange();
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
interface TestArg {
|
|
269
|
+
client: PlClient;
|
|
270
|
+
uploader: UploadDriver;
|
|
271
|
+
signer: Signer;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function withTest(cb: (arg: TestArg) => Promise<void>) {
|
|
275
|
+
await TestHelpers.withTempRoot(async (client) => {
|
|
276
|
+
const signer = new HmacSha256Signer(HmacSha256Signer.generateSecret());
|
|
277
|
+
const logger = new ConsoleLoggerAdapter();
|
|
278
|
+
const uploader = new UploadDriver(
|
|
279
|
+
logger,
|
|
280
|
+
signer,
|
|
281
|
+
createUploadBlobClient(client, logger),
|
|
282
|
+
createUploadProgressClient(client, logger)
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
await cb({ client, uploader, signer });
|
|
286
|
+
|
|
287
|
+
await uploader.releaseAll();
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
interface FileStat {
|
|
292
|
+
fPath: string;
|
|
293
|
+
mtime: bigint;
|
|
294
|
+
fileSignature: string;
|
|
295
|
+
size: number;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
async function writeFile(
|
|
299
|
+
fileContent: string,
|
|
300
|
+
signer: Signer,
|
|
301
|
+
tmpDir?: string,
|
|
302
|
+
fileName: string = 'testUploadABlob.txt'
|
|
303
|
+
): Promise<FileStat> {
|
|
304
|
+
if (tmpDir == undefined)
|
|
305
|
+
tmpDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test'));
|
|
306
|
+
|
|
307
|
+
const fPath = path.join(tmpDir, fileName);
|
|
308
|
+
|
|
309
|
+
const data = Buffer.from(new TextEncoder().encode(fileContent));
|
|
310
|
+
await fsp.writeFile(fPath, data);
|
|
311
|
+
|
|
312
|
+
return await getFileStats(signer, fPath);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async function getFileStats(signer: Signer, fPath: string): Promise<FileStat> {
|
|
316
|
+
const fileSignature = signer.sign(fPath);
|
|
317
|
+
const stats = await fsp.stat(fPath);
|
|
318
|
+
const mtime = BigInt(Math.floor(stats.mtime.getTime() / 1000));
|
|
319
|
+
|
|
320
|
+
return { fPath, mtime, fileSignature, size: stats.size };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async function createMapOfUploads(
|
|
324
|
+
c: PlClient,
|
|
325
|
+
n: number,
|
|
326
|
+
settings: FileStat[]
|
|
327
|
+
) {
|
|
328
|
+
return await c.withWriteTx(
|
|
329
|
+
'UploaderCreateMapOfUploads',
|
|
330
|
+
async (tx: PlTransaction) => {
|
|
331
|
+
const uploads: ResourceId[] = [];
|
|
332
|
+
|
|
333
|
+
const mapId = tx.createStruct({ name: 'StdMap', version: '1' });
|
|
334
|
+
for (let i = 0; i < n; i++) {
|
|
335
|
+
const uploadId = await createBlobUploadTx(tx, settings[i]);
|
|
336
|
+
uploads.push(uploadId);
|
|
337
|
+
const fId = { resourceId: mapId, fieldName: String(i) };
|
|
338
|
+
tx.createField(fId, 'Input');
|
|
339
|
+
tx.setField(fId, uploadId);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
tx.createField(
|
|
343
|
+
{ resourceId: c.clientRoot, fieldName: 'project1' },
|
|
344
|
+
'Dynamic',
|
|
345
|
+
mapId
|
|
346
|
+
);
|
|
347
|
+
await tx.commit();
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
mapId: await mapId.globalId,
|
|
351
|
+
uploadIds: uploads
|
|
352
|
+
};
|
|
353
|
+
},
|
|
354
|
+
{}
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
async function createBlobUpload(
|
|
359
|
+
c: PlClient,
|
|
360
|
+
stat: FileStat
|
|
361
|
+
): Promise<ResourceId> {
|
|
362
|
+
return await c.withWriteTx(
|
|
363
|
+
'UploadDriverCreateTest',
|
|
364
|
+
async (tx: PlTransaction) => {
|
|
365
|
+
const uploadId = await createBlobUploadTx(tx, stat);
|
|
366
|
+
|
|
367
|
+
tx.createField(
|
|
368
|
+
{ resourceId: c.clientRoot, fieldName: 'project1' },
|
|
369
|
+
'Dynamic',
|
|
370
|
+
uploadId
|
|
371
|
+
);
|
|
372
|
+
await tx.commit();
|
|
373
|
+
|
|
374
|
+
return uploadId;
|
|
375
|
+
},
|
|
376
|
+
{}
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function createBlobUploadTx(
|
|
381
|
+
tx: PlTransaction,
|
|
382
|
+
stat: FileStat
|
|
383
|
+
): Promise<ResourceId> {
|
|
384
|
+
const settings = {
|
|
385
|
+
modificationTime: stat.mtime.toString(),
|
|
386
|
+
localPath: stat.fPath,
|
|
387
|
+
pathSignature: stat.fileSignature,
|
|
388
|
+
sizeBytes: stat.size.toString()
|
|
389
|
+
};
|
|
390
|
+
const data = new TextEncoder().encode(JSON.stringify(settings));
|
|
391
|
+
const upload = tx.createStruct({ name: 'BlobUpload', version: '1' }, data);
|
|
392
|
+
|
|
393
|
+
return await upload.globalId;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async function createBlobIndex(
|
|
397
|
+
c: PlClient,
|
|
398
|
+
path: string,
|
|
399
|
+
storageId: string
|
|
400
|
+
): Promise<ResourceId> {
|
|
401
|
+
return await c.withWriteTx(
|
|
402
|
+
'UploadDriverCreateTest',
|
|
403
|
+
async (tx: PlTransaction) => {
|
|
404
|
+
const settings = {
|
|
405
|
+
storageId: storageId,
|
|
406
|
+
path: path
|
|
407
|
+
};
|
|
408
|
+
const data = new TextEncoder().encode(JSON.stringify(settings));
|
|
409
|
+
const importInternal = tx.createStruct(
|
|
410
|
+
{ name: 'BlobImportInternal', version: '1' },
|
|
411
|
+
data
|
|
412
|
+
);
|
|
413
|
+
tx.createField(
|
|
414
|
+
{ resourceId: c.clientRoot, fieldName: 'project1' },
|
|
415
|
+
'Dynamic',
|
|
416
|
+
importInternal
|
|
417
|
+
);
|
|
418
|
+
await tx.commit();
|
|
419
|
+
|
|
420
|
+
return await importInternal.globalId;
|
|
421
|
+
},
|
|
422
|
+
{}
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async function getHandleField(
|
|
427
|
+
client: PlClient,
|
|
428
|
+
uploadId: ResourceId
|
|
429
|
+
): Promise<UploadResourceSnapshot> {
|
|
430
|
+
return await poll(client, async (tx: PollTxAccessor) => {
|
|
431
|
+
const upload = await tx.get(uploadId);
|
|
432
|
+
const handle = await upload.get('handle');
|
|
433
|
+
|
|
434
|
+
const blob = handle.data.fields.find((f) => f.name == 'blob')?.value;
|
|
435
|
+
const incarnation = handle.data.fields.find(
|
|
436
|
+
(f) => f.name == 'incarnation'
|
|
437
|
+
)?.value;
|
|
438
|
+
|
|
439
|
+
const fields = {
|
|
440
|
+
blob: undefined as ResourceId | undefined,
|
|
441
|
+
incarnation: undefined as ResourceId | undefined
|
|
442
|
+
};
|
|
443
|
+
if (blob != undefined && isNotNullResourceId(blob)) fields.blob = blob;
|
|
444
|
+
if (incarnation != undefined && isNotNullResourceId(incarnation))
|
|
445
|
+
fields.incarnation = incarnation;
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
...handle.data,
|
|
449
|
+
data: JSON.parse(handle.data.data!.toString()) as UploadOpts,
|
|
450
|
+
fields,
|
|
451
|
+
kv: undefined
|
|
452
|
+
};
|
|
453
|
+
});
|
|
454
|
+
}
|