gcf-common-lib 0.21.4 → 0.22.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gcf-common-lib",
3
3
  "description": "",
4
- "version": "0.21.4",
4
+ "version": "0.22.4",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "branches": [
@@ -18,15 +18,19 @@
18
18
  "url": "https://github.com/TopTechnologies/gcf-common.git"
19
19
  },
20
20
  "dependencies": {
21
- "@google-cloud/pubsub": "^3.2.0",
22
- "@google-cloud/secret-manager": "^4.1.3",
23
- "@google-cloud/storage": "^6.5.2",
24
- "lodash": "^4.17.21"
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",
25
+ "lodash": "^4.17.21",
26
+ "moment": "^2.29.4",
27
+ "mongodb": "^4.13.0",
28
+ "rxjs": "^7.8.0"
25
29
  },
26
30
  "devDependencies": {
27
31
  "@tsconfig/node14": "^1.0.3",
28
- "@types/node": "^14.18.32",
29
- "@types/lodash": "^4.14.186"
32
+ "@types/lodash": "^4.14.191",
33
+ "@types/node": "^14.18.36"
30
34
  },
31
35
  "author": "alert83@gmail.com",
32
36
  "license": "MIT"
package/src/index.js CHANGED
@@ -12,17 +12,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.GcfCommon = exports.storage = exports.pubSub = void 0;
15
+ exports.GcfCommon = exports.secretClient = exports.storage = exports.pubSub = void 0;
16
16
  const pubsub_1 = require("@google-cloud/pubsub");
17
- const secret_manager_1 = require("@google-cloud/secret-manager");
18
- const storage_1 = require("@google-cloud/storage");
19
17
  const fromPairs_1 = __importDefault(require("lodash/fromPairs"));
20
18
  const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
21
19
  const noop_1 = __importDefault(require("lodash/noop"));
22
20
  const utils_1 = require("./utils");
21
+ const storage_1 = require("@google-cloud/storage");
22
+ const secret_manager_1 = require("@google-cloud/secret-manager");
23
23
  exports.pubSub = new pubsub_1.PubSub();
24
24
  exports.storage = new storage_1.Storage();
