gcf-common-lib 0.23.7 → 0.23.8
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/package.json +8 -7
- package/src/index.js +98 -79
- package/src/mongo-lock.js +54 -38
- package/src/utils.js +16 -5
- package/tsconfig.json +10 -6
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gcf-common-lib",
|
|
3
3
|
"description": "",
|
|
4
|
-
"version": "0.23.
|
|
4
|
+
"version": "0.23.8",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"branches": [
|
|
@@ -18,18 +18,19 @@
|
|
|
18
18
|
"url": "https://github.com/TopTechnologies/gcf-common.git"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@google-cloud/pubsub": "^3.
|
|
22
|
-
"@google-cloud/secret-manager": "^4.2.
|
|
23
|
-
"@google-cloud/storage": "^6.9.
|
|
21
|
+
"@google-cloud/pubsub": "^3.2.1",
|
|
22
|
+
"@google-cloud/secret-manager": "^4.2.0",
|
|
23
|
+
"@google-cloud/storage": "^6.9.0",
|
|
24
|
+
"bluebird": "^3.7.2",
|
|
24
25
|
"lodash": "^4.17.21",
|
|
25
26
|
"moment": "^2.29.4",
|
|
26
|
-
"mongodb": "^
|
|
27
|
+
"mongodb": "^4.14.0",
|
|
27
28
|
"rxjs": "^7.8.0"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
|
-
"@tsconfig/
|
|
31
|
+
"@tsconfig/node14": "^1.0.3",
|
|
31
32
|
"@types/lodash": "^4.14.191",
|
|
32
|
-
"@types/node": "^18.
|
|
33
|
+
"@types/node": "^14.18.36"
|
|
33
34
|
},
|
|
34
35
|
"author": "alert83@gmail.com",
|
|
35
36
|
"license": "MIT"
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
13
|
};
|
|
@@ -22,96 +31,106 @@ class GcfCommon {
|
|
|
22
31
|
* @param handler
|
|
23
32
|
* @param timeout Seconds
|
|
24
33
|
*/
|
|
25
|
-
static
|
|
26
|
-
return
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
static process(event, context, handler, timeout = 535) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
return Promise.race([
|
|
37
|
+
(0, utils_1.timeoutAfter)(timeout),
|
|
38
|
+
handler(event, context),
|
|
39
|
+
])
|
|
40
|
+
.then((res) => __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
// console.log('res:', res);
|
|
42
|
+
yield this.publish(event, context, res);
|
|
43
|
+
}))
|
|
44
|
+
.catch((err) => __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
var _a, _b;
|
|
46
|
+
const fname = (_b = (_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.K_SERVICE) !== null && _b !== void 0 ? _b : 'UNKNOWN';
|
|
47
|
+
const response = {
|
|
48
|
+
error: {
|
|
49
|
+
name: err.name,
|
|
50
|
+
message: `GCF [${fname}]: ${err.message}`,
|
|
51
|
+
stack: err.stack,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
yield this.publish(event, context, response, { error: '1' }).catch(noop_1.default);
|
|
55
|
+
throw err;
|
|
56
|
+
}));
|
|
45
57
|
});
|
|
46
58
|
}
|
|
47
|
-
static
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
.map(([k, v]) => [k, '' + v])),
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
response: '1',
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
}
|
|
59
|
+
static publish(event, context, json, attributes) {
|
|
60
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
const { topic, requestId, env } = yield this.getTopic(event, context);
|
|
62
|
+
console.log('publish:', topic, env, json, attributes);
|
|
63
|
+
if (!(0, isEmpty_1.default)(topic)) {
|
|
64
|
+
return exports.pubSub.topic(topic).publishMessage({
|
|
65
|
+
json: json !== null && json !== void 0 ? json : {},
|
|
66
|
+
attributes: Object.assign(Object.assign({}, (0, fromPairs_1.default)(Object.entries(attributes !== null && attributes !== void 0 ? attributes : {})
|
|
67
|
+
.map(([k, v]) => [k, '' + v]))), { env: env !== null && env !== void 0 ? env : '', requestId: requestId !== null && requestId !== void 0 ? requestId : '', type: 'response', response: '1' }),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
63
71
|
}
|
|
64
|
-
static
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
(
|
|
72
|
+
static getTopic(event, context) {
|
|
73
|
+
var _a, _b, _c, _d;
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
/** t_{GUID}__{YYYY-MM-DD} */
|
|
76
|
+
let topic;
|
|
77
|
+
let requestId;
|
|
78
|
+
let env;
|
|
79
|
+
switch (context === null || context === void 0 ? void 0 : context.eventType) {
|
|
80
|
+
case 'google.storage.object.finalize': {
|
|
81
|
+
const gsEvent = event;
|
|
82
|
+
({ topic, requestId, env } = (_a = gsEvent === null || gsEvent === void 0 ? void 0 : gsEvent.metadata) !== null && _a !== void 0 ? _a : {});
|
|
83
|
+
if (!topic && ((_b = context === null || context === void 0 ? void 0 : context.resource) === null || _b === void 0 ? void 0 : _b.type) === 'storage#object') {
|
|
84
|
+
const [meta] = yield exports.storage.bucket(gsEvent.bucket).file(gsEvent.name).getMetadata();
|
|
85
|
+
({ topic, requestId, env } = (_c = meta === null || meta === void 0 ? void 0 : meta.metadata) !== null && _c !== void 0 ? _c : {});
|
|
86
|
+
}
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case 'google.pubsub.topic.publish': {
|
|
90
|
+
const psEvent = event;
|
|
91
|
+
({ topic, requestId, env } = (_d = psEvent === null || psEvent === void 0 ? void 0 : psEvent.attributes) !== null && _d !== void 0 ? _d : {});
|
|
92
|
+
break;
|
|
76
93
|
}
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
case 'google.pubsub.topic.publish': {
|
|
80
|
-
const psEvent = event;
|
|
81
|
-
({ topic, requestId, env } = psEvent?.attributes ?? {});
|
|
82
|
-
break;
|
|
83
94
|
}
|
|
84
|
-
|
|
85
|
-
|
|
95
|
+
return { topic, requestId, env };
|
|
96
|
+
});
|
|
86
97
|
}
|
|
87
|
-
static
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
static getOptions(event, context) {
|
|
99
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
100
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
switch (context === null || context === void 0 ? void 0 : context.eventType) {
|
|
102
|
+
case 'google.storage.object.finalize': {
|
|
103
|
+
const gsEvent = event;
|
|
104
|
+
if ((_a = gsEvent === null || gsEvent === void 0 ? void 0 : gsEvent.metadata) === null || _a === void 0 ? void 0 : _a.options) {
|
|
105
|
+
return JSON.parse((_c = (_b = gsEvent === null || gsEvent === void 0 ? void 0 : gsEvent.metadata) === null || _b === void 0 ? void 0 : _b.options) !== null && _c !== void 0 ? _c : '{}');
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const file = exports.storage.bucket(gsEvent.bucket).file(gsEvent.name);
|
|
109
|
+
const [meta] = yield file.getMetadata();
|
|
110
|
+
return JSON.parse((_e = (_d = meta === null || meta === void 0 ? void 0 : meta.metadata) === null || _d === void 0 ? void 0 : _d.options) !== null && _e !== void 0 ? _e : '{}');
|
|
111
|
+
}
|
|
93
112
|
}
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
return JSON.parse(meta?.metadata?.options ?? '{}');
|
|
113
|
+
case 'google.pubsub.topic.publish': {
|
|
114
|
+
const psEvent = event;
|
|
115
|
+
return JSON.parse((_g = (_f = psEvent === null || psEvent === void 0 ? void 0 : psEvent.attributes) === null || _f === void 0 ? void 0 : _f.options) !== null && _g !== void 0 ? _g : '{}');
|
|
98
116
|
}
|
|
99
117
|
}
|
|
100
|
-
|
|
101
|
-
const psEvent = event;
|
|
102
|
-
return JSON.parse(psEvent?.attributes?.options ?? '{}');
|
|
103
|
-
}
|
|
104
|
-
}
|
|
118
|
+
});
|
|
105
119
|
}
|
|
106
|
-
static
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
static getSecret(name, version) {
|
|
121
|
+
var _a, _b;
|
|
122
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
const projectId = yield exports.secretClient.getProjectId();
|
|
124
|
+
const secretName = `projects/${projectId}/secrets/${name}`;
|
|
125
|
+
const secretVersion = `${secretName}/versions/${version !== null && version !== void 0 ? version : 'latest'}`;
|
|
126
|
+
const [response] = yield exports.secretClient.accessSecretVersion({ name: secretVersion });
|
|
127
|
+
return (_b = (_a = response === null || response === void 0 ? void 0 : response.payload) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.toString();
|
|
128
|
+
});
|
|
112
129
|
}
|
|
113
|
-
static
|
|
114
|
-
return
|
|
130
|
+
static getSecrets(names, versions) {
|
|
131
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
return Promise.all(names.map((name, idx) => __awaiter(this, void 0, void 0, function* () { return this.getSecret(name, versions === null || versions === void 0 ? void 0 : versions[idx]).catch(); })));
|
|
133
|
+
});
|
|
115
134
|
}
|
|
116
135
|
}
|
|
117
136
|
exports.GcfCommon = GcfCommon;
|
package/src/mongo-lock.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
13
|
};
|
|
@@ -8,18 +17,19 @@ const moment_1 = __importDefault(require("moment"));
|
|
|
8
17
|
const noop_1 = __importDefault(require("lodash/noop"));
|
|
9
18
|
const rxjs_1 = require("rxjs");
|
|
10
19
|
class MongoLock {
|
|
11
|
-
client;
|
|
12
20
|
constructor(client) {
|
|
13
21
|
this.client = client;
|
|
14
22
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
getCollection() {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const locksColl = this.client.db().collection('locks');
|
|
26
|
+
yield locksColl.indexExists('expiresAt')
|
|
27
|
+
.then((exists) => __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
if (!exists)
|
|
29
|
+
yield locksColl.createIndex({ "expiresAt": 1 }, { expireAfterSeconds: 0 });
|
|
30
|
+
}));
|
|
31
|
+
return locksColl;
|
|
21
32
|
});
|
|
22
|
-
return locksColl;
|
|
23
33
|
}
|
|
24
34
|
/**
|
|
25
35
|
* Create the MongoDB collection and an expiring index on a field named "expiresAt".
|
|
@@ -27,39 +37,45 @@ class MongoLock {
|
|
|
27
37
|
* db.createCollection('locks');
|
|
28
38
|
* db.locks.createIndex( { "expiresAt": 1 }, { expireAfterSeconds: 0 } )
|
|
29
39
|
**/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
acquireLock(name, ttlSeconds) {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
const collection = yield this.getCollection();
|
|
43
|
+
// Entry gets removed automatically due to an expiry index in Mongo
|
|
44
|
+
const expiresAt = (0, moment_1.default)().add(ttlSeconds, 'seconds').toDate();
|
|
45
|
+
try {
|
|
46
|
+
yield collection.insertOne({
|
|
47
|
+
_id: name,
|
|
48
|
+
expiresAt,
|
|
49
|
+
});
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch (ex) {
|
|
53
|
+
// 11000 means duplicate key error, which is expected on an active lock
|
|
54
|
+
if ((ex === null || ex === void 0 ? void 0 : ex.code) !== 11000) {
|
|
55
|
+
// Unexpected error, what happened here :o
|
|
56
|
+
throw ex;
|
|
57
|
+
}
|
|
58
|
+
// As we got a duplicate key exception, no lock could be acquired
|
|
59
|
+
return false;
|
|
46
60
|
}
|
|
47
|
-
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
61
|
+
});
|
|
50
62
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
releaseLock(name) {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
const collection = yield this.getCollection();
|
|
66
|
+
return collection.deleteOne({ _id: name });
|
|
67
|
+
});
|
|
54
68
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
acquireAndExecute(name, ttlSeconds, wait, fn) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
const delay = 200;
|
|
72
|
+
const count = Math.round((1000 / delay) * ttlSeconds);
|
|
73
|
+
return (0, rxjs_1.lastValueFrom)((0, rxjs_1.defer)(() => (0, rxjs_1.from)(this.acquireLock(name, ttlSeconds))).pipe((0, rxjs_1.map)(locked => {
|
|
74
|
+
console.log(locked);
|
|
75
|
+
if (!locked)
|
|
76
|
+
throw locked;
|
|
77
|
+
}), wait ? (0, rxjs_1.retry)({ count, delay }) : rxjs_1.identity, (0, rxjs_1.switchMap)(() => fn().finally(() => this.releaseLock(name).catch(noop_1.default)))));
|
|
78
|
+
});
|
|
63
79
|
}
|
|
64
80
|
}
|
|
65
81
|
exports.MongoLock = MongoLock;
|
package/src/utils.js
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
exports.A1ToColNum = exports.colNumToA1 = exports.A1ToIndex = exports.indexToA1 = exports.timeoutAfter = void 0;
|
|
4
13
|
/**
|
|
5
14
|
*
|
|
6
15
|
* @param seconds Google function timeout limit (max: 9 min)
|
|
7
16
|
*/
|
|
8
|
-
|
|
9
|
-
return
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
function timeoutAfter(seconds = 540) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
reject(new Error(`${seconds} seconds timeout exceeded`));
|
|
22
|
+
}, seconds * 1000);
|
|
23
|
+
});
|
|
13
24
|
});
|
|
14
25
|
}
|
|
15
26
|
exports.timeoutAfter = timeoutAfter;
|
package/tsconfig.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json.schemastore.org/tsconfig",
|
|
3
|
-
"extends": "@tsconfig/
|
|
3
|
+
"extends": "@tsconfig/node14/tsconfig.json",
|
|
4
4
|
"compilerOptions": {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
"target": "ES6",
|
|
6
|
+
"lib": [
|
|
7
|
+
"ES2018",
|
|
8
|
+
"ES2019",
|
|
9
|
+
"ES2020",
|
|
10
|
+
"ES2021",
|
|
11
|
+
"ESNext"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
10
14
|
}
|