gcf-common-lib 0.35.0 → 0.36.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/src/index.ts CHANGED
@@ -1,178 +1,177 @@
1
- import { PubSub } from '@google-cloud/pubsub';
2
- import { Storage } from '@google-cloud/storage';
3
- import { Options } from 'amqplib';
4
- import { Request } from 'express';
5
- import isEmpty from 'lodash/isEmpty';
6
- import mapValues from 'lodash/mapValues';
7
- import noop from 'lodash/noop';
8
- import { AmqpHelper } from './amqp-helper';
9
- import { TEvent, TGSEvent, TMetadataOrAttributes, TPayload, TPSEvent, TResponse } from './types';
10
- import { ms, safeJsonParse } from './utils';
11
- import Dict = NodeJS.Dict;
12
-
13
- export * as Storage from '@google-cloud/storage';
14
- export * as PubSub from '@google-cloud/pubsub';
15
- export * as RxJs from 'rxjs';
16
- export * as MongoDb from 'mongodb';
17
- export * from './types';
18
- export * from './utils';
19
- export * from './mongo-helper';
20
- export * from './amqp-helper';
21
-
22
- export const pubSub = new PubSub();
23
- export const storage = new Storage();
24
-
25
- export const GcfCommon = {
26
- amqpOptions: {
27
- assertExchange: { durable: true, autoDelete: false },
28
- assertOptions: { durable: true, autoDelete: true, expires: ms({ d: 1 }) },
29
- publishOptions: { persistent: true },
30
- } as {
31
- url?: string;
32
- assertExchange?: Options.AssertExchange;
33
- assertOptions?: Options.AssertQueue;
34
- publishOptions?: Options.Publish;
35
- },
36
-
37
- async process<T extends TResponse, E = TEvent>(
38
- payload: TPayload<E>,
39
- handler: (p: TPayload<E>) => Promise<any> | any,
40
- // timeoutSec = 535,
41
- ) {
42
- const asyncHandler = async (p: TPayload<E>) => await handler(p);
43
-
44
- // return firstValueFrom(
45
- // defer(() => from(asyncHandler({ ...payload }))).pipe(first(), timeout({ first: ms({ s: timeoutSec }) })),
46
- // )
47
-
48
- return asyncHandler({ ...payload })
49
- .then(async res => {
50
- // console.log('res:', res);
51
- await GcfCommon.response({ ...payload }, res as T).catch(noop);
52
- return res;
53
- })
54
- .catch(async (error: Error) => {
55
- await GcfCommon.response({ ...payload }, GcfCommon.buildResponse(error), { error: '1' }).catch(noop);
56
- throw error;
57
- });
58
- },
59
-
60
- buildResponse(error: Error) {
61
- return {
62
- error: {
63
- name: error.name,
64
- message: `GCF [${process?.env?.K_SERVICE ?? 'UNKNOWN'}]: ${error.message}`,
65
- stack: error.stack,
66
- },
67
- } as TResponse;
68
- },
69
-
70
- async response<E = TEvent>(payload: TPayload<E>, json?: TResponse, attributes?: Dict<any>) {
71
- // console.time('safeGetAttributes');
72
- // const { topic, exchange, queue, consumer_id, request_id, app_id, env } = await GcfCommon.safeGetAttributes(
73
- // event,
74
- // context,
75
- // ['consumer_id', 'topic', 'exchange', 'queue'],
76
- // );
77
- // console.timeEnd('safeGetAttributes');
78
-
79
- const { topic, exchange, queue, consumer_id, request_id, app_id, env } = GcfCommon.getMetadataOrAttribute(payload);
80
-
81
- //
82
-
83
- console.time('publish');
84
-
85
- if (topic && !isEmpty(topic)) {
86
- console.log('send:', topic, app_id, env, json, attributes);
87
- await pubSub.topic(topic).publishMessage({
88
- json: json ?? {},
89
- attributes: {
90
- ...mapValues(attributes ?? {}, v => '' + v),
91
- consumer_id: consumer_id ?? '',
92
- request_id: request_id ?? '',
93
- app_id: app_id ?? '',
94
- env: env ?? '',
95
- } as TMetadataOrAttributes,
96
- });
97
- }
98
-
99
- if (exchange && !isEmpty(exchange)) {
100
- console.log('send:', exchange, queue, app_id, env, json, attributes);
101
- await AmqpHelper.withAmqpCh(async ch => {
102
- await ch.assertExchange(exchange, 'direct', GcfCommon.amqpOptions.assertExchange);
103
- await AmqpHelper.publishAmqp(ch, exchange, queue ?? '', json ?? {}, {
104
- ...GcfCommon.amqpOptions.publishOptions,
105
- correlationId: request_id,
106
- });
107
- }, GcfCommon.amqpOptions.url as string);
108
- } else if (queue && !isEmpty(queue)) {
109
- console.log('send:', queue, app_id, env, json, attributes);
110
- await AmqpHelper.withAmqpCh(async ch => {
111
- // await ch.assertQueue(queue, GcfCommon.amqpOptions.assertOptions);
112
- await AmqpHelper.publishAmqp(ch, undefined, queue, json ?? {}, {
113
- ...GcfCommon.amqpOptions.publishOptions,
114
- correlationId: request_id,
115
- });
116
- }, GcfCommon.amqpOptions.url as string);
117
- }
118
-
119
- console.timeEnd('publish');
120
- },
121
-
122
- // async safeGetAttributes<E = TEvent>(event: E, context: TContext, props: string[]) {
123
- // let metaOrAttr = GcfCommon.getMetadataOrAttribute(event, context);
124
- // // const everyPropIsNil = props.map(prop => get(metaOrAttr, prop)).every(v => isNil(v));
125
- //
126
- // const someProp = props.map(prop => get(metaOrAttr, prop)).some(v => !isNil(v));
127
- // // if no prop then check file metadata
128
- // if (!someProp && context?.resource?.type === 'storage#object') {
129
- // console.log('get metadata from file');
130
- // if (context?.eventType === 'google.storage.object.finalize') {
131
- // const gsEvent = event as TGSEvent;
132
- // const [meta] = await new Storage().bucket(gsEvent.bucket).file(gsEvent.name).getMetadata();
133
- // metaOrAttr = meta?.metadata ?? {};
134
- // }
135
- // }
136
- //
137
- // return {
138
- // ...metaOrAttr,
139
- // app_id: metaOrAttr.app_id,
140
- // request_id: metaOrAttr.request_id,
141
- // } as TMetadataOrAttributes;
142
- // },
143
-
144
- async getOptions(payload: TPayload): Promise<Dict<any>> {
145
- // const { options } = await GcfCommon.safeGetAttributes(event, context, ['options']);
146
- const { options } = GcfCommon.getMetadataOrAttribute(payload);
147
- return safeJsonParse(options as any, {} as any);
148
- },
149
-
150
- getMetadataOrAttribute<E = TEvent>(payload: TPayload<E>) {
151
- let metadataOrAttribute: TMetadataOrAttributes | undefined;
152
-
153
- if (payload?.context) {
154
- switch (payload?.context?.eventType) {
155
- case 'google.storage.object.finalize': {
156
- const gsEvent = payload?.event as TGSEvent;
157
- metadataOrAttribute = gsEvent?.metadata;
158
- break;
159
- }
160
- case 'google.pubsub.topic.publish': {
161
- const psEvent = payload?.event as TPSEvent;
162
- metadataOrAttribute = psEvent?.attributes;
163
- break;
164
- }
165
- }
166
- } else if (payload?.request) {
167
- metadataOrAttribute = GcfCommon.getRequestMessage(payload.request)?.attributes;
168
- }
169
-
170
- // console.log('metadataOrAttribute:', metadataOrAttribute);
171
-
172
- return metadataOrAttribute ?? {};
173
- },
174
-
175
- getRequestMessage(request: Request) {
176
- return request.body.message as { attributes: TMetadataOrAttributes; data: string; json?: Dict<any> };
177
- },
178
- };
1
+ import { PubSub } from '@google-cloud/pubsub';
2
+ import { Storage } from '@google-cloud/storage';
3
+ import { Request } from 'express';
4
+ import isEmpty from 'lodash/isEmpty';
5
+ import mapValues from 'lodash/mapValues';
6
+ import noop from 'lodash/noop';
7
+ // import { AmqpHelper } from './amqp-helper.ts';
8
+ import { TEvent, TGSEvent, TMetadataOrAttributes, TPayload, TPSEvent, TResponse } from './types';
9
+ import { ms, safeJsonParse } from './utils';
10
+ import Dict = NodeJS.Dict;
11
+
12
+ export * as Storage from '@google-cloud/storage';
13
+ export * as PubSub from '@google-cloud/pubsub';
14
+ export * as RxJs from 'rxjs';
15
+ export * as MongoDb from 'mongodb';
16
+ export * from './types';
17
+ export * from './utils';
18
+ export * from './mongo-helper';
19
+ // export * from './amqp-helper.ts';
20
+
21
+ export const pubSub = new PubSub();
22
+ export const storage = new Storage();
23
+
24
+ export const GcfCommon = {
25
+ // amqpOptions: {
26
+ // assertExchange: { durable: true, autoDelete: false },
27
+ // assertOptions: { durable: true, autoDelete: true, expires: ms({ d: 1 }) },
28
+ // publishOptions: { persistent: true },
29
+ // } as {
30
+ // url?: string;
31
+ // assertExchange?: Options.AssertExchange;
32
+ // assertOptions?: Options.AssertQueue;
33
+ // publishOptions?: Options.Publish;
34
+ // },
35
+
36
+ async process<T extends TResponse, E = TEvent>(
37
+ payload: TPayload<E>,
38
+ handler: (p: TPayload<E>) => Promise<any> | any,
39
+ // timeoutSec = 535,
40
+ ) {
41
+ const asyncHandler = async (p: TPayload<E>) => await handler(p);
42
+
43
+ // return firstValueFrom(
44
+ // defer(() => from(asyncHandler({ ...payload }))).pipe(first(), timeout({ first: ms({ s: timeoutSec }) })),
45
+ // )
46
+
47
+ return asyncHandler({ ...payload })
48
+ .then(async res => {
49
+ // console.log('res:', res);
50
+ await GcfCommon.response({ ...payload }, res as T).catch(noop);
51
+ return res;
52
+ })
53
+ .catch(async (error: Error) => {
54
+ await GcfCommon.response({ ...payload }, GcfCommon.buildResponse(error), { error: '1' }).catch(noop);
55
+ throw error;
56
+ });
57
+ },
58
+
59
+ buildResponse(error: Error) {
60
+ return {
61
+ error: {
62
+ name: error.name,
63
+ message: `GCF [${process?.env?.K_SERVICE ?? 'UNKNOWN'}]: ${error.message}`,
64
+ stack: error.stack,
65
+ },
66
+ } as TResponse;
67
+ },
68
+
69
+ async response<E = TEvent>(payload: TPayload<E>, json?: TResponse, attributes?: Dict<any>) {
70
+ // console.time('safeGetAttributes');
71
+ // const { topic, exchange, queue, consumer_id, request_id, app_id, env } = await GcfCommon.safeGetAttributes(
72
+ // event,
73
+ // context,
74
+ // ['consumer_id', 'topic', 'exchange', 'queue'],
75
+ // );
76
+ // console.timeEnd('safeGetAttributes');
77
+
78
+ const { topic, exchange, queue, consumer_id, request_id, app_id, env } = GcfCommon.getMetadataOrAttribute(payload);
79
+
80
+ //
81
+
82
+ console.time('publish');
83
+
84
+ if (topic && !isEmpty(topic)) {
85
+ console.log('send:', topic, app_id, env, json, attributes);
86
+ await pubSub.topic(topic).publishMessage({
87
+ json: json ?? {},
88
+ attributes: {
89
+ ...mapValues(attributes ?? {}, v => '' + v),
90
+ consumer_id: consumer_id ?? '',
91
+ request_id: request_id ?? '',
92
+ app_id: app_id ?? '',
93
+ env: env ?? '',
94
+ } as TMetadataOrAttributes,
95
+ });
96
+ }
97
+
98
+ // if (exchange && !isEmpty(exchange)) {
99
+ // console.log('send:', exchange, queue, app_id, env, json, attributes);
100
+ // await AmqpHelper.withAmqpCh(async ch => {
101
+ // await ch.assertExchange(exchange, 'direct', GcfCommon.amqpOptions.assertExchange);
102
+ // await AmqpHelper.publishAmqp(ch, exchange, queue ?? '', json ?? {}, {
103
+ // ...GcfCommon.amqpOptions.publishOptions,
104
+ // correlationId: request_id,
105
+ // });
106
+ // }, GcfCommon.amqpOptions.url as string);
107
+ // } else if (queue && !isEmpty(queue)) {
108
+ // console.log('send:', queue, app_id, env, json, attributes);
109
+ // await AmqpHelper.withAmqpCh(async ch => {
110
+ // // await ch.assertQueue(queue, GcfCommon.amqpOptions.assertOptions);
111
+ // await AmqpHelper.publishAmqp(ch, undefined, queue, json ?? {}, {
112
+ // ...GcfCommon.amqpOptions.publishOptions,
113
+ // correlationId: request_id,
114
+ // });
115
+ // }, GcfCommon.amqpOptions.url as string);
116
+ // }
117
+
118
+ console.timeEnd('publish');
119
+ },
120
+
121
+ // async safeGetAttributes<E = TEvent>(event: E, context: TContext, props: string[]) {
122
+ // let metaOrAttr = GcfCommon.getMetadataOrAttribute(event, context);
123
+ // // const everyPropIsNil = props.map(prop => get(metaOrAttr, prop)).every(v => isNil(v));
124
+ //
125
+ // const someProp = props.map(prop => get(metaOrAttr, prop)).some(v => !isNil(v));
126
+ // // if no prop then check file metadata
127
+ // if (!someProp && context?.resource?.type === 'storage#object') {
128
+ // console.log('get metadata from file');
129
+ // if (context?.eventType === 'google.storage.object.finalize') {
130
+ // const gsEvent = event as TGSEvent;
131
+ // const [meta] = await new Storage().bucket(gsEvent.bucket).file(gsEvent.name).getMetadata();
132
+ // metaOrAttr = meta?.metadata ?? {};
133
+ // }
134
+ // }
135
+ //
136
+ // return {
137
+ // ...metaOrAttr,
138
+ // app_id: metaOrAttr.app_id,
139
+ // request_id: metaOrAttr.request_id,
140
+ // } as TMetadataOrAttributes;
141
+ // },
142
+
143
+ async getOptions(payload: TPayload): Promise<Dict<any>> {
144
+ // const { options } = await GcfCommon.safeGetAttributes(event, context, ['options']);
145
+ const { options } = GcfCommon.getMetadataOrAttribute(payload);
146
+ return safeJsonParse(options as any, {} as any);
147
+ },
148
+
149
+ getMetadataOrAttribute<E = TEvent>(payload: TPayload<E>) {
150
+ let metadataOrAttribute: TMetadataOrAttributes | undefined;
151
+
152
+ if (payload?.context) {
153
+ switch (payload?.context?.eventType) {
154
+ case 'google.storage.object.finalize': {
155
+ const gsEvent = payload?.event as TGSEvent;
156
+ metadataOrAttribute = gsEvent?.metadata;
157
+ break;
158
+ }
159
+ case 'google.pubsub.topic.publish': {
160
+ const psEvent = payload?.event as TPSEvent;
161
+ metadataOrAttribute = psEvent?.attributes;
162
+ break;
163
+ }
164
+ }
165
+ } else if (payload?.request) {
166
+ metadataOrAttribute = GcfCommon.getRequestMessage(payload.request)?.attributes;
167
+ }
168
+
169
+ // console.log('metadataOrAttribute:', metadataOrAttribute);
170
+
171
+ return metadataOrAttribute ?? {};
172
+ },
173
+
174
+ getRequestMessage(request: Request) {
175
+ return request.body.message as { attributes: TMetadataOrAttributes; data: string; json?: Dict<any> };
176
+ },
177
+ };
@@ -1,42 +1,42 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.MongoHelper = void 0;
7
- const mongodb_1 = require("mongodb");
8
- const bluebird_1 = __importDefault(require("bluebird"));
9
- let mongoClient;
10
- exports.MongoHelper = {
11
- async collectionExists(client, name) {
12
- const db = client.db();
13
- const collections = await db.listCollections({ name }, { nameOnly: true }).toArray();
14
- return collections.length > 0;
15
- },
16
- async collectionSafeGet(client, name, options, afterCreate) {
17
- const db = client.db();
18
- let coll;
19
- if (await this.collectionExists(client, name)) {
20
- coll = db.collection(name);
21
- }
22
- else {
23
- coll = await db.createCollection(name, options);
24
- afterCreate && (await afterCreate(coll));
25
- }
26
- return coll;
27
- },
28
- async withMongoClient(fn, url, mongoClientOptions) {
29
- function withDisposer() {
30
- return bluebird_1.default.method(async () => {
31
- if (!mongoClient) {
32
- mongoClient = new mongodb_1.MongoClient(url, mongoClientOptions);
33
- await mongoClient.connect();
34
- }
35
- return mongoClient;
36
- })().disposer((client, promise) => {
37
- // client.close();
38
- });
39
- }
40
- return bluebird_1.default.using(withDisposer(), client => fn(client));
41
- },
42
- };
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MongoHelper = void 0;
7
+ const mongodb_1 = require("mongodb");
8
+ const bluebird_1 = __importDefault(require("bluebird"));
9
+ let mongoClient;
10
+ exports.MongoHelper = {
11
+ async collectionExists(client, name) {
12
+ const db = client.db();
13
+ const collections = await db.listCollections({ name }, { nameOnly: true }).toArray();
14
+ return collections.length > 0;
15
+ },
16
+ async collectionSafeGet(client, name, options, afterCreate) {
17
+ const db = client.db();
18
+ let coll;
19
+ if (await this.collectionExists(client, name)) {
20
+ coll = db.collection(name);
21
+ }
22
+ else {
23
+ coll = await db.createCollection(name, options);
24
+ afterCreate && (await afterCreate(coll));
25
+ }
26
+ return coll;
27
+ },
28
+ async withMongoClient(fn, url, mongoClientOptions) {
29
+ function withDisposer() {
30
+ return bluebird_1.default.method(async () => {
31
+ if (!mongoClient) {
32
+ mongoClient = new mongodb_1.MongoClient(url, mongoClientOptions);
33
+ await mongoClient.connect();
34
+ }
35
+ return mongoClient;
36
+ })().disposer((client, promise) => {
37
+ // client.close();
38
+ });
39
+ }
40
+ return bluebird_1.default.using(withDisposer(), client => fn(client));
41
+ },
42
+ };
@@ -1,51 +1,51 @@
1
- import { Collection, CreateCollectionOptions, MongoClient, MongoClientOptions } from 'mongodb';
2
- import { Document } from 'bson';
3
- import Bluebird from 'bluebird';
4
- let mongoClient: MongoClient;
5
-
6
- export const MongoHelper = {
7
- async collectionExists(client: MongoClient, name: string) {
8
- const db = client.db();
9
- const collections = await db.listCollections({ name }, { nameOnly: true }).toArray();
10
- return collections.length > 0;
11
- },
12
-
13
- async collectionSafeGet<TSchema extends Document = Document>(
14
- client: MongoClient,
15
- name: string,
16
- options?: CreateCollectionOptions,
17
- afterCreate?: (col: Collection<TSchema>) => Promise<void>,
18
- ) {
19
- const db = client.db();
20
- let coll: Collection<TSchema>;
21
-
22
- if (await this.collectionExists(client, name)) {
23
- coll = db.collection<TSchema>(name);
24
- } else {
25
- coll = await db.createCollection<TSchema>(name, options);
26
- afterCreate && (await afterCreate(coll));
27
- }
28
-
29
- return coll;
30
- },
31
-
32
- async withMongoClient<T = any>(
33
- fn: (mongoClient: MongoClient) => Promise<T>,
34
- url: string,
35
- mongoClientOptions?: MongoClientOptions,
36
- ) {
37
- function withDisposer() {
38
- return Bluebird.method(async () => {
39
- if (!mongoClient) {
40
- mongoClient = new MongoClient(url, mongoClientOptions);
41
- await mongoClient.connect();
42
- }
43
- return mongoClient;
44
- })().disposer((client, promise) => {
45
- // client.close();
46
- });
47
- }
48
-
49
- return Bluebird.using(withDisposer(), client => fn(client));
50
- },
51
- };
1
+ import { Collection, CreateCollectionOptions, MongoClient, MongoClientOptions } from 'mongodb';
2
+ import { Document } from 'bson';
3
+ import Bluebird from 'bluebird';
4
+ let mongoClient: MongoClient;
5
+
6
+ export const MongoHelper = {
7
+ async collectionExists(client: MongoClient, name: string) {
8
+ const db = client.db();
9
+ const collections = await db.listCollections({ name }, { nameOnly: true }).toArray();
10
+ return collections.length > 0;
11
+ },
12
+
13
+ async collectionSafeGet<TSchema extends Document = Document>(
14
+ client: MongoClient,
15
+ name: string,
16
+ options?: CreateCollectionOptions,
17
+ afterCreate?: (col: Collection<TSchema>) => Promise<void>,
18
+ ) {
19
+ const db = client.db();
20
+ let coll: Collection<TSchema>;
21
+
22
+ if (await this.collectionExists(client, name)) {
23
+ coll = db.collection<TSchema>(name);
24
+ } else {
25
+ coll = await db.createCollection<TSchema>(name, options);
26
+ afterCreate && (await afterCreate(coll));
27
+ }
28
+
29
+ return coll;
30
+ },
31
+
32
+ async withMongoClient<T = any>(
33
+ fn: (mongoClient: MongoClient) => Promise<T>,
34
+ url: string,
35
+ mongoClientOptions?: MongoClientOptions,
36
+ ) {
37
+ function withDisposer() {
38
+ return Bluebird.method(async () => {
39
+ if (!mongoClient) {
40
+ mongoClient = new MongoClient(url, mongoClientOptions);
41
+ await mongoClient.connect();
42
+ }
43
+ return mongoClient;
44
+ })().disposer((client, promise) => {
45
+ // client.close();
46
+ });
47
+ }
48
+
49
+ return Bluebird.using(withDisposer(), client => fn(client));
50
+ },
51
+ };