25
- const secretClient = new secret_manager_1.SecretManagerServiceClient();
25
+ exports.secretClient = new secret_manager_1.SecretManagerServiceClient();
26
26
  class GcfCommon {
27
27
  /**
28
28
  *
@@ -120,10 +120,10 @@ class GcfCommon {
120
120
  static getSecret(name, version) {
121
121
  var _a, _b;
122
122
  return __awaiter(this, void 0, void 0, function* () {
123
- const projectId = yield secretClient.getProjectId();
123
+ const projectId = yield exports.secretClient.getProjectId();
124
124
  const secretName = `projects/${projectId}/secrets/${name}`;
125
125
  const secretVersion = `${secretName}/versions/${version !== null && version !== void 0 ? version : 'latest'}`;
126
- const [response] = yield secretClient.accessSecretVersion({ name: secretVersion });
126
+ const [response] = yield exports.secretClient.accessSecretVersion({ name: secretVersion });
127
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
128
  });
129
129
  }
package/src/index.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import {PubSub} from "@google-cloud/pubsub";
2
- import {SecretManagerServiceClient} from "@google-cloud/secret-manager";
3
- import {File, Storage} from "@google-cloud/storage";
4
2
  import fromPairs from "lodash/fromPairs";
5
3
  import isEmpty from "lodash/isEmpty";
6
4
  import noop from "lodash/noop";
7
5
  import {timeoutAfter} from "./utils";
6
+ import {File, Storage} from "@google-cloud/storage";
7
+ import {SecretManagerServiceClient} from "@google-cloud/secret-manager";
8
8
  import Dict = NodeJS.Dict;
9
9
 
10
10
  export type TGSEvent = {
@@ -70,7 +70,7 @@ export type TResponse = {
70
70
 
71
71
  export const pubSub = new PubSub();
72
72
  export const storage = new Storage();
73
- const secretClient = new SecretManagerServiceClient();
73
+ export const secretClient = new SecretManagerServiceClient();
74
74
 
75
75
  export class GcfCommon {
76
76
 
@@ -0,0 +1,75 @@
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
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.MongoLock = void 0;
16
+ const moment_1 = __importDefault(require("moment"));
17
+ const noop_1 = __importDefault(require("lodash/noop"));
18
+ const rxjs_1 = require("rxjs");
19
+ class MongoLock {
20
+ constructor(client) {
21
+ this.client = client;
22
+ }
23
+ getCollection() {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ return this.client.db().collection('locks');
26
+ });
27
+ }
28
+ /**
29
+ * Create the MongoDB collection and an expiring index on a field named "expiresAt".
30
+ *
31
+ * db.createCollection('locks');
32
+ * db.locks.createIndex( { "expiresAt": 1 }, { expireAfterSeconds: 0 } )
33
+ **/
34
+ acquireLock(name, ttlSeconds) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const collection = yield this.getCollection();
37
+ // Entry gets removed automatically due to an expiry index in Mongo
38
+ const expiresAt = (0, moment_1.default)().add(ttlSeconds, 'seconds').toDate();
39
+ try {
40
+ yield collection.insertOne({
41
+ _id: name,
42
+ expiresAt,
43
+ });
44
+ return true;
45
+ }
46
+ catch (ex) {
47
+ // 11000 means duplicate key error, which is expected on an active lock
48
+ if ((ex === null || ex === void 0 ? void 0 : ex.code) !== 11000) {
49
+ // Unexpected error, what happened here :o
50
+ throw ex;
51
+ }
52
+ // As we got a duplicate key exception, no lock could be acquired
53
+ return false;
54
+ }
55
+ });
56
+ }
57
+ releaseLock(name) {
58
+ return __awaiter(this, void 0, void 0, function* () {
59
+ const collection = yield this.getCollection();
60
+ return collection.deleteOne({ _id: name });
61
+ });
62
+ }
63
+ acquireAndExecute(name, ttlSeconds, wait, fn) {
64
+ return __awaiter(this, void 0, void 0, function* () {
65
+ const delay = 200;
66
+ const count = Math.round((1000 / delay) * ttlSeconds);
67
+ return (0, rxjs_1.lastValueFrom)((0, rxjs_1.defer)(() => (0, rxjs_1.from)(this.acquireLock(name, ttlSeconds))).pipe((0, rxjs_1.map)(locked => {
68
+ console.log(locked);
69
+ if (!locked)
70
+ throw locked;
71
+ }), wait ? (0, rxjs_1.retry)({ count, delay }) : rxjs_1.identity, (0, rxjs_1.switchMap)(() => fn().finally(() => this.releaseLock(name).catch(noop_1.default)))));
72
+ });
73
+ }
74
+ }
75
+ exports.MongoLock = MongoLock;
@@ -0,0 +1,66 @@
1
+ import {MongoClient, MongoError} from "mongodb";
2
+ import moment from "moment";
3
+ import noop from "lodash/noop";
4
+ import {defer, from, identity, lastValueFrom, map, retry, switchMap} from "rxjs";
5
+
6
+ export class MongoLock {
7
+
8
+ constructor(private client: MongoClient) {
9
+ }
10
+
11
+ private async getCollection() {
12
+ return this.client.db().collection('locks');
13
+ }
14
+
15
+ /**
16
+ * Create the MongoDB collection and an expiring index on a field named "expiresAt".
17
+ *
18
+ * db.createCollection('locks');
19
+ * db.locks.createIndex( { "expiresAt": 1 }, { expireAfterSeconds: 0 } )
20
+ **/
21
+ async acquireLock(name: string, ttlSeconds: number) {
22
+ const collection = await this.getCollection();
23
+
24
+ // Entry gets removed automatically due to an expiry index in Mongo
25
+ const expiresAt = moment().add(ttlSeconds, 'seconds').toDate();
26
+
27
+ try {
28
+ await collection.insertOne({
29
+ _id: name as any,
30
+ expiresAt,
31
+ });
32
+
33
+ return true;
34
+ } catch (ex) {
35
+ // 11000 means duplicate key error, which is expected on an active lock
36
+ if ((ex as MongoError)?.code !== 11000) {
37
+ // Unexpected error, what happened here :o
38
+ throw ex
39
+ }
40
+
41
+ // As we got a duplicate key exception, no lock could be acquired
42
+ return false;
43
+ }
44
+ }
45
+
46
+ async releaseLock(name: string) {
47
+ const collection = await this.getCollection();
48
+ return collection.deleteOne({_id: name});
49
+ }
50
+
51
+ async acquireAndExecute(name: string, ttlSeconds: number, wait: boolean, fn: () => Promise<any>) {
52
+ const delay = 200;
53
+ const count = Math.round((1000 / delay) * ttlSeconds);
54
+
55
+ return lastValueFrom(
56
+ defer(() => from(this.acquireLock(name, ttlSeconds))).pipe(
57
+ map(locked => {
58
+ console.log(locked);
59
+ if (!locked) throw locked;
60
+ }),
61
+ wait ? retry({count, delay}) : identity,
62
+ switchMap(() => fn().finally(() => this.releaseLock(name).catch(noop))),
63
+ ),
64
+ );
65
+ }
66
+ }