@pi-r/gcp 0.6.5 → 0.7.0
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 +3 -6
- package/client/index.js +130 -68
- package/download/index.js +39 -33
- package/package.json +6 -6
- package/types/index.d.ts +36 -0
- package/upload/index.js +175 -33
package/README.md
CHANGED
package/client/index.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
exports.getProjectId = exports.createBucketRequest = exports.setPredefinedAcl = exports.setPublicRead = exports.executeBatchQuery = exports.executeQuery = exports.deleteObjectsV2 = exports.deleteObjects = exports.setBucketWebsite = exports.setBucketPolicy = exports.createBucketV2 = exports.createBucket = exports.createDatabaseClient = exports.createStorageClient = exports.validateDatabase = exports.validateStorage = exports.isFirebaseApp = void 0;
|
|
2
|
+
exports.CLOUD_DOWNLOAD_CHUNK = exports.CLOUD_UPLOAD_CHUNK = exports.CLOUD_UPLOAD_STREAM = exports.getProjectId = exports.createBucketRequest = exports.setPredefinedAcl = exports.setPublicRead = exports.executeBatchQuery = exports.executeQuery = exports.deleteObjectsV2 = exports.deleteObjects = exports.setBucketWebsite = exports.setBucketTagging = exports.setBucketPolicy = exports.createBucketV2 = exports.createBucket = exports.createDatabaseClient = exports.createStorageClient = exports.validateDatabase = exports.validateStorage = exports.isFirebaseApp = void 0;
|
|
4
3
|
const path = require("path");
|
|
5
4
|
const storage = require("@google-cloud/storage");
|
|
6
5
|
const firestore_1 = require("@google-cloud/firestore");
|
|
7
6
|
const util_1 = require("@e-mc/cloud/util");
|
|
8
7
|
const types_1 = require("@e-mc/types");
|
|
9
|
-
const Module = require("@e-mc/module");
|
|
10
8
|
const Cloud = require("@e-mc/cloud");
|
|
11
9
|
const FIREBASE_DB = {};
|
|
12
10
|
const FIREBASE_STORAGE = {};
|
|
13
11
|
const ADMIN_DB = {};
|
|
14
12
|
const ADMIN_STORAGE = {};
|
|
15
13
|
function getApp(credential, isDB) {
|
|
16
|
-
var _a, _b;
|
|
17
14
|
const { projectId, databaseURL, storageBucket, apiKey, authDomain } = credential;
|
|
18
15
|
if (apiKey && authDomain) {
|
|
19
16
|
const { getApps, initializeApp } = require('@firebase/app');
|
|
@@ -27,7 +24,7 @@ function getApp(credential, isDB) {
|
|
|
27
24
|
}
|
|
28
25
|
if (!app) {
|
|
29
26
|
const firebaseKey = (projectId || '') + '_' + apiKey + '_' + authDomain + (isDB ? '_' + databaseURL : '');
|
|
30
|
-
app = isDB ? FIREBASE_DB[firebaseKey]
|
|
27
|
+
app = isDB ? FIREBASE_DB[firebaseKey] ||= initializeApp({ ...credential, databaseURL }, firebaseKey) : FIREBASE_STORAGE[firebaseKey] ||= initializeApp({ ...credential, storageBucket }, firebaseKey);
|
|
31
28
|
}
|
|
32
29
|
if (isDB) {
|
|
33
30
|
const { getDatabase, goOnline } = require('@firebase/database');
|
|
@@ -48,7 +45,7 @@ function getApp(credential, isDB) {
|
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
47
|
if (!app) {
|
|
51
|
-
app = isDB ? ADMIN_DB[
|
|
48
|
+
app = isDB ? ADMIN_DB[databaseURL || "[DEFAULT]"] ||= initializeApp({ credential: applicationDefault(), databaseURL }, databaseURL) : ADMIN_STORAGE[storageBucket || "[DEFAULT]"] ||= initializeApp({ credential: applicationDefault(), storageBucket }, storageBucket);
|
|
52
49
|
}
|
|
53
50
|
credential.admin = true;
|
|
54
51
|
if (isDB) {
|
|
@@ -60,7 +57,7 @@ function getApp(credential, isDB) {
|
|
|
60
57
|
}
|
|
61
58
|
}
|
|
62
59
|
async function hasBucket(client) {
|
|
63
|
-
const [exists] = await client.exists().catch(err => isErrorConflict(err) ? [true] : [false]);
|
|
60
|
+
const [exists] = await client.exists().catch((err) => isErrorConflict(err) ? [true] : [false]);
|
|
64
61
|
return exists;
|
|
65
62
|
}
|
|
66
63
|
async function updatePredefinedAcl(acl, values, metadata = {}) {
|
|
@@ -84,7 +81,7 @@ async function updatePredefinedAcl(acl, values, metadata = {}) {
|
|
|
84
81
|
}
|
|
85
82
|
if ((0, types_1.isString)(value.role)) {
|
|
86
83
|
if (projectNumber !== undefined) {
|
|
87
|
-
value.userProject
|
|
84
|
+
value.userProject ||= projectNumber.toString();
|
|
88
85
|
}
|
|
89
86
|
return target.add(value);
|
|
90
87
|
}
|
|
@@ -100,24 +97,24 @@ async function updatePredefinedAcl(acl, values, metadata = {}) {
|
|
|
100
97
|
}
|
|
101
98
|
return errors;
|
|
102
99
|
})
|
|
103
|
-
.catch(err => [err]);
|
|
100
|
+
.catch((err) => [err]);
|
|
104
101
|
}
|
|
105
102
|
async function setUniformBucketLevel(bucket, enabled) {
|
|
106
103
|
return bucket.setMetadata({ iamConfiguration: { uniformBucketLevelAccess: { enabled } } });
|
|
107
104
|
}
|
|
108
105
|
const getFirebasePackageName = (credential) => credential.apiKey && credential.authDomain ? 'firebase' : 'firebase-admin';
|
|
109
|
-
const hasKeyFile = (credential) => (0, types_1.isString)(credential.keyFilename || credential.keyFile || process.env.GOOGLE_APPLICATION_CREDENTIALS) || (0, types_1.isObject)(credential.credentials);
|
|
110
106
|
const isErrorConflict = (err) => (err instanceof Error) && err.code === 409;
|
|
107
|
+
const hasGoogleAuth = (credential) => (0, types_1.isString)(credential.keyFilename || credential.keyFile || process.env.GOOGLE_APPLICATION_CREDENTIALS) || (0, types_1.isObject)(credential.credentials) || !!credential.authClient;
|
|
111
108
|
function isFirebaseApp(credential, store, admin) {
|
|
112
|
-
return !!(credential.apiKey && credential.authDomain && (store || credential.databaseURL) || credential.product ===
|
|
109
|
+
return !!(credential.apiKey && credential.authDomain && (store || credential.databaseURL) || credential.product === "firebase" && process.env.GOOGLE_APPLICATION_CREDENTIALS) && (!admin || !credential.admin);
|
|
113
110
|
}
|
|
114
111
|
exports.isFirebaseApp = isFirebaseApp;
|
|
115
112
|
function validateStorage(credential) {
|
|
116
|
-
return
|
|
113
|
+
return hasGoogleAuth(credential) || isFirebaseApp(credential, true);
|
|
117
114
|
}
|
|
118
115
|
exports.validateStorage = validateStorage;
|
|
119
116
|
function validateDatabase(credential, data) {
|
|
120
|
-
return (
|
|
117
|
+
return hasGoogleAuth(credential) && !!(data.product || data.database || data.table || data.query || data.id || data.keys || data.kind || data.options?.query) || isFirebaseApp(credential);
|
|
121
118
|
}
|
|
122
119
|
exports.validateDatabase = validateDatabase;
|
|
123
120
|
function createStorageClient(credential, bucket) {
|
|
@@ -142,29 +139,26 @@ exports.createStorageClient = createStorageClient;
|
|
|
142
139
|
function createDatabaseClient(credential, data) {
|
|
143
140
|
let packageName = '';
|
|
144
141
|
try {
|
|
145
|
-
|
|
146
|
-
if (data) {
|
|
147
|
-
({ product, name, table, query, database } = data);
|
|
148
|
-
}
|
|
149
|
-
if (product === 'firebase' || isFirebaseApp(credential)) {
|
|
142
|
+
if (data?.product === "firebase" || isFirebaseApp(credential)) {
|
|
150
143
|
packageName = getFirebasePackageName(credential);
|
|
151
144
|
return getApp(credential, true);
|
|
152
145
|
}
|
|
153
146
|
getProjectId(credential, true);
|
|
154
147
|
if (data) {
|
|
155
|
-
|
|
148
|
+
const { product, name, table, query, database } = data;
|
|
149
|
+
if (product === "spanner" || !product && name && database && (query || table)) {
|
|
156
150
|
const { Spanner } = require(packageName = '@google-cloud/spanner');
|
|
157
151
|
return new Spanner(credential);
|
|
158
152
|
}
|
|
159
|
-
if (product ===
|
|
153
|
+
if (product === "bigquery" || !product && (!name && table && database || (0, types_1.isString)(query))) {
|
|
160
154
|
const { BigQuery } = require(packageName = '@google-cloud/bigquery');
|
|
161
155
|
return new BigQuery(credential);
|
|
162
156
|
}
|
|
163
|
-
if (product ===
|
|
157
|
+
if (product === "bigtable" || !product && name && table && !database) {
|
|
164
158
|
const { Bigtable } = require(packageName = '@google-cloud/bigtable');
|
|
165
159
|
return new Bigtable(credential);
|
|
166
160
|
}
|
|
167
|
-
if (product ===
|
|
161
|
+
if (product === "datastore" || !product && (data.keys || data.kind || query && !table && !data.id)) {
|
|
168
162
|
const { Datastore } = require(packageName = '@google-cloud/datastore');
|
|
169
163
|
return new Datastore(credential);
|
|
170
164
|
}
|
|
@@ -223,32 +217,32 @@ async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
|
|
|
223
217
|
if (!Array.isArray(options.acl)) {
|
|
224
218
|
options.acl = undefined;
|
|
225
219
|
switch (acl) {
|
|
226
|
-
case
|
|
227
|
-
case
|
|
228
|
-
await client.makePrivate(options).catch(err => !isErrorConflict(err) && errors.push(err));
|
|
229
|
-
await setPredefinedAcl.call(this, client.acl, acl, client, '', options.bucket?.metadata).catch(err => errors.push(err));
|
|
220
|
+
case "private":
|
|
221
|
+
case "projectPrivate":
|
|
222
|
+
await client.makePrivate(options).catch((err) => !isErrorConflict(err) && errors.push(err));
|
|
223
|
+
await setPredefinedAcl.call(this, client.acl, acl, client, '', options.bucket?.metadata).catch((err) => errors.push(err));
|
|
230
224
|
break;
|
|
231
|
-
case
|
|
232
|
-
await client.makePublic(options).catch(err => !isErrorConflict(err) && errors.push(err));
|
|
225
|
+
case "authenticatedRead":
|
|
226
|
+
await client.makePublic(options).catch((err) => !isErrorConflict(err) && errors.push(err));
|
|
233
227
|
options = { ...options };
|
|
234
228
|
options.acl = [{ entity: 'allUsers' }, { entity: 'allAuthenticatedUsers', role: 'READER' }];
|
|
235
229
|
break;
|
|
236
|
-
case
|
|
237
|
-
await client.makePublic(options).catch(err => !isErrorConflict(err) && errors.push(err));
|
|
230
|
+
case "publicReadWrite":
|
|
231
|
+
await client.makePublic(options).catch((err) => !isErrorConflict(err) && errors.push(err));
|
|
238
232
|
options = { ...options };
|
|
239
233
|
options.acl = [{ entity: 'allUsers', role: 'WRITER' }];
|
|
240
234
|
break;
|
|
241
|
-
case
|
|
242
|
-
await client.makePublic(options).catch(err => !isErrorConflict(err) && errors.push(err));
|
|
235
|
+
case "publicRead":
|
|
236
|
+
await client.makePublic(options).catch((err) => !isErrorConflict(err) && errors.push(err));
|
|
243
237
|
break;
|
|
244
238
|
case 'bucketAccessUniform':
|
|
245
|
-
await setUniformBucketLevel(client, true).catch(err => errors.push(err));
|
|
239
|
+
await setUniformBucketLevel(client, true).catch((err) => errors.push(err));
|
|
246
240
|
break;
|
|
247
241
|
case 'bucketAccessACL':
|
|
248
|
-
await setUniformBucketLevel(client, false).catch(err => errors.push(err));
|
|
242
|
+
await setUniformBucketLevel(client, false).catch((err) => errors.push(err));
|
|
249
243
|
break;
|
|
250
244
|
default:
|
|
251
|
-
errors.push((0, types_1.errorValue)('Invalid ACL',
|
|
245
|
+
errors.push((0, types_1.errorValue)('Invalid ACL', Cloud.asString(acl) || 'empty'));
|
|
252
246
|
break;
|
|
253
247
|
}
|
|
254
248
|
}
|
|
@@ -263,6 +257,33 @@ async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
|
|
|
263
257
|
return true;
|
|
264
258
|
}
|
|
265
259
|
exports.setBucketPolicy = setBucketPolicy;
|
|
260
|
+
async function setBucketTagging(credential, bucket, labels, service = 'gcp') {
|
|
261
|
+
if (isFirebaseApp(credential, true, true) || !(0, types_1.isPlainObject)(labels)) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
const client = createStorageClient.call(this, credential, bucket).bucket(bucket);
|
|
265
|
+
const deleting = Object.keys(labels).length === 0;
|
|
266
|
+
if (deleting) {
|
|
267
|
+
const [metadata] = await client.getMetadata();
|
|
268
|
+
if (!(0, types_1.isPlainObject)(metadata.labels)) {
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
labels = {};
|
|
272
|
+
for (const key in metadata.labels) {
|
|
273
|
+
labels[key] = null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return client.setMetadata({ labels })
|
|
277
|
+
.then(([metadata]) => {
|
|
278
|
+
this.formatMessage(64, service, [deleting ? "Tags deleted" : "Tags created", bucket], ((0, types_1.isPlainObject)(metadata.labels) ? Object.keys(metadata.labels).length : 0) + ' labels (current)', { ...Cloud.LOG_CLOUD_COMMAND });
|
|
279
|
+
return true;
|
|
280
|
+
})
|
|
281
|
+
.catch((err) => {
|
|
282
|
+
this.formatFail(64, service, ["Unable to update bucket tagging", bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
283
|
+
return false;
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
exports.setBucketTagging = setBucketTagging;
|
|
266
287
|
async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
|
|
267
288
|
if (isFirebaseApp(credential, true, true)) {
|
|
268
289
|
return false;
|
|
@@ -277,11 +298,11 @@ async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
|
|
|
277
298
|
}
|
|
278
299
|
return createStorageClient.call(this, credential, bucket).bucket(bucket).setMetadata({ website })
|
|
279
300
|
.then(() => {
|
|
280
|
-
this.formatMessage(64, service, ["Bucket configured", bucket], website, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
301
|
+
this.formatMessage(64, service, ["Bucket website configured", bucket], website, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
281
302
|
return true;
|
|
282
303
|
})
|
|
283
|
-
.catch(err => {
|
|
284
|
-
this.formatFail(64, service, ["Unable to
|
|
304
|
+
.catch((err) => {
|
|
305
|
+
this.formatFail(64, service, ["Unable to set bucket website", bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
|
|
285
306
|
return false;
|
|
286
307
|
});
|
|
287
308
|
}
|
|
@@ -305,7 +326,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
|
|
|
305
326
|
}
|
|
306
327
|
if (recursive && prefixes.length) {
|
|
307
328
|
for (const { name } of prefixes) {
|
|
308
|
-
await recurse(
|
|
329
|
+
await recurse(Cloud.joinPath(prefix, name));
|
|
309
330
|
}
|
|
310
331
|
}
|
|
311
332
|
}
|
|
@@ -328,7 +349,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
|
|
|
328
349
|
const result = await client.getFiles();
|
|
329
350
|
for (const { name } of result[0]) {
|
|
330
351
|
if (!name.includes('/')) {
|
|
331
|
-
tasks.push(client.file(name).delete({ ignoreNotFound: true }).catch(err => this.formatFail(64, service, ["Delete failed", name], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false })));
|
|
352
|
+
tasks.push(client.file(name).delete({ ignoreNotFound: true }).catch((err) => this.formatFail(64, service, ["Delete failed", name], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false })));
|
|
332
353
|
}
|
|
333
354
|
}
|
|
334
355
|
}
|
|
@@ -355,7 +376,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
|
|
|
355
376
|
this.formatMessage(64, service, ["Bucket emptied" + ` (${recursive ? 'recursive' : files})`, bucket], recursive ? files : '', { ...Cloud.LOG_CLOUD_COMMAND });
|
|
356
377
|
}
|
|
357
378
|
})
|
|
358
|
-
.catch(err => {
|
|
379
|
+
.catch((err) => {
|
|
359
380
|
errors.push(err);
|
|
360
381
|
});
|
|
361
382
|
}
|
|
@@ -369,7 +390,7 @@ exports.executeQuery = executeQuery;
|
|
|
369
390
|
async function executeBatchQuery(credential, batch, sessionKey) {
|
|
370
391
|
const length = batch.length;
|
|
371
392
|
const result = new Array(length);
|
|
372
|
-
const clients =
|
|
393
|
+
const clients = {};
|
|
373
394
|
const caching = length > 0 && this.hasCache(batch[0].service, sessionKey);
|
|
374
395
|
const cacheValue = { value: this.valueOfKey(credential, 'cache'), sessionKey };
|
|
375
396
|
const authItems = [];
|
|
@@ -384,7 +405,14 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
384
405
|
};
|
|
385
406
|
const closeClient = () => {
|
|
386
407
|
const fs = clients[3];
|
|
387
|
-
fs
|
|
408
|
+
if (fs) {
|
|
409
|
+
fs.terminate();
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const sp = clients[5];
|
|
413
|
+
if (sp) {
|
|
414
|
+
sp.close();
|
|
415
|
+
}
|
|
388
416
|
};
|
|
389
417
|
const getFamily = (data, row, family) => {
|
|
390
418
|
const familyData = data[family];
|
|
@@ -417,14 +445,14 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
417
445
|
};
|
|
418
446
|
cacheValue.exclusiveOf = Array.isArray(ignoreCache) ? ignoreCache : undefined;
|
|
419
447
|
let rows, queryString = '';
|
|
420
|
-
if (product ===
|
|
448
|
+
if (product === "firebase" || isFirebaseApp(credential)) {
|
|
421
449
|
if (!(0, types_1.isString)(query)) {
|
|
422
450
|
closeClient();
|
|
423
451
|
throw (0, util_1.formatError)(item, "Missing database query");
|
|
424
452
|
}
|
|
425
453
|
const orderBy = item.orderBy;
|
|
426
454
|
if (useCache) {
|
|
427
|
-
queryString = query +
|
|
455
|
+
queryString = query + Cloud.asString(orderBy, true);
|
|
428
456
|
if (!update && (rows = getCache(queryString))) {
|
|
429
457
|
result[i] = rows;
|
|
430
458
|
continue;
|
|
@@ -473,7 +501,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
473
501
|
rows = [group && (0, types_1.isObject)(val) && (0, types_1.isObject)(val[group[0]]) ? val[group[0]] : val];
|
|
474
502
|
}
|
|
475
503
|
}
|
|
476
|
-
else if (product ===
|
|
504
|
+
else if (product === "spanner" || !product && name && database && (query || table)) {
|
|
477
505
|
const columns = (0, types_1.isPlainObject)(query) && query.columns || item.columns;
|
|
478
506
|
if (!(query || table && columns)) {
|
|
479
507
|
closeClient();
|
|
@@ -485,7 +513,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
485
513
|
}
|
|
486
514
|
const { updateType, options = {} } = item;
|
|
487
515
|
if (useCache) {
|
|
488
|
-
queryString = name + '_' + database + '_' + (table ? table + (columns ?
|
|
516
|
+
queryString = name + '_' + database + '_' + (table ? table + (columns ? Cloud.asString(columns, true) : '') : '') + Cloud.asString(query, true) + (limit > 0 ? limit : '');
|
|
489
517
|
if (!update && (rows = getCache(queryString))) {
|
|
490
518
|
result[i] = rows;
|
|
491
519
|
continue;
|
|
@@ -516,8 +544,12 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
516
544
|
}
|
|
517
545
|
else {
|
|
518
546
|
transaction.runUpdate(update)
|
|
519
|
-
.then(async () =>
|
|
520
|
-
.
|
|
547
|
+
.then(async () => {
|
|
548
|
+
transaction.commit()
|
|
549
|
+
.then(() => resolve())
|
|
550
|
+
.catch(reject);
|
|
551
|
+
})
|
|
552
|
+
.catch(reject);
|
|
521
553
|
}
|
|
522
554
|
});
|
|
523
555
|
});
|
|
@@ -525,12 +557,12 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
525
557
|
const request = (0, types_1.isPlainObject)(query) ? query : { sql: query };
|
|
526
558
|
request.json = true;
|
|
527
559
|
if (limit > 0) {
|
|
528
|
-
(request.gaxOptions
|
|
560
|
+
(request.gaxOptions ||= {}).maxResults = limit;
|
|
529
561
|
}
|
|
530
562
|
[rows] = await db.run(request);
|
|
531
563
|
}
|
|
532
564
|
}
|
|
533
|
-
else if (product ===
|
|
565
|
+
else if (product === "bigtable" || !product && name && table && !database) {
|
|
534
566
|
if (!name || !table) {
|
|
535
567
|
closeClient();
|
|
536
568
|
throw (0, util_1.formatError)(item, !name ? "Missing database name" : "Missing database table");
|
|
@@ -540,10 +572,10 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
540
572
|
options.filter = query;
|
|
541
573
|
}
|
|
542
574
|
if (!id && limit > 0) {
|
|
543
|
-
(options.gaxOptions
|
|
575
|
+
(options.gaxOptions ||= {}).maxResults = limit;
|
|
544
576
|
}
|
|
545
577
|
if (useCache) {
|
|
546
|
-
queryString = name + '_' + table + '_' + ((0, types_1.isString)(id) ? id + ((0, types_1.isArray)(columns) ? '_' +
|
|
578
|
+
queryString = name + '_' + table + '_' + ((0, types_1.isString)(id) ? id + ((0, types_1.isArray)(columns) ? '_' + Cloud.asString(columns, true) : '') : '') + Cloud.asString(options, true);
|
|
547
579
|
if (!(update && id) && (rows = getCache(queryString))) {
|
|
548
580
|
result[i] = rows;
|
|
549
581
|
continue;
|
|
@@ -574,7 +606,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
574
606
|
});
|
|
575
607
|
}
|
|
576
608
|
}
|
|
577
|
-
else if (product ===
|
|
609
|
+
else if (product === "bigquery" || !product && (!name && database && table || (0, types_1.isString)(query) || (0, types_1.isString)(item.options?.query))) {
|
|
578
610
|
const { params, options = {} } = item;
|
|
579
611
|
if ((0, types_1.isString)(query)) {
|
|
580
612
|
options.query = query;
|
|
@@ -586,7 +618,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
586
618
|
options.maxResults = limit;
|
|
587
619
|
}
|
|
588
620
|
if (useCache) {
|
|
589
|
-
queryString = query + (database ? '_' + database + (table ? '_' + table : '') : '') +
|
|
621
|
+
queryString = query + (database ? '_' + database + (table ? '_' + table : '') : '') + Cloud.asString(options, true);
|
|
590
622
|
if (!update && (rows = getCache(queryString))) {
|
|
591
623
|
result[i] = rows;
|
|
592
624
|
continue;
|
|
@@ -613,7 +645,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
613
645
|
}
|
|
614
646
|
[rows] = await job.getQueryResults();
|
|
615
647
|
}
|
|
616
|
-
else if (product ===
|
|
648
|
+
else if (product === "datastore" || !product && (item.keys || item.kind || query && !table && !id)) {
|
|
617
649
|
const { keys, kind } = item;
|
|
618
650
|
if (!keys && !kind && !Array.isArray(query)) {
|
|
619
651
|
closeClient();
|
|
@@ -669,19 +701,19 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
669
701
|
db.runQuery(task.select('__key__'), item.options).then(entities => {
|
|
670
702
|
if ((0, types_1.isArray)(entities)) {
|
|
671
703
|
const items = entities.map((entity) => db.key(entity[db.KEY]));
|
|
672
|
-
db.save({ key: items, data: update }).then(() => resolve()).catch(err => reject(err));
|
|
704
|
+
db.save({ key: items, data: update }).then(() => resolve()).catch((err) => reject(err));
|
|
673
705
|
}
|
|
674
706
|
else {
|
|
675
707
|
resolve();
|
|
676
708
|
}
|
|
677
709
|
})
|
|
678
|
-
.catch(err => reject(err));
|
|
710
|
+
.catch((err) => reject(err));
|
|
679
711
|
});
|
|
680
712
|
}
|
|
681
713
|
[rows] = await db.runQuery(task, item.options);
|
|
682
714
|
}
|
|
683
715
|
}
|
|
684
|
-
else if (product ===
|
|
716
|
+
else if (product === "firestore" || !product && table) {
|
|
685
717
|
if (!table) {
|
|
686
718
|
closeClient();
|
|
687
719
|
throw (0, util_1.formatError)(item, "Missing database table");
|
|
@@ -705,7 +737,34 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
705
737
|
else {
|
|
706
738
|
const doc = db.collection(table).doc(id);
|
|
707
739
|
if ((0, types_1.isPlainObject)(update)) {
|
|
708
|
-
|
|
740
|
+
const pattern = /^__(delete|serverTimestamp|increment)(?:<(.+)>)?__$/;
|
|
741
|
+
for (const attr in update) {
|
|
742
|
+
const match = pattern.exec(attr);
|
|
743
|
+
if (match) {
|
|
744
|
+
const method = match[1];
|
|
745
|
+
switch (method) {
|
|
746
|
+
case 'delete':
|
|
747
|
+
case 'serverTimestamp':
|
|
748
|
+
update[attr] = firestore_1.FieldValue[method]();
|
|
749
|
+
break;
|
|
750
|
+
case 'increment':
|
|
751
|
+
update[attr] = firestore_1.FieldValue.increment(match[2] ? +match[2] : 1);
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
switch (item.updateType) {
|
|
757
|
+
case 1:
|
|
758
|
+
await doc.create(update);
|
|
759
|
+
break;
|
|
760
|
+
case 2:
|
|
761
|
+
case 3:
|
|
762
|
+
await doc.set(update, { merge: item.updateType === 3 });
|
|
763
|
+
break;
|
|
764
|
+
default:
|
|
765
|
+
await doc.update(update);
|
|
766
|
+
break;
|
|
767
|
+
}
|
|
709
768
|
}
|
|
710
769
|
const data = (await doc.get()).data();
|
|
711
770
|
if (data) {
|
|
@@ -715,7 +774,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
715
774
|
}
|
|
716
775
|
else if (Array.isArray(query)) {
|
|
717
776
|
const orderBy = item.orderBy;
|
|
718
|
-
if (useCache && (rows = getCache(queryString = table + '_' +
|
|
777
|
+
if (useCache && (rows = getCache(queryString = table + '_' + Cloud.asString(query, true) + Cloud.asString(orderBy, true) + (limit > 0 ? limit : '')))) {
|
|
719
778
|
result[i] = rows;
|
|
720
779
|
continue;
|
|
721
780
|
}
|
|
@@ -727,7 +786,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
727
786
|
switch (method) {
|
|
728
787
|
case 'whereAnd':
|
|
729
788
|
case 'whereOr':
|
|
730
|
-
if (params.every(p =>
|
|
789
|
+
if (params.every(p => (0, types_1.isArray)(p))) {
|
|
731
790
|
db = db.where(firestore_1.Filter[method === 'whereAnd' ? 'and' : 'or'](...params.map((p) => firestore_1.Filter.where(p[0], p[1], p[2]))));
|
|
732
791
|
}
|
|
733
792
|
else {
|
|
@@ -784,7 +843,7 @@ function setPublicRead(acl, pathname, requested, service = 'gcp') {
|
|
|
784
843
|
this.formatMessage(64, service, "Grant public-read", pathname, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
785
844
|
}
|
|
786
845
|
})
|
|
787
|
-
.catch(err => {
|
|
846
|
+
.catch((err) => {
|
|
788
847
|
if (requested) {
|
|
789
848
|
this.formatMessage(64, service, ["Unable to grant public-read", pathname], err, { ...Cloud.LOG_CLOUD_WARN });
|
|
790
849
|
}
|
|
@@ -816,7 +875,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
|
|
|
816
875
|
items = [{ entity: 'allUsers' }, { entity: 'allAuthenticatedUsers' }];
|
|
817
876
|
}
|
|
818
877
|
switch (value) {
|
|
819
|
-
case
|
|
878
|
+
case "private": {
|
|
820
879
|
const owners = new Set(acl.filter(item => item.role === 'OWNER' && item.entity).map(item => item.entity));
|
|
821
880
|
if (owner) {
|
|
822
881
|
owners.add(owner);
|
|
@@ -831,7 +890,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
|
|
|
831
890
|
}
|
|
832
891
|
break;
|
|
833
892
|
}
|
|
834
|
-
case
|
|
893
|
+
case "projectPrivate":
|
|
835
894
|
for (const user of acl) {
|
|
836
895
|
const entity = user.entity;
|
|
837
896
|
if (entity) {
|
|
@@ -840,7 +899,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
|
|
|
840
899
|
}
|
|
841
900
|
}
|
|
842
901
|
break;
|
|
843
|
-
case
|
|
902
|
+
case "bucketOwnerRead":
|
|
844
903
|
if (bucket && owner) {
|
|
845
904
|
for (const user of acl) {
|
|
846
905
|
const entity = user.entity;
|
|
@@ -849,7 +908,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
|
|
|
849
908
|
}
|
|
850
909
|
}
|
|
851
910
|
}
|
|
852
|
-
case
|
|
911
|
+
case "bucketOwnerFullControl":
|
|
853
912
|
if (bucket && owner) {
|
|
854
913
|
items.push({ entity: owner, role: 'OWNER' });
|
|
855
914
|
}
|
|
@@ -916,13 +975,16 @@ function getProjectId(credential, cache) {
|
|
|
916
975
|
const id = require(pathname).project_id;
|
|
917
976
|
if ((0, types_1.isString)(id)) {
|
|
918
977
|
projectId = id;
|
|
919
|
-
credential.projectId = projectId;
|
|
920
978
|
}
|
|
921
979
|
}
|
|
922
980
|
catch {
|
|
923
981
|
}
|
|
982
|
+
credential.projectId = projectId || (projectId = process.env.GCLOUD_PROJECT);
|
|
924
983
|
}
|
|
925
984
|
}
|
|
926
985
|
return projectId;
|
|
927
986
|
}
|
|
928
987
|
exports.getProjectId = getProjectId;
|
|
988
|
+
exports.CLOUD_UPLOAD_STREAM = true;
|
|
989
|
+
exports.CLOUD_UPLOAD_CHUNK = true;
|
|
990
|
+
exports.CLOUD_DOWNLOAD_CHUNK = true;
|
package/download/index.js
CHANGED
|
@@ -3,20 +3,18 @@ const path = require("path");
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const https = require("https");
|
|
5
5
|
const types_1 = require("@e-mc/types");
|
|
6
|
-
const Module = require("@e-mc/module");
|
|
7
6
|
const Cloud = require("@e-mc/cloud");
|
|
8
7
|
const client_1 = require("@pi-r/gcp");
|
|
9
|
-
function download(credential, service = 'gcp') {
|
|
8
|
+
module.exports = function download(credential, service = 'gcp') {
|
|
10
9
|
const storage = client_1.createStorageClient.call(this, credential);
|
|
11
10
|
return (data, callback) => {
|
|
12
11
|
const { bucket: Bucket, download: target } = data;
|
|
13
|
-
const Key = target.filename;
|
|
14
|
-
const firebase = (0, client_1.isFirebaseApp)(credential, true, true);
|
|
12
|
+
const Key = target.keyname || target.filename;
|
|
15
13
|
let tempDir;
|
|
16
|
-
const downloadResponse = (err, url) => {
|
|
14
|
+
const downloadResponse = (err, url = null) => {
|
|
17
15
|
callback(err, url);
|
|
18
16
|
if (tempDir) {
|
|
19
|
-
queueMicrotask(() =>
|
|
17
|
+
queueMicrotask(() => Cloud.removeDir(tempDir));
|
|
20
18
|
}
|
|
21
19
|
};
|
|
22
20
|
if (!Bucket || !Key) {
|
|
@@ -24,13 +22,13 @@ function download(credential, service = 'gcp') {
|
|
|
24
22
|
return;
|
|
25
23
|
}
|
|
26
24
|
if (!(tempDir = this.getTempDir({ uuidDir: true }))) {
|
|
27
|
-
downloadResponse(
|
|
25
|
+
downloadResponse((0, types_1.errorValue)("Unable to create temp directory", service));
|
|
28
26
|
return;
|
|
29
27
|
}
|
|
30
|
-
const location =
|
|
31
|
-
const destination = path.join(tempDir, path.basename(Key));
|
|
28
|
+
const location = Cloud.joinPath(Bucket, Key);
|
|
29
|
+
const destination = path.join(tempDir, path.basename(target.filename || Key));
|
|
32
30
|
const deleteMessage = () => this.formatMessage(64, service, "Delete success", location, { ...Cloud.LOG_CLOUD_DELETE });
|
|
33
|
-
if (
|
|
31
|
+
if ((0, client_1.isFirebaseApp)(credential, true, true)) {
|
|
34
32
|
const { ref, getDownloadURL, deleteObject } = require('@firebase/storage');
|
|
35
33
|
const objectRef = ref(storage, Key);
|
|
36
34
|
getDownloadURL(objectRef).then(url => {
|
|
@@ -44,7 +42,7 @@ function download(credential, service = 'gcp') {
|
|
|
44
42
|
if (target.deleteObject) {
|
|
45
43
|
deleteObject(objectRef)
|
|
46
44
|
.then(() => deleteMessage())
|
|
47
|
-
.catch(err => this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active }));
|
|
45
|
+
.catch((err) => this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active }));
|
|
48
46
|
}
|
|
49
47
|
})
|
|
50
48
|
.on('error', err => downloadResponse(err)));
|
|
@@ -54,28 +52,36 @@ function download(credential, service = 'gcp') {
|
|
|
54
52
|
}
|
|
55
53
|
});
|
|
56
54
|
});
|
|
55
|
+
return;
|
|
57
56
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
else {
|
|
71
|
-
this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active });
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
.catch(err => downloadResponse(err));
|
|
57
|
+
const { flags = 0 } = target;
|
|
58
|
+
const bucket = storage.bucket(Bucket);
|
|
59
|
+
const file = bucket.file(Key, { generation: target.versionId });
|
|
60
|
+
const chunkSize = flags & 4 ? (0, types_1.alignSize)(target.chunkSize, 1024) : 0;
|
|
61
|
+
let manager;
|
|
62
|
+
if (chunkSize > 0) {
|
|
63
|
+
const { TransferManager } = require('@google-cloud/storage');
|
|
64
|
+
let concurrencyLimit = target.chunkLimit;
|
|
65
|
+
if (!concurrencyLimit && target.options) {
|
|
66
|
+
({ concurrencyLimit } = target.options);
|
|
67
|
+
}
|
|
68
|
+
manager = new TransferManager(bucket).downloadFileInChunks(file, { destination, chunkSizeBytes: chunkSize, concurrencyLimit });
|
|
77
69
|
}
|
|
70
|
+
(manager || file.download({ destination }))
|
|
71
|
+
.then(() => {
|
|
72
|
+
downloadResponse(null, destination);
|
|
73
|
+
const deleteObject = target.deleteObject;
|
|
74
|
+
if (deleteObject) {
|
|
75
|
+
file.delete((0, types_1.isObject)(deleteObject) ? deleteObject : { ignoreNotFound: true }, err => {
|
|
76
|
+
if (!err) {
|
|
77
|
+
deleteMessage();
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active });
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
.catch((err) => downloadResponse(err));
|
|
78
86
|
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
module.exports = download;
|
|
87
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-r/gcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Google (GCP) cloud functions for E-mc.",
|
|
5
5
|
"main": "client/index.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"homepage": "https://github.com/anpham6/pi-r#readme",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@e-mc/cloud": "^0.
|
|
24
|
-
"@e-mc/module": "^0.
|
|
25
|
-
"@e-mc/types": "^0.
|
|
26
|
-
"@google-cloud/firestore": "^7.
|
|
27
|
-
"@google-cloud/storage": "^7.
|
|
23
|
+
"@e-mc/cloud": "^0.9.0",
|
|
24
|
+
"@e-mc/module": "^0.9.0",
|
|
25
|
+
"@e-mc/types": "^0.9.0",
|
|
26
|
+
"@google-cloud/firestore": "^7.6.0",
|
|
27
|
+
"@google-cloud/storage": "^7.10.1"
|
|
28
28
|
}
|
|
29
29
|
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CloudDatabase, CloudStorage } from '@e-mc/types/lib/cloud';
|
|
2
|
+
|
|
3
|
+
import type { StorageOptions } from '@google-cloud/storage';
|
|
4
|
+
import type { PathType } from '@google-cloud/datastore';
|
|
5
|
+
import type { entity } from '@google-cloud/datastore/build/src/entity';
|
|
6
|
+
import type { FirebaseOptions as IFirebaseOptions } from '@firebase/app';
|
|
7
|
+
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
import type { GoogleAuthOptions } from 'google-auth-library';
|
|
10
|
+
|
|
11
|
+
export type GCPStorage = CloudStorage<GCPStorageCredential, "gcp | gcloud">;
|
|
12
|
+
|
|
13
|
+
export interface GCPStorageCredential extends StorageOptions, IFirebaseOptions {}
|
|
14
|
+
|
|
15
|
+
export interface GCPDatabaseQuery<T = PlainObject> extends Omit<CloudDatabase<unknown, T, unknown, unknown[] | StandardMap, GCPDatabaseCredential>, "id"> {
|
|
16
|
+
source: "cloud";
|
|
17
|
+
service: "gcp" | "gcloud";
|
|
18
|
+
product?: "firestore" | "firebase" | "bigquery" | "bigtable" | "datastore" | "spanner";
|
|
19
|
+
database?: string;
|
|
20
|
+
id?: ArrayOf<string>;
|
|
21
|
+
updateType?: 0 | 1 | 2 | 3;
|
|
22
|
+
columns?: string[];
|
|
23
|
+
keys?: ArrayOf<DatastoreKey>;
|
|
24
|
+
kind?: ArrayOf<string>;
|
|
25
|
+
orderBy?: unknown[][];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type GCPDatabaseCredential = GoogleAuthOptions;
|
|
29
|
+
|
|
30
|
+
export interface FirebaseOptions extends IFirebaseOptions {
|
|
31
|
+
product?: "firebase";
|
|
32
|
+
admin?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type DatastoreKey = string | PathType[] | entity.KeyOptions;
|
|
36
|
+
export type BucketAcl = "authenticatedRead" | "private" | "projectPrivate" | "publicRead" | "publicReadWrite" | "bucketAccessUniform" | "bucketAccessACL";
|
package/upload/index.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const path = require("path");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const stream = require("stream");
|
|
3
5
|
const util_1 = require("@e-mc/cloud/util");
|
|
4
6
|
const types_1 = require("@e-mc/types");
|
|
5
|
-
const Module = require("@e-mc/module");
|
|
6
7
|
const Cloud = require("@e-mc/cloud");
|
|
7
8
|
const client_1 = require("@pi-r/gcp");
|
|
8
9
|
const BUCKET_SESSION = new Set();
|
|
9
10
|
const BUCKET_RESPONSE = {};
|
|
10
|
-
const getBucketKey = (credential, bucket, acl = '') =>
|
|
11
|
-
function upload(credential, service = 'gcp') {
|
|
11
|
+
const getBucketKey = (credential, bucket, acl = '') => Cloud.asString(credential, true) + bucket + '_' + acl;
|
|
12
|
+
module.exports = function upload(credential, service = 'gcp') {
|
|
12
13
|
const storage = client_1.createStorageClient.call(this, credential);
|
|
13
14
|
return async (data, callback) => {
|
|
14
|
-
var _a;
|
|
15
15
|
const firebase = (0, client_1.isFirebaseApp)(credential, true, true);
|
|
16
16
|
const { bucket, localUri } = data;
|
|
17
|
-
const { pathname = '', fileGroup, contentType, metadata, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
|
|
18
|
-
let filename = data.upload.filename || path.basename(localUri), bucketClient, bucketKey, listFiles;
|
|
17
|
+
const { pathname = '', flags = 0, fileGroup, contentType, metadata, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
|
|
18
|
+
let filename = data.upload.filename || path.basename(localUri), chunkSizeBytes = 0, bucketClient, bucketKey, listFiles;
|
|
19
19
|
const uploadResponse = (err, url) => {
|
|
20
20
|
if (!firebase) {
|
|
21
21
|
BUCKET_SESSION.delete(bucket);
|
|
@@ -42,8 +42,8 @@ function upload(credential, service = 'gcp') {
|
|
|
42
42
|
else {
|
|
43
43
|
const configBucket = admin.configBucket;
|
|
44
44
|
if (!BUCKET_SESSION.has(bucket)) {
|
|
45
|
-
const bucketAcl = admin.publicRead ?
|
|
46
|
-
const response = BUCKET_RESPONSE[
|
|
45
|
+
const bucketAcl = admin.publicRead ? "publicRead" : admin.acl;
|
|
46
|
+
const response = BUCKET_RESPONSE[bucketKey = getBucketKey(credential, bucket, bucketAcl)] ||= client_1.createBucketV2.call(this, credential, bucket, bucketAcl, configBucket?.create);
|
|
47
47
|
if (!await response) {
|
|
48
48
|
uploadResponse(null);
|
|
49
49
|
return;
|
|
@@ -51,13 +51,49 @@ function upload(credential, service = 'gcp') {
|
|
|
51
51
|
BUCKET_SESSION.add(bucket);
|
|
52
52
|
}
|
|
53
53
|
bucketClient = storage.bucket(bucket);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
if (configBucket) {
|
|
55
|
+
let { cors, lifecycle, retentionPolicy } = configBucket;
|
|
56
|
+
const commandMessage = (feature, message) => this.formatMessage(64, service, ["Bucket configured" + ` (${feature})`, bucket], message, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
57
|
+
if (typeof retentionPolicy === 'number') {
|
|
58
|
+
bucketClient.setRetentionPeriod(retentionPolicy)
|
|
59
|
+
.then(([response]) => commandMessage('Retention Policy', response.retentionPolicy?.effectiveTime))
|
|
60
|
+
.catch((err) => addLog(err));
|
|
61
|
+
}
|
|
62
|
+
if ((0, types_1.isObject)(cors)) {
|
|
63
|
+
bucketClient.setCorsConfiguration(Array.isArray(cors) ? cors : [cors])
|
|
64
|
+
.then(([response]) => {
|
|
65
|
+
const length = response.cors?.length;
|
|
66
|
+
commandMessage('CORS', length ? length + ' rules' : null);
|
|
67
|
+
})
|
|
68
|
+
.catch((err) => addLog(err));
|
|
69
|
+
}
|
|
70
|
+
if ((0, types_1.isObject)(lifecycle)) {
|
|
71
|
+
let append;
|
|
72
|
+
if (Array.isArray(lifecycle)) {
|
|
73
|
+
if (lifecycle.length === 0) {
|
|
74
|
+
append = false;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const arg = lifecycle[lifecycle.length - 1];
|
|
78
|
+
if (typeof arg === 'boolean') {
|
|
79
|
+
append = arg;
|
|
80
|
+
lifecycle = lifecycle.slice(0, lifecycle.length - 1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
bucketClient.addLifecycleRule(lifecycle, { append })
|
|
85
|
+
.then(([response]) => {
|
|
86
|
+
const length = response.lifecycle?.rule?.length;
|
|
87
|
+
commandMessage('Lifecycle', length ? length + ' rules' : null);
|
|
88
|
+
})
|
|
89
|
+
.catch((err) => addLog(err));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (flags & 4) {
|
|
93
|
+
const chunkSize = (0, types_1.alignSize)(data.upload.chunkSize, 1024);
|
|
94
|
+
if (chunkSize > 0) {
|
|
95
|
+
chunkSizeBytes = Math.max(chunkSize, 8388608);
|
|
96
|
+
}
|
|
61
97
|
}
|
|
62
98
|
}
|
|
63
99
|
if (!overwrite && (!listFiles || listFiles.length)) {
|
|
@@ -71,7 +107,7 @@ function upload(credential, service = 'gcp') {
|
|
|
71
107
|
break;
|
|
72
108
|
}
|
|
73
109
|
}
|
|
74
|
-
const name = pathname ?
|
|
110
|
+
const name = pathname ? Cloud.joinPath(pathname, filename) : filename;
|
|
75
111
|
if (firebase) {
|
|
76
112
|
exists = listFiles.includes(name);
|
|
77
113
|
}
|
|
@@ -83,16 +119,94 @@ function upload(credential, service = 'gcp') {
|
|
|
83
119
|
this.formatMessage(64, service, ["File renamed", current], filename, { ...Cloud.LOG_CLOUD_WARN });
|
|
84
120
|
}
|
|
85
121
|
}
|
|
86
|
-
const getURL = (value) => endpoint ?
|
|
122
|
+
const getURL = (value) => endpoint ? Cloud.joinPath(endpoint, value) : Cloud.joinPath("https://storage.googleapis.com", bucket, value);
|
|
87
123
|
const Key = [filename];
|
|
88
124
|
const Body = [data.buffer];
|
|
125
|
+
const Path = [];
|
|
126
|
+
const Stream = [];
|
|
89
127
|
const ContentType = [contentType];
|
|
90
|
-
if (
|
|
91
|
-
const
|
|
128
|
+
if (chunkSizeBytes > 0) {
|
|
129
|
+
const main = Body[0];
|
|
130
|
+
if (main.length > chunkSizeBytes) {
|
|
131
|
+
try {
|
|
132
|
+
fs.writeFileSync(localUri, main);
|
|
133
|
+
Path[0] = localUri;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
if (flags & 2) {
|
|
137
|
+
Stream[0] = stream.Readable.from(main, { highWaterMark: chunkSizeBytes });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (main.length === 0) {
|
|
142
|
+
try {
|
|
143
|
+
if (fs.statSync(localUri).size > chunkSizeBytes) {
|
|
144
|
+
Path[0] = localUri;
|
|
145
|
+
}
|
|
146
|
+
else if (flags & 2) {
|
|
147
|
+
Stream[0] = fs.createReadStream(localUri, { highWaterMark: chunkSizeBytes, signal: this.signal });
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
Body[0] = fs.readFileSync(localUri);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
uploadResponse(err);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (fileGroup) {
|
|
159
|
+
const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, chunkSizeBytes, addLog, flags);
|
|
160
|
+
Key.push(...key);
|
|
161
|
+
ContentType.push(...type);
|
|
162
|
+
for (let i = 0; i < body.length; ++i) {
|
|
163
|
+
const item = body[i];
|
|
164
|
+
if (typeof item === 'string') {
|
|
165
|
+
Path[i + 1] = item;
|
|
166
|
+
}
|
|
167
|
+
else if (Buffer.isBuffer(item)) {
|
|
168
|
+
Body[i + 1] = item;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
Stream[i + 1] = item;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else if ((flags & 2) && !firebase) {
|
|
177
|
+
try {
|
|
178
|
+
Stream.push(data.buffer.length ? stream.Readable.from(data.buffer) : fs.createReadStream(localUri, { signal: this.signal }));
|
|
179
|
+
if (fileGroup) {
|
|
180
|
+
const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, 0, addLog, 2);
|
|
181
|
+
Key.push(...key);
|
|
182
|
+
Stream.push(...body);
|
|
183
|
+
ContentType.push(...type);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
uploadResponse(err);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else if (fileGroup) {
|
|
192
|
+
const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, 0, addLog);
|
|
92
193
|
Key.push(...key);
|
|
93
194
|
Body.push(...body);
|
|
94
195
|
ContentType.push(...type);
|
|
95
196
|
}
|
|
197
|
+
let headers, concurrencyLimit, maxQueueSize;
|
|
198
|
+
if (options) {
|
|
199
|
+
({ headers, concurrencyLimit, maxQueueSize } = options);
|
|
200
|
+
if (headers !== undefined) {
|
|
201
|
+
delete options.headers;
|
|
202
|
+
}
|
|
203
|
+
if (concurrencyLimit !== undefined) {
|
|
204
|
+
delete options.concurrencyLimit;
|
|
205
|
+
}
|
|
206
|
+
if (maxQueueSize !== undefined) {
|
|
207
|
+
delete options.maxQueueSize;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
96
210
|
for (let i = 0; i < Key.length; ++i) {
|
|
97
211
|
const first = i === 0;
|
|
98
212
|
if (this.aborted) {
|
|
@@ -101,12 +215,21 @@ function upload(credential, service = 'gcp') {
|
|
|
101
215
|
}
|
|
102
216
|
return;
|
|
103
217
|
}
|
|
104
|
-
const destination = pathname ?
|
|
218
|
+
const destination = pathname ? Cloud.joinPath(pathname, Key[i]) : Key[i];
|
|
105
219
|
if (firebase) {
|
|
106
220
|
const { ref, uploadBytes } = require('@firebase/storage');
|
|
107
221
|
const params = { ...options };
|
|
108
222
|
if (first) {
|
|
109
|
-
|
|
223
|
+
if (Body[0].length === 0) {
|
|
224
|
+
try {
|
|
225
|
+
Body[0] = fs.readFileSync(localUri);
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
uploadResponse(err);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
params.contentType ||= ContentType[i];
|
|
110
233
|
if (metadata) {
|
|
111
234
|
params.customMetadata = metadata;
|
|
112
235
|
}
|
|
@@ -122,7 +245,7 @@ function upload(credential, service = 'gcp') {
|
|
|
122
245
|
uploadResponse(null, url);
|
|
123
246
|
}
|
|
124
247
|
})
|
|
125
|
-
.catch(err => {
|
|
248
|
+
.catch((err) => {
|
|
126
249
|
if (first) {
|
|
127
250
|
uploadResponse(err);
|
|
128
251
|
}
|
|
@@ -136,14 +259,14 @@ function upload(credential, service = 'gcp') {
|
|
|
136
259
|
const readable = publicRead || active && publicRead !== false && publicRead !== 0 && !acl;
|
|
137
260
|
let ACL, revoke, predefined;
|
|
138
261
|
if (first) {
|
|
139
|
-
params.contentType
|
|
262
|
+
params.contentType ||= ContentType[i];
|
|
140
263
|
if (readable) {
|
|
141
|
-
ACL =
|
|
264
|
+
ACL = "publicRead";
|
|
142
265
|
}
|
|
143
266
|
else {
|
|
144
267
|
predefined = true;
|
|
145
268
|
}
|
|
146
|
-
if (
|
|
269
|
+
if ((0, types_1.isObject)(metadata)) {
|
|
147
270
|
params.metadata = metadata;
|
|
148
271
|
}
|
|
149
272
|
}
|
|
@@ -151,7 +274,7 @@ function upload(credential, service = 'gcp') {
|
|
|
151
274
|
params.contentType = ContentType[i];
|
|
152
275
|
if (!params.predefinedAcl) {
|
|
153
276
|
if (readable) {
|
|
154
|
-
ACL =
|
|
277
|
+
ACL = "publicRead";
|
|
155
278
|
}
|
|
156
279
|
else {
|
|
157
280
|
predefined = true;
|
|
@@ -160,26 +283,47 @@ function upload(credential, service = 'gcp') {
|
|
|
160
283
|
}
|
|
161
284
|
if (predefined) {
|
|
162
285
|
if (publicRead === 0) {
|
|
163
|
-
ACL =
|
|
286
|
+
ACL = "publicRead";
|
|
164
287
|
revoke = true;
|
|
165
288
|
}
|
|
166
289
|
if (acl && (!revoke || acl !== ACL)) {
|
|
167
290
|
params.predefinedAcl = acl;
|
|
168
291
|
}
|
|
169
292
|
}
|
|
170
|
-
params.resumable ?? (params.resumable = false);
|
|
171
293
|
const file = bucketClient.file(destination);
|
|
172
|
-
|
|
294
|
+
let uploadClient;
|
|
295
|
+
if (Path[i]) {
|
|
296
|
+
const { TransferManager } = require('@google-cloud/storage');
|
|
297
|
+
uploadClient = new TransferManager(bucketClient).uploadFileInChunks(Path[i], { uploadName: destination, chunkSizeBytes, headers, concurrencyLimit: data.upload.chunkLimit || concurrencyLimit, maxQueueSize });
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
params.resumable ??= false;
|
|
301
|
+
if (Stream[i]) {
|
|
302
|
+
if (chunkSizeBytes > 0) {
|
|
303
|
+
params.chunkSize = chunkSizeBytes;
|
|
304
|
+
}
|
|
305
|
+
uploadClient = new Promise((resolve, reject) => {
|
|
306
|
+
Stream[i].pipe(file.createWriteStream(params))
|
|
307
|
+
.on('finish', resolve)
|
|
308
|
+
.on('error', reject);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
(uploadClient || file.save(Body[i], params))
|
|
313
|
+
.then(async () => {
|
|
173
314
|
const url = getURL(file.name);
|
|
174
315
|
this.formatMessage(64, service, "Upload success", url, { ...Cloud.LOG_CLOUD_UPLOAD });
|
|
175
316
|
if (first) {
|
|
176
317
|
uploadResponse(null, url);
|
|
177
318
|
}
|
|
319
|
+
if (Path[i]) {
|
|
320
|
+
file.setMetadata(params).catch((err) => addLog(err));
|
|
321
|
+
}
|
|
178
322
|
if (ACL) {
|
|
179
323
|
client_1.setPredefinedAcl.call(this, file.acl, ACL, file.bucket, file.name, revoke || (await file.getMetadata())[0], true);
|
|
180
324
|
}
|
|
181
325
|
})
|
|
182
|
-
.catch(err => {
|
|
326
|
+
.catch((err) => {
|
|
183
327
|
if (first) {
|
|
184
328
|
uploadResponse(err);
|
|
185
329
|
}
|
|
@@ -190,6 +334,4 @@ function upload(credential, service = 'gcp') {
|
|
|
190
334
|
}
|
|
191
335
|
}
|
|
192
336
|
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
module.exports = upload;
|
|
337
|
+
};
|