@pi-r/gcp 0.6.6 → 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 -67
- package/download/index.js +37 -29
- package/package.json +5 -5
- package/types/index.d.ts +36 -0
- package/upload/index.js +173 -29
package/README.md
CHANGED
package/client/index.js
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
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;
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const storage = require("@google-cloud/storage");
|
|
5
5
|
const firestore_1 = require("@google-cloud/firestore");
|
|
6
6
|
const util_1 = require("@e-mc/cloud/util");
|
|
7
7
|
const types_1 = require("@e-mc/types");
|
|
8
|
-
const Module = require("@e-mc/module");
|
|
9
8
|
const Cloud = require("@e-mc/cloud");
|
|
10
9
|
const FIREBASE_DB = {};
|
|
11
10
|
const FIREBASE_STORAGE = {};
|
|
12
11
|
const ADMIN_DB = {};
|
|
13
12
|
const ADMIN_STORAGE = {};
|
|
14
13
|
function getApp(credential, isDB) {
|
|
15
|
-
var _a, _b;
|
|
16
14
|
const { projectId, databaseURL, storageBucket, apiKey, authDomain } = credential;
|
|
17
15
|
if (apiKey && authDomain) {
|
|
18
16
|
const { getApps, initializeApp } = require('@firebase/app');
|
|
@@ -26,7 +24,7 @@ function getApp(credential, isDB) {
|
|
|
26
24
|
}
|
|
27
25
|
if (!app) {
|
|
28
26
|
const firebaseKey = (projectId || '') + '_' + apiKey + '_' + authDomain + (isDB ? '_' + databaseURL : '');
|
|
29
|
-
app = isDB ? FIREBASE_DB[firebaseKey]
|
|
27
|
+
app = isDB ? FIREBASE_DB[firebaseKey] ||= initializeApp({ ...credential, databaseURL }, firebaseKey) : FIREBASE_STORAGE[firebaseKey] ||= initializeApp({ ...credential, storageBucket }, firebaseKey);
|
|
30
28
|
}
|
|
31
29
|
if (isDB) {
|
|
32
30
|
const { getDatabase, goOnline } = require('@firebase/database');
|
|
@@ -47,7 +45,7 @@ function getApp(credential, isDB) {
|
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
47
|
if (!app) {
|
|
50
|
-
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);
|
|
51
49
|
}
|
|
52
50
|
credential.admin = true;
|
|
53
51
|
if (isDB) {
|
|
@@ -59,7 +57,7 @@ function getApp(credential, isDB) {
|
|
|
59
57
|
}
|
|
60
58
|
}
|
|
61
59
|
async function hasBucket(client) {
|
|
62
|
-
const [exists] = await client.exists().catch(err => isErrorConflict(err) ? [true] : [false]);
|
|
60
|
+
const [exists] = await client.exists().catch((err) => isErrorConflict(err) ? [true] : [false]);
|
|
63
61
|
return exists;
|
|
64
62
|
}
|
|
65
63
|
async function updatePredefinedAcl(acl, values, metadata = {}) {
|
|
@@ -83,7 +81,7 @@ async function updatePredefinedAcl(acl, values, metadata = {}) {
|
|
|
83
81
|
}
|
|
84
82
|
if ((0, types_1.isString)(value.role)) {
|
|
85
83
|
if (projectNumber !== undefined) {
|
|
86
|
-
value.userProject
|
|
84
|
+
value.userProject ||= projectNumber.toString();
|
|
87
85
|
}
|
|
88
86
|
return target.add(value);
|
|
89
87
|
}
|
|
@@ -99,24 +97,24 @@ async function updatePredefinedAcl(acl, values, metadata = {}) {
|
|
|
99
97
|
}
|
|
100
98
|
return errors;
|
|
101
99
|
})
|
|
102
|
-
.catch(err => [err]);
|
|
100
|
+
.catch((err) => [err]);
|
|
103
101
|
}
|
|
104
102
|
async function setUniformBucketLevel(bucket, enabled) {
|
|
105
103
|
return bucket.setMetadata({ iamConfiguration: { uniformBucketLevelAccess: { enabled } } });
|
|
106
104
|
}
|
|
107
105
|
const getFirebasePackageName = (credential) => credential.apiKey && credential.authDomain ? 'firebase' : 'firebase-admin';
|
|
108
|
-
const hasKeyFile = (credential) => (0, types_1.isString)(credential.keyFilename || credential.keyFile || process.env.GOOGLE_APPLICATION_CREDENTIALS) || (0, types_1.isObject)(credential.credentials);
|
|
109
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;
|
|
110
108
|
function isFirebaseApp(credential, store, admin) {
|
|
111
|
-
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);
|
|
112
110
|
}
|
|
113
111
|
exports.isFirebaseApp = isFirebaseApp;
|
|
114
112
|
function validateStorage(credential) {
|
|
115
|
-
return
|
|
113
|
+
return hasGoogleAuth(credential) || isFirebaseApp(credential, true);
|
|
116
114
|
}
|
|
117
115
|
exports.validateStorage = validateStorage;
|
|
118
116
|
function validateDatabase(credential, data) {
|
|
119
|
-
return (
|
|
117
|
+
return hasGoogleAuth(credential) && !!(data.product || data.database || data.table || data.query || data.id || data.keys || data.kind || data.options?.query) || isFirebaseApp(credential);
|
|
120
118
|
}
|
|
121
119
|
exports.validateDatabase = validateDatabase;
|
|
122
120
|
function createStorageClient(credential, bucket) {
|
|
@@ -141,29 +139,26 @@ exports.createStorageClient = createStorageClient;
|
|
|
141
139
|
function createDatabaseClient(credential, data) {
|
|
142
140
|
let packageName = '';
|
|
143
141
|
try {
|
|
144
|
-
|
|
145
|
-
if (data) {
|
|
146
|
-
({ product, name, table, query, database } = data);
|
|
147
|
-
}
|
|
148
|
-
if (product === 'firebase' || isFirebaseApp(credential)) {
|
|
142
|
+
if (data?.product === "firebase" || isFirebaseApp(credential)) {
|
|
149
143
|
packageName = getFirebasePackageName(credential);
|
|
150
144
|
return getApp(credential, true);
|
|
151
145
|
}
|
|
152
146
|
getProjectId(credential, true);
|
|
153
147
|
if (data) {
|
|
154
|
-
|
|
148
|
+
const { product, name, table, query, database } = data;
|
|
149
|
+
if (product === "spanner" || !product && name && database && (query || table)) {
|
|
155
150
|
const { Spanner } = require(packageName = '@google-cloud/spanner');
|
|
156
151
|
return new Spanner(credential);
|
|
157
152
|
}
|
|
158
|
-
if (product ===
|
|
153
|
+
if (product === "bigquery" || !product && (!name && table && database || (0, types_1.isString)(query))) {
|
|
159
154
|
const { BigQuery } = require(packageName = '@google-cloud/bigquery');
|
|
160
155
|
return new BigQuery(credential);
|
|
161
156
|
}
|
|
162
|
-
if (product ===
|
|
157
|
+
if (product === "bigtable" || !product && name && table && !database) {
|
|
163
158
|
const { Bigtable } = require(packageName = '@google-cloud/bigtable');
|
|
164
159
|
return new Bigtable(credential);
|
|
165
160
|
}
|
|
166
|
-
if (product ===
|
|
161
|
+
if (product === "datastore" || !product && (data.keys || data.kind || query && !table && !data.id)) {
|
|
167
162
|
const { Datastore } = require(packageName = '@google-cloud/datastore');
|
|
168
163
|
return new Datastore(credential);
|
|
169
164
|
}
|
|
@@ -222,32 +217,32 @@ async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
|
|
|
222
217
|
if (!Array.isArray(options.acl)) {
|
|
223
218
|
options.acl = undefined;
|
|
224
219
|
switch (acl) {
|
|
225
|
-
case
|
|
226
|
-
case
|
|
227
|
-
await client.makePrivate(options).catch(err => !isErrorConflict(err) && errors.push(err));
|
|
228
|
-
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));
|
|
229
224
|
break;
|
|
230
|
-
case
|
|
231
|
-
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));
|
|
232
227
|
options = { ...options };
|
|
233
228
|
options.acl = [{ entity: 'allUsers' }, { entity: 'allAuthenticatedUsers', role: 'READER' }];
|
|
234
229
|
break;
|
|
235
|
-
case
|
|
236
|
-
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));
|
|
237
232
|
options = { ...options };
|
|
238
233
|
options.acl = [{ entity: 'allUsers', role: 'WRITER' }];
|
|
239
234
|
break;
|
|
240
|
-
case
|
|
241
|
-
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));
|
|
242
237
|
break;
|
|
243
238
|
case 'bucketAccessUniform':
|
|
244
|
-
await setUniformBucketLevel(client, true).catch(err => errors.push(err));
|
|
239
|
+
await setUniformBucketLevel(client, true).catch((err) => errors.push(err));
|
|
245
240
|
break;
|
|
246
241
|
case 'bucketAccessACL':
|
|
247
|
-
await setUniformBucketLevel(client, false).catch(err => errors.push(err));
|
|
242
|
+
await setUniformBucketLevel(client, false).catch((err) => errors.push(err));
|
|
248
243
|
break;
|
|
249
244
|
default:
|
|
250
|
-
errors.push((0, types_1.errorValue)('Invalid ACL',
|
|
245
|
+
errors.push((0, types_1.errorValue)('Invalid ACL', Cloud.asString(acl) || 'empty'));
|
|
251
246
|
break;
|
|
252
247
|
}
|
|
253
248
|
}
|
|
@@ -262,6 +257,33 @@ async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
|
|
|
262
257
|
return true;
|
|
263
258
|
}
|
|
264
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;
|
|
265
287
|
async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
|
|
266
288
|
if (isFirebaseApp(credential, true, true)) {
|
|
267
289
|
return false;
|
|
@@ -276,11 +298,11 @@ async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
|
|
|
276
298
|
}
|
|
277
299
|
return createStorageClient.call(this, credential, bucket).bucket(bucket).setMetadata({ website })
|
|
278
300
|
.then(() => {
|
|
279
|
-
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 });
|
|
280
302
|
return true;
|
|
281
303
|
})
|
|
282
|
-
.catch(err => {
|
|
283
|
-
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 });
|
|
284
306
|
return false;
|
|
285
307
|
});
|
|
286
308
|
}
|
|
@@ -304,7 +326,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
|
|
|
304
326
|
}
|
|
305
327
|
if (recursive && prefixes.length) {
|
|
306
328
|
for (const { name } of prefixes) {
|
|
307
|
-
await recurse(
|
|
329
|
+
await recurse(Cloud.joinPath(prefix, name));
|
|
308
330
|
}
|
|
309
331
|
}
|
|
310
332
|
}
|
|
@@ -327,7 +349,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
|
|
|
327
349
|
const result = await client.getFiles();
|
|
328
350
|
for (const { name } of result[0]) {
|
|
329
351
|
if (!name.includes('/')) {
|
|
330
|
-
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 })));
|
|
331
353
|
}
|
|
332
354
|
}
|
|
333
355
|
}
|
|
@@ -354,7 +376,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
|
|
|
354
376
|
this.formatMessage(64, service, ["Bucket emptied" + ` (${recursive ? 'recursive' : files})`, bucket], recursive ? files : '', { ...Cloud.LOG_CLOUD_COMMAND });
|
|
355
377
|
}
|
|
356
378
|
})
|
|
357
|
-
.catch(err => {
|
|
379
|
+
.catch((err) => {
|
|
358
380
|
errors.push(err);
|
|
359
381
|
});
|
|
360
382
|
}
|
|
@@ -368,7 +390,7 @@ exports.executeQuery = executeQuery;
|
|
|
368
390
|
async function executeBatchQuery(credential, batch, sessionKey) {
|
|
369
391
|
const length = batch.length;
|
|
370
392
|
const result = new Array(length);
|
|
371
|
-
const clients =
|
|
393
|
+
const clients = {};
|
|
372
394
|
const caching = length > 0 && this.hasCache(batch[0].service, sessionKey);
|
|
373
395
|
const cacheValue = { value: this.valueOfKey(credential, 'cache'), sessionKey };
|
|
374
396
|
const authItems = [];
|
|
@@ -383,7 +405,14 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
383
405
|
};
|
|
384
406
|
const closeClient = () => {
|
|
385
407
|
const fs = clients[3];
|
|
386
|
-
fs
|
|
408
|
+
if (fs) {
|
|
409
|
+
fs.terminate();
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const sp = clients[5];
|
|
413
|
+
if (sp) {
|
|
414
|
+
sp.close();
|
|
415
|
+
}
|
|
387
416
|
};
|
|
388
417
|
const getFamily = (data, row, family) => {
|
|
389
418
|
const familyData = data[family];
|
|
@@ -416,14 +445,14 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
416
445
|
};
|
|
417
446
|
cacheValue.exclusiveOf = Array.isArray(ignoreCache) ? ignoreCache : undefined;
|
|
418
447
|
let rows, queryString = '';
|
|
419
|
-
if (product ===
|
|
448
|
+
if (product === "firebase" || isFirebaseApp(credential)) {
|
|
420
449
|
if (!(0, types_1.isString)(query)) {
|
|
421
450
|
closeClient();
|
|
422
451
|
throw (0, util_1.formatError)(item, "Missing database query");
|
|
423
452
|
}
|
|
424
453
|
const orderBy = item.orderBy;
|
|
425
454
|
if (useCache) {
|
|
426
|
-
queryString = query +
|
|
455
|
+
queryString = query + Cloud.asString(orderBy, true);
|
|
427
456
|
if (!update && (rows = getCache(queryString))) {
|
|
428
457
|
result[i] = rows;
|
|
429
458
|
continue;
|
|
@@ -472,7 +501,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
472
501
|
rows = [group && (0, types_1.isObject)(val) && (0, types_1.isObject)(val[group[0]]) ? val[group[0]] : val];
|
|
473
502
|
}
|
|
474
503
|
}
|
|
475
|
-
else if (product ===
|
|
504
|
+
else if (product === "spanner" || !product && name && database && (query || table)) {
|
|
476
505
|
const columns = (0, types_1.isPlainObject)(query) && query.columns || item.columns;
|
|
477
506
|
if (!(query || table && columns)) {
|
|
478
507
|
closeClient();
|
|
@@ -484,7 +513,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
484
513
|
}
|
|
485
514
|
const { updateType, options = {} } = item;
|
|
486
515
|
if (useCache) {
|
|
487
|
-
queryString = name + '_' + database + '_' + (table ? table + (columns ?
|
|
516
|
+
queryString = name + '_' + database + '_' + (table ? table + (columns ? Cloud.asString(columns, true) : '') : '') + Cloud.asString(query, true) + (limit > 0 ? limit : '');
|
|
488
517
|
if (!update && (rows = getCache(queryString))) {
|
|
489
518
|
result[i] = rows;
|
|
490
519
|
continue;
|
|
@@ -515,8 +544,12 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
515
544
|
}
|
|
516
545
|
else {
|
|
517
546
|
transaction.runUpdate(update)
|
|
518
|
-
.then(async () =>
|
|
519
|
-
.
|
|
547
|
+
.then(async () => {
|
|
548
|
+
transaction.commit()
|
|
549
|
+
.then(() => resolve())
|
|
550
|
+
.catch(reject);
|
|
551
|
+
})
|
|
552
|
+
.catch(reject);
|
|
520
553
|
}
|
|
521
554
|
});
|
|
522
555
|
});
|
|
@@ -524,12 +557,12 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
524
557
|
const request = (0, types_1.isPlainObject)(query) ? query : { sql: query };
|
|
525
558
|
request.json = true;
|
|
526
559
|
if (limit > 0) {
|
|
527
|
-
(request.gaxOptions
|
|
560
|
+
(request.gaxOptions ||= {}).maxResults = limit;
|
|
528
561
|
}
|
|
529
562
|
[rows] = await db.run(request);
|
|
530
563
|
}
|
|
531
564
|
}
|
|
532
|
-
else if (product ===
|
|
565
|
+
else if (product === "bigtable" || !product && name && table && !database) {
|
|
533
566
|
if (!name || !table) {
|
|
534
567
|
closeClient();
|
|
535
568
|
throw (0, util_1.formatError)(item, !name ? "Missing database name" : "Missing database table");
|
|
@@ -539,10 +572,10 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
539
572
|
options.filter = query;
|
|
540
573
|
}
|
|
541
574
|
if (!id && limit > 0) {
|
|
542
|
-
(options.gaxOptions
|
|
575
|
+
(options.gaxOptions ||= {}).maxResults = limit;
|
|
543
576
|
}
|
|
544
577
|
if (useCache) {
|
|
545
|
-
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);
|
|
546
579
|
if (!(update && id) && (rows = getCache(queryString))) {
|
|
547
580
|
result[i] = rows;
|
|
548
581
|
continue;
|
|
@@ -573,7 +606,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
573
606
|
});
|
|
574
607
|
}
|
|
575
608
|
}
|
|
576
|
-
else if (product ===
|
|
609
|
+
else if (product === "bigquery" || !product && (!name && database && table || (0, types_1.isString)(query) || (0, types_1.isString)(item.options?.query))) {
|
|
577
610
|
const { params, options = {} } = item;
|
|
578
611
|
if ((0, types_1.isString)(query)) {
|
|
579
612
|
options.query = query;
|
|
@@ -585,7 +618,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
585
618
|
options.maxResults = limit;
|
|
586
619
|
}
|
|
587
620
|
if (useCache) {
|
|
588
|
-
queryString = query + (database ? '_' + database + (table ? '_' + table : '') : '') +
|
|
621
|
+
queryString = query + (database ? '_' + database + (table ? '_' + table : '') : '') + Cloud.asString(options, true);
|
|
589
622
|
if (!update && (rows = getCache(queryString))) {
|
|
590
623
|
result[i] = rows;
|
|
591
624
|
continue;
|
|
@@ -612,7 +645,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
612
645
|
}
|
|
613
646
|
[rows] = await job.getQueryResults();
|
|
614
647
|
}
|
|
615
|
-
else if (product ===
|
|
648
|
+
else if (product === "datastore" || !product && (item.keys || item.kind || query && !table && !id)) {
|
|
616
649
|
const { keys, kind } = item;
|
|
617
650
|
if (!keys && !kind && !Array.isArray(query)) {
|
|
618
651
|
closeClient();
|
|
@@ -668,19 +701,19 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
668
701
|
db.runQuery(task.select('__key__'), item.options).then(entities => {
|
|
669
702
|
if ((0, types_1.isArray)(entities)) {
|
|
670
703
|
const items = entities.map((entity) => db.key(entity[db.KEY]));
|
|
671
|
-
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));
|
|
672
705
|
}
|
|
673
706
|
else {
|
|
674
707
|
resolve();
|
|
675
708
|
}
|
|
676
709
|
})
|
|
677
|
-
.catch(err => reject(err));
|
|
710
|
+
.catch((err) => reject(err));
|
|
678
711
|
});
|
|
679
712
|
}
|
|
680
713
|
[rows] = await db.runQuery(task, item.options);
|
|
681
714
|
}
|
|
682
715
|
}
|
|
683
|
-
else if (product ===
|
|
716
|
+
else if (product === "firestore" || !product && table) {
|
|
684
717
|
if (!table) {
|
|
685
718
|
closeClient();
|
|
686
719
|
throw (0, util_1.formatError)(item, "Missing database table");
|
|
@@ -704,7 +737,34 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
704
737
|
else {
|
|
705
738
|
const doc = db.collection(table).doc(id);
|
|
706
739
|
if ((0, types_1.isPlainObject)(update)) {
|
|
707
|
-
|
|
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
|
+
}
|
|
708
768
|
}
|
|
709
769
|
const data = (await doc.get()).data();
|
|
710
770
|
if (data) {
|
|
@@ -714,7 +774,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
714
774
|
}
|
|
715
775
|
else if (Array.isArray(query)) {
|
|
716
776
|
const orderBy = item.orderBy;
|
|
717
|
-
if (useCache && (rows = getCache(queryString = table + '_' +
|
|
777
|
+
if (useCache && (rows = getCache(queryString = table + '_' + Cloud.asString(query, true) + Cloud.asString(orderBy, true) + (limit > 0 ? limit : '')))) {
|
|
718
778
|
result[i] = rows;
|
|
719
779
|
continue;
|
|
720
780
|
}
|
|
@@ -726,7 +786,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
|
|
|
726
786
|
switch (method) {
|
|
727
787
|
case 'whereAnd':
|
|
728
788
|
case 'whereOr':
|
|
729
|
-
if (params.every(p =>
|
|
789
|
+
if (params.every(p => (0, types_1.isArray)(p))) {
|
|
730
790
|
db = db.where(firestore_1.Filter[method === 'whereAnd' ? 'and' : 'or'](...params.map((p) => firestore_1.Filter.where(p[0], p[1], p[2]))));
|
|
731
791
|
}
|
|
732
792
|
else {
|
|
@@ -783,7 +843,7 @@ function setPublicRead(acl, pathname, requested, service = 'gcp') {
|
|
|
783
843
|
this.formatMessage(64, service, "Grant public-read", pathname, { ...Cloud.LOG_CLOUD_COMMAND });
|
|
784
844
|
}
|
|
785
845
|
})
|
|
786
|
-
.catch(err => {
|
|
846
|
+
.catch((err) => {
|
|
787
847
|
if (requested) {
|
|
788
848
|
this.formatMessage(64, service, ["Unable to grant public-read", pathname], err, { ...Cloud.LOG_CLOUD_WARN });
|
|
789
849
|
}
|
|
@@ -815,7 +875,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
|
|
|
815
875
|
items = [{ entity: 'allUsers' }, { entity: 'allAuthenticatedUsers' }];
|
|
816
876
|
}
|
|
817
877
|
switch (value) {
|
|
818
|
-
case
|
|
878
|
+
case "private": {
|
|
819
879
|
const owners = new Set(acl.filter(item => item.role === 'OWNER' && item.entity).map(item => item.entity));
|
|
820
880
|
if (owner) {
|
|
821
881
|
owners.add(owner);
|
|
@@ -830,7 +890,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
|
|
|
830
890
|
}
|
|
831
891
|
break;
|
|
832
892
|
}
|
|
833
|
-
case
|
|
893
|
+
case "projectPrivate":
|
|
834
894
|
for (const user of acl) {
|
|
835
895
|
const entity = user.entity;
|
|
836
896
|
if (entity) {
|
|
@@ -839,7 +899,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
|
|
|
839
899
|
}
|
|
840
900
|
}
|
|
841
901
|
break;
|
|
842
|
-
case
|
|
902
|
+
case "bucketOwnerRead":
|
|
843
903
|
if (bucket && owner) {
|
|
844
904
|
for (const user of acl) {
|
|
845
905
|
const entity = user.entity;
|
|
@@ -848,7 +908,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
|
|
|
848
908
|
}
|
|
849
909
|
}
|
|
850
910
|
}
|
|
851
|
-
case
|
|
911
|
+
case "bucketOwnerFullControl":
|
|
852
912
|
if (bucket && owner) {
|
|
853
913
|
items.push({ entity: owner, role: 'OWNER' });
|
|
854
914
|
}
|
|
@@ -915,13 +975,16 @@ function getProjectId(credential, cache) {
|
|
|
915
975
|
const id = require(pathname).project_id;
|
|
916
976
|
if ((0, types_1.isString)(id)) {
|
|
917
977
|
projectId = id;
|
|
918
|
-
credential.projectId = projectId;
|
|
919
978
|
}
|
|
920
979
|
}
|
|
921
980
|
catch {
|
|
922
981
|
}
|
|
982
|
+
credential.projectId = projectId || (projectId = process.env.GCLOUD_PROJECT);
|
|
923
983
|
}
|
|
924
984
|
}
|
|
925
985
|
return projectId;
|
|
926
986
|
}
|
|
927
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
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 @@ module.exports = 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 @@ module.exports = 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,26 +52,36 @@ module.exports = 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
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.
|
|
23
|
+
"@e-mc/cloud": "^0.9.0",
|
|
24
|
+
"@e-mc/module": "^0.9.0",
|
|
25
|
+
"@e-mc/types": "^0.9.0",
|
|
26
26
|
"@google-cloud/firestore": "^7.6.0",
|
|
27
|
-
"@google-cloud/storage": "^7.
|
|
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
|
+
const getBucketKey = (credential, bucket, acl = '') => Cloud.asString(credential, true) + bucket + '_' + acl;
|
|
11
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 @@ module.exports = 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 @@ module.exports = 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 @@ module.exports = 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 @@ module.exports = 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 @@ module.exports = 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 @@ module.exports = 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 @@ module.exports = 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 @@ module.exports = 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 @@ module.exports = 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
|
}
|