@eyevinn/player-analytics-shared 0.5.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/.github/workflows/build-test.yml +19 -0
- package/.github/workflows/release-gh-package.yml +24 -0
- package/.github/workflows/release-npmjs-package.yml +21 -0
- package/README.md +2 -0
- package/adapters/db/DynamoDBAdapter.ts +147 -0
- package/adapters/db/MongoDBAdapter.ts +79 -0
- package/adapters/queue/BeanstalkdAdapter.ts +41 -0
- package/adapters/queue/RedisAdapter.ts +34 -0
- package/adapters/queue/SqsQueueAdapter.ts +127 -0
- package/build/adapters/db/DynamoDBAdapter.d.ts +14 -0
- package/build/adapters/db/DynamoDBAdapter.js +138 -0
- package/build/adapters/db/DynamoDBAdapter.js.map +1 -0
- package/build/adapters/db/MongoDBAdapter.d.ts +16 -0
- package/build/adapters/db/MongoDBAdapter.js +98 -0
- package/build/adapters/db/MongoDBAdapter.js.map +1 -0
- package/build/adapters/queue/BeanstalkdAdapter.d.ts +13 -0
- package/build/adapters/queue/BeanstalkdAdapter.js +55 -0
- package/build/adapters/queue/BeanstalkdAdapter.js.map +1 -0
- package/build/adapters/queue/RedisAdapter.d.ts +12 -0
- package/build/adapters/queue/RedisAdapter.js +44 -0
- package/build/adapters/queue/RedisAdapter.js.map +1 -0
- package/build/adapters/queue/SqsQueueAdapter.d.ts +12 -0
- package/build/adapters/queue/SqsQueueAdapter.js +122 -0
- package/build/adapters/queue/SqsQueueAdapter.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.js +19 -0
- package/build/index.js.map +1 -0
- package/build/types/db.d.ts +32 -0
- package/build/types/db.js +12 -0
- package/build/types/db.js.map +1 -0
- package/build/types/interfaces.d.ts +2 -0
- package/build/types/interfaces.js +15 -0
- package/build/types/interfaces.js.map +1 -0
- package/build/types/queue.d.ts +15 -0
- package/build/types/queue.js +7 -0
- package/build/types/queue.js.map +1 -0
- package/build/util/constants.d.ts +1 -0
- package/build/util/constants.js +5 -0
- package/build/util/constants.js.map +1 -0
- package/build/util/logger.d.ts +3 -0
- package/build/util/logger.js +37 -0
- package/build/util/logger.js.map +1 -0
- package/index.ts +8 -0
- package/package.json +43 -0
- package/spec/adapters/DynamoDBAdapter.spec.ts +275 -0
- package/spec/adapters/MongoDBAdapter.spec.ts +170 -0
- package/spec/adapters/SqsQueueAdapter.spec.ts +149 -0
- package/spec/support/jasmine.json +11 -0
- package/tsconfig-build.json +6 -0
- package/tsconfig.json +21 -0
- package/tslint.json +9 -0
- package/types/db.ts +39 -0
- package/types/interfaces.ts +2 -0
- package/types/queue.ts +17 -0
- package/util/constants.ts +1 -0
- package/util/logger.ts +45 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Run tests
|
|
2
|
+
on: push
|
|
3
|
+
jobs:
|
|
4
|
+
test:
|
|
5
|
+
runs-on: ubuntu-latest
|
|
6
|
+
strategy:
|
|
7
|
+
matrix:
|
|
8
|
+
node-version: [14.x]
|
|
9
|
+
steps:
|
|
10
|
+
- uses: actions/checkout@v1
|
|
11
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
12
|
+
uses: actions/setup-node@v1
|
|
13
|
+
with:
|
|
14
|
+
node-version: ${{ matrix.node-version }}
|
|
15
|
+
- name: Install dependencies and run tests
|
|
16
|
+
run: |
|
|
17
|
+
npm ci
|
|
18
|
+
npm install
|
|
19
|
+
npm test
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
name: Publish GitHub Package
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
jobs:
|
|
7
|
+
publish-gpr:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
permissions:
|
|
10
|
+
packages: write
|
|
11
|
+
contents: read
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v2
|
|
14
|
+
- uses: actions/setup-node@v2
|
|
15
|
+
with:
|
|
16
|
+
node-version: 14.x
|
|
17
|
+
registry-url: https://npm.pkg.github.com/
|
|
18
|
+
- run: npm ci
|
|
19
|
+
- run: npm install
|
|
20
|
+
- run: npm test
|
|
21
|
+
- run: npm run build --if-present
|
|
22
|
+
- run: npm publish
|
|
23
|
+
env:
|
|
24
|
+
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
name: Publish Package on NPM
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
jobs:
|
|
7
|
+
publish-npmjs:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
steps:
|
|
10
|
+
- uses: actions/checkout@v2
|
|
11
|
+
- uses: actions/setup-node@v2
|
|
12
|
+
with:
|
|
13
|
+
node-version: 14.x
|
|
14
|
+
registry-url: https://registry.npmjs.org/
|
|
15
|
+
- run: npm ci
|
|
16
|
+
- run: npm install
|
|
17
|
+
- run: npm test
|
|
18
|
+
- run: npm run build --if-present
|
|
19
|
+
- run: npm publish --access public
|
|
20
|
+
env:
|
|
21
|
+
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
package/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CreateTableCommand,
|
|
3
|
+
ListTablesCommand,
|
|
4
|
+
PutItemCommand,
|
|
5
|
+
DynamoDBClient,
|
|
6
|
+
GetItemCommand,
|
|
7
|
+
DeleteItemCommand,
|
|
8
|
+
QueryCommand,
|
|
9
|
+
QueryCommandInput,
|
|
10
|
+
QueryCommandOutput,
|
|
11
|
+
DescribeTableCommand,
|
|
12
|
+
DescribeTableCommandInput
|
|
13
|
+
} from '@aws-sdk/client-dynamodb';
|
|
14
|
+
import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';
|
|
15
|
+
import winston from 'winston';
|
|
16
|
+
import {
|
|
17
|
+
AbstractDBAdapter,
|
|
18
|
+
IGetItemInput,
|
|
19
|
+
IGetItems,
|
|
20
|
+
IPutItemInput,
|
|
21
|
+
IHandleErrorOutput,
|
|
22
|
+
ErrorType,
|
|
23
|
+
} from '../../types/interfaces';
|
|
24
|
+
|
|
25
|
+
export class DynamoDBAdapter implements AbstractDBAdapter {
|
|
26
|
+
logger: winston.Logger;
|
|
27
|
+
dbClient: DynamoDBClient;
|
|
28
|
+
|
|
29
|
+
constructor(logger: winston.Logger) {
|
|
30
|
+
this.dbClient = new DynamoDBClient({
|
|
31
|
+
region: process.env.AWS_REGION,
|
|
32
|
+
maxAttempts: 5,
|
|
33
|
+
});
|
|
34
|
+
this.logger = logger;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async tableExists(name: string): Promise<boolean> {
|
|
38
|
+
try {
|
|
39
|
+
const params: DescribeTableCommandInput = { TableName: name };
|
|
40
|
+
const tablesData = await this.dbClient.send(new DescribeTableCommand(params));
|
|
41
|
+
if (tablesData['Table'] && tablesData['Table'].TableStatus === 'ACTIVE') return true;
|
|
42
|
+
return false;
|
|
43
|
+
} catch (awsError) {
|
|
44
|
+
if (awsError.name && awsError.name === 'ResourceNotFoundException') {
|
|
45
|
+
return false;
|
|
46
|
+
} else {
|
|
47
|
+
this.logger.error(awsError);
|
|
48
|
+
throw new Error(awsError);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async putItem(params: IPutItemInput): Promise<boolean> {
|
|
54
|
+
try {
|
|
55
|
+
const data = await this.dbClient.send(
|
|
56
|
+
new PutItemCommand({
|
|
57
|
+
TableName: params.tableName,
|
|
58
|
+
Item: marshall(params.data),
|
|
59
|
+
})
|
|
60
|
+
);
|
|
61
|
+
return data.$metadata.httpStatusCode === 200;
|
|
62
|
+
} catch (err) {
|
|
63
|
+
throw this.handleError(err);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async getItem(params: IGetItemInput): Promise<any> {
|
|
68
|
+
try {
|
|
69
|
+
const data = await this.dbClient.send(
|
|
70
|
+
new GetItemCommand({
|
|
71
|
+
TableName: params.tableName,
|
|
72
|
+
Key: marshall({
|
|
73
|
+
sessionId: params.sessionId,
|
|
74
|
+
timestamp: params.timestamp,
|
|
75
|
+
}),
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
this.logger.debug('Read Item from Table');
|
|
79
|
+
return data;
|
|
80
|
+
} catch (err) {
|
|
81
|
+
throw this.handleError(err);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async deleteItem(params: IGetItemInput): Promise<boolean> {
|
|
86
|
+
try {
|
|
87
|
+
const data = await this.dbClient.send(
|
|
88
|
+
new DeleteItemCommand({
|
|
89
|
+
TableName: params.tableName,
|
|
90
|
+
Key: marshall({
|
|
91
|
+
sessionId: params.sessionId,
|
|
92
|
+
timestamp: params.timestamp,
|
|
93
|
+
}),
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
this.logger.debug('Deleted Item from Table', data);
|
|
97
|
+
return data.$metadata.httpStatusCode === 200;
|
|
98
|
+
} catch (err) {
|
|
99
|
+
throw this.handleError(err);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async getItemsBySession(params: IGetItems): Promise<any[]> {
|
|
104
|
+
try {
|
|
105
|
+
const inputData: QueryCommandInput = {
|
|
106
|
+
TableName: params.tableName,
|
|
107
|
+
KeyConditionExpression: '#sid = :sid',
|
|
108
|
+
ExpressionAttributeNames: {
|
|
109
|
+
'#sid': 'sessionId',
|
|
110
|
+
},
|
|
111
|
+
ExpressionAttributeValues: marshall({
|
|
112
|
+
':sid': params.sessionId,
|
|
113
|
+
}),
|
|
114
|
+
};
|
|
115
|
+
const queryData: QueryCommandOutput = await this.dbClient.send(
|
|
116
|
+
new QueryCommand(inputData)
|
|
117
|
+
);
|
|
118
|
+
if (queryData.Items && queryData.Items.length > 0) {
|
|
119
|
+
let items: any[] = [];
|
|
120
|
+
for (let i = 0; i < queryData.Items.length; i++) {
|
|
121
|
+
items[i] = unmarshall(queryData.Items[i]);
|
|
122
|
+
}
|
|
123
|
+
return items;
|
|
124
|
+
}
|
|
125
|
+
return [];
|
|
126
|
+
} catch (err) {
|
|
127
|
+
throw this.handleError(err);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
handleError(errorObject: any): IHandleErrorOutput {
|
|
132
|
+
this.logger.error(errorObject);
|
|
133
|
+
const errorOutput: IHandleErrorOutput = {
|
|
134
|
+
errorType: ErrorType.ABORT,
|
|
135
|
+
error: errorObject,
|
|
136
|
+
};
|
|
137
|
+
if (errorObject.name) {
|
|
138
|
+
if (
|
|
139
|
+
errorObject.name === 'ResourceNotFoundException' ||
|
|
140
|
+
errorObject.name === 'ResourceInUseException'
|
|
141
|
+
) {
|
|
142
|
+
errorOutput['errorType'] = ErrorType.CONTINUE;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return errorOutput;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Logger } from "winston";
|
|
2
|
+
import { AbstractDBAdapter, IHandleErrorOutput, ErrorType, IPutItemInput, IGetItemInput, IGetItems } from "../../types/interfaces";
|
|
3
|
+
import { MongoClient } from "mongodb";
|
|
4
|
+
|
|
5
|
+
const DB_NAME = "EPAS";
|
|
6
|
+
|
|
7
|
+
export class MongoDBAdapter implements AbstractDBAdapter {
|
|
8
|
+
logger: Logger;
|
|
9
|
+
dbClient: MongoClient;
|
|
10
|
+
|
|
11
|
+
constructor(logger: Logger) {
|
|
12
|
+
const connectionString = process.env.MONGODB_URI || "mongodb://localhost";
|
|
13
|
+
this.dbClient = new MongoClient(connectionString);
|
|
14
|
+
this.connect()
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private async isConnected(): Promise<boolean> {
|
|
19
|
+
return !!await this.dbClient.db("admin").command({ ping: 1 });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private async connect(): Promise<void> {
|
|
23
|
+
await this.dbClient.connect();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public async tableExists(tableName: string): Promise<boolean> {
|
|
27
|
+
if (!await this.isConnected()) await this.connect();
|
|
28
|
+
const collections = await this.dbClient.db().collections();
|
|
29
|
+
const tableNames = collections.map((collection) => collection.collectionName);
|
|
30
|
+
return tableNames.includes(tableName);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public async putItem({ tableName, data }: IPutItemInput): Promise<boolean> {
|
|
34
|
+
try {
|
|
35
|
+
const collection = await this.dbClient.db().collection(tableName);
|
|
36
|
+
const result = await collection.insertOne(data);
|
|
37
|
+
return result.acknowledged;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw this.handleError(error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public async getItem({ sessionId, tableName, timestamp }: IGetItemInput): Promise<any> {
|
|
44
|
+
try {
|
|
45
|
+
const collection = await this.dbClient.db().collection(tableName);
|
|
46
|
+
const result = await collection.findOne({ sessionId: sessionId, timestamp: timestamp });
|
|
47
|
+
return result;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
throw this.handleError(error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public async deleteItem({ sessionId, tableName, timestamp }: IGetItemInput): Promise<boolean> {
|
|
54
|
+
try {
|
|
55
|
+
const collection = await this.dbClient.db().collection(tableName);
|
|
56
|
+
const result = await collection.deleteOne({ sessionId: sessionId, timestamp: timestamp });
|
|
57
|
+
return result.acknowledged;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw this.handleError(error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
public async getItemsBySession({ tableName, sessionId }: IGetItems): Promise<any[]> {
|
|
63
|
+
try {
|
|
64
|
+
const collection = await this.dbClient.db().collection(tableName);
|
|
65
|
+
return await collection.find({ sessionId: sessionId }).toArray();
|
|
66
|
+
} catch (error) {
|
|
67
|
+
throw this.handleError(error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public handleError(error: any): IHandleErrorOutput {
|
|
72
|
+
this.logger.error(error);
|
|
73
|
+
return {
|
|
74
|
+
errorType: ErrorType.ABORT,
|
|
75
|
+
error: error,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Client } from "node-beanstalk";
|
|
2
|
+
import winston from "winston";
|
|
3
|
+
import { AbstractQueueAdapter } from "../../types/interfaces";
|
|
4
|
+
|
|
5
|
+
export class BeanstalkdAdapter implements AbstractQueueAdapter {
|
|
6
|
+
logger: winston.Logger;
|
|
7
|
+
client: Client;
|
|
8
|
+
|
|
9
|
+
constructor(logger: winston.Logger) {
|
|
10
|
+
this.logger = logger;
|
|
11
|
+
this.client = new Client();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
private async connect(): Promise<void> {
|
|
15
|
+
await this.client.connect();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async pushToQueue(body: Object): Promise<Object> {
|
|
19
|
+
if (!this.client.isConnected) await this.connect();
|
|
20
|
+
const result = await this.client.put(body);
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async pullFromQueue(): Promise<Object> {
|
|
25
|
+
if (!this.client.isConnected) await this.connect();
|
|
26
|
+
const job = await this.client.reserveWithTimeout(1);
|
|
27
|
+
return job || {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async removeFromQueue(body: Record<string, any>): Promise<boolean> {
|
|
31
|
+
if (!this.client.isConnected) await this.connect();
|
|
32
|
+
const jobId = body.id;
|
|
33
|
+
const result = await this.client.delete(jobId);
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getEventJSONsFromMessages(body: any[]): Object[] {
|
|
38
|
+
this.logger.warn("Method not implemented.");
|
|
39
|
+
return body;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import RedisTaskQueue = require("redis-task-queue");
|
|
2
|
+
import winston from "winston";
|
|
3
|
+
import { AbstractQueueAdapter } from "../../types/interfaces";
|
|
4
|
+
|
|
5
|
+
export class RedisAdapter implements AbstractQueueAdapter {
|
|
6
|
+
logger: winston.Logger;
|
|
7
|
+
client: RedisTaskQueue;
|
|
8
|
+
|
|
9
|
+
constructor(logger: winston.Logger) {
|
|
10
|
+
this.logger = logger;
|
|
11
|
+
this.client = new RedisTaskQueue();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async pushToQueue(body: Object): Promise<Object> {
|
|
15
|
+
const result = await this.client.add({ data: body });
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async pullFromQueue(): Promise<Object> {
|
|
20
|
+
const job = await this.client.get();
|
|
21
|
+
return job || {};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async removeFromQueue(body: Record<string, any>): Promise<boolean> {
|
|
25
|
+
const jobId = body.id;
|
|
26
|
+
const result = await this.client.getStatus(jobId);
|
|
27
|
+
return result === 'completed';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getEventJSONsFromMessages(body: any[]): Object[] {
|
|
31
|
+
this.logger.warn("Method not implemented.");
|
|
32
|
+
return body;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SQSClient,
|
|
3
|
+
SendMessageCommand,
|
|
4
|
+
SendMessageCommandInput,
|
|
5
|
+
ReceiveMessageCommandInput,
|
|
6
|
+
ReceiveMessageCommand,
|
|
7
|
+
DeleteMessageCommandInput,
|
|
8
|
+
Message,
|
|
9
|
+
DeleteMessageCommand,
|
|
10
|
+
} from '@aws-sdk/client-sqs';
|
|
11
|
+
import { AbstractQueueAdapter } from '../../types/interfaces';
|
|
12
|
+
import winston from 'winston';
|
|
13
|
+
|
|
14
|
+
export class SqsQueueAdapter implements AbstractQueueAdapter {
|
|
15
|
+
logger: winston.Logger;
|
|
16
|
+
client: SQSClient;
|
|
17
|
+
|
|
18
|
+
constructor(logger: winston.Logger) {
|
|
19
|
+
this.logger = logger;
|
|
20
|
+
let region: any;
|
|
21
|
+
if ('QUEUE_REGION' in process.env) {
|
|
22
|
+
region = process.env.QUEUE_REGION;
|
|
23
|
+
} else {
|
|
24
|
+
region = process.env.AWS_REGION;
|
|
25
|
+
}
|
|
26
|
+
this.logger.info(`SQS Region: ${region}`);
|
|
27
|
+
this.client = new SQSClient({ region: region });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async pushToQueue(event: Object): Promise<any> {
|
|
31
|
+
if (process.env.SQS_QUEUE_URL === 'undefined') {
|
|
32
|
+
return { message: 'SQS_QUEUE_URL is undefined' };
|
|
33
|
+
}
|
|
34
|
+
const params: SendMessageCommandInput = {
|
|
35
|
+
MessageAttributes: {
|
|
36
|
+
Event: {
|
|
37
|
+
DataType: 'String',
|
|
38
|
+
StringValue: event['event'],
|
|
39
|
+
},
|
|
40
|
+
Time: {
|
|
41
|
+
DataType: 'String',
|
|
42
|
+
StringValue: event['timestamp']
|
|
43
|
+
? event['timestamp']
|
|
44
|
+
: new Date().toISOString(),
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
QueueUrl: process.env.SQS_QUEUE_URL,
|
|
48
|
+
MessageBody: JSON.stringify(event),
|
|
49
|
+
};
|
|
50
|
+
const sendMessageCommand = new SendMessageCommand(params);
|
|
51
|
+
try {
|
|
52
|
+
const sendMessageResult = await this.client.send(sendMessageCommand);
|
|
53
|
+
this.logger.info(
|
|
54
|
+
`Response from SQS: ${JSON.stringify(sendMessageResult)}`
|
|
55
|
+
);
|
|
56
|
+
return sendMessageResult;
|
|
57
|
+
} catch (err) {
|
|
58
|
+
this.logger.error(err);
|
|
59
|
+
return err;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async pullFromQueue(): Promise<any> {
|
|
64
|
+
if (process.env.SQS_QUEUE_URL === 'undefined') {
|
|
65
|
+
return { message: 'SQS_QUEUE_URL is undefined' };
|
|
66
|
+
}
|
|
67
|
+
let maxMessages: number = 10;
|
|
68
|
+
if (typeof process.env.SQS_MAX_MESSAGES === 'number') {
|
|
69
|
+
maxMessages = process.env.SQS_MAX_MESSAGES;
|
|
70
|
+
}
|
|
71
|
+
let waitTime: number = 20;
|
|
72
|
+
if (typeof process.env.SQS_WAIT_TIME === 'number') {
|
|
73
|
+
waitTime = process.env.SQS_WAIT_TIME;
|
|
74
|
+
}
|
|
75
|
+
const params: ReceiveMessageCommandInput = {
|
|
76
|
+
QueueUrl: process.env.SQS_QUEUE_URL,
|
|
77
|
+
MaxNumberOfMessages: maxMessages,
|
|
78
|
+
MessageAttributeNames: ['All'],
|
|
79
|
+
WaitTimeSeconds: waitTime,
|
|
80
|
+
};
|
|
81
|
+
const receiveMessageCommand = new ReceiveMessageCommand(params);
|
|
82
|
+
try {
|
|
83
|
+
const receiveMessageResult = await this.client.send(
|
|
84
|
+
receiveMessageCommand
|
|
85
|
+
);
|
|
86
|
+
this.logger.info(
|
|
87
|
+
`Reserved Messages From SQS Count: ${
|
|
88
|
+
receiveMessageResult.Messages
|
|
89
|
+
? receiveMessageResult.Messages.length
|
|
90
|
+
: 0
|
|
91
|
+
}`
|
|
92
|
+
);
|
|
93
|
+
if (!receiveMessageResult.Messages) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
return receiveMessageResult.Messages;
|
|
97
|
+
} catch (err) {
|
|
98
|
+
this.logger.error(err);
|
|
99
|
+
return err;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async removeFromQueue(queueMsg: Message) {
|
|
104
|
+
if (process.env.SQS_QUEUE_URL === 'undefined') {
|
|
105
|
+
return { message: 'SQS_QUEUE_URL is undefined' };
|
|
106
|
+
}
|
|
107
|
+
const params: DeleteMessageCommandInput = {
|
|
108
|
+
QueueUrl: process.env.SQS_QUEUE_URL,
|
|
109
|
+
ReceiptHandle: queueMsg.ReceiptHandle,
|
|
110
|
+
};
|
|
111
|
+
const deleteMessageCommand = new DeleteMessageCommand(params);
|
|
112
|
+
try {
|
|
113
|
+
const deleteMessageResult = await this.client.send(deleteMessageCommand);
|
|
114
|
+
this.logger.info(
|
|
115
|
+
`Response from SQS: ${JSON.stringify(deleteMessageResult)}`
|
|
116
|
+
);
|
|
117
|
+
return deleteMessageResult;
|
|
118
|
+
} catch (err) {
|
|
119
|
+
this.logger.error(JSON.stringify(err));
|
|
120
|
+
return err;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
getEventJSONsFromMessages(messages: Message[]): any[] {
|
|
125
|
+
return messages.map((item) => (item.Body ? JSON.parse(item.Body) : {}));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
2
|
+
import winston from 'winston';
|
|
3
|
+
import { AbstractDBAdapter, IGetItemInput, IGetItems, IPutItemInput, IHandleErrorOutput } from '../../types/interfaces';
|
|
4
|
+
export declare class DynamoDBAdapter implements AbstractDBAdapter {
|
|
5
|
+
logger: winston.Logger;
|
|
6
|
+
dbClient: DynamoDBClient;
|
|
7
|
+
constructor(logger: winston.Logger);
|
|
8
|
+
tableExists(name: string): Promise<boolean>;
|
|
9
|
+
putItem(params: IPutItemInput): Promise<boolean>;
|
|
10
|
+
getItem(params: IGetItemInput): Promise<any>;
|
|
11
|
+
deleteItem(params: IGetItemInput): Promise<boolean>;
|
|
12
|
+
getItemsBySession(params: IGetItems): Promise<any[]>;
|
|
13
|
+
handleError(errorObject: any): IHandleErrorOutput;
|
|
14
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DynamoDBAdapter = void 0;
|
|
13
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
14
|
+
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
15
|
+
const interfaces_1 = require("../../types/interfaces");
|
|
16
|
+
class DynamoDBAdapter {
|
|
17
|
+
constructor(logger) {
|
|
18
|
+
this.dbClient = new client_dynamodb_1.DynamoDBClient({
|
|
19
|
+
region: process.env.AWS_REGION,
|
|
20
|
+
maxAttempts: 5,
|
|
21
|
+
});
|
|
22
|
+
this.logger = logger;
|
|
23
|
+
}
|
|
24
|
+
tableExists(name) {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
try {
|
|
27
|
+
const params = { TableName: name };
|
|
28
|
+
const tablesData = yield this.dbClient.send(new client_dynamodb_1.DescribeTableCommand(params));
|
|
29
|
+
if (tablesData['Table'] && tablesData['Table'].TableStatus === 'ACTIVE')
|
|
30
|
+
return true;
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
catch (awsError) {
|
|
34
|
+
if (awsError.name && awsError.name === 'ResourceNotFoundException') {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.logger.error(awsError);
|
|
39
|
+
throw new Error(awsError);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
putItem(params) {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
try {
|
|
47
|
+
const data = yield this.dbClient.send(new client_dynamodb_1.PutItemCommand({
|
|
48
|
+
TableName: params.tableName,
|
|
49
|
+
Item: (0, util_dynamodb_1.marshall)(params.data),
|
|
50
|
+
}));
|
|
51
|
+
return data.$metadata.httpStatusCode === 200;
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
throw this.handleError(err);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
getItem(params) {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
try {
|
|
61
|
+
const data = yield this.dbClient.send(new client_dynamodb_1.GetItemCommand({
|
|
62
|
+
TableName: params.tableName,
|
|
63
|
+
Key: (0, util_dynamodb_1.marshall)({
|
|
64
|
+
sessionId: params.sessionId,
|
|
65
|
+
timestamp: params.timestamp,
|
|
66
|
+
}),
|
|
67
|
+
}));
|
|
68
|
+
this.logger.debug('Read Item from Table');
|
|
69
|
+
return data;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
throw this.handleError(err);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
deleteItem(params) {
|
|
77
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
try {
|
|
79
|
+
const data = yield this.dbClient.send(new client_dynamodb_1.DeleteItemCommand({
|
|
80
|
+
TableName: params.tableName,
|
|
81
|
+
Key: (0, util_dynamodb_1.marshall)({
|
|
82
|
+
sessionId: params.sessionId,
|
|
83
|
+
timestamp: params.timestamp,
|
|
84
|
+
}),
|
|
85
|
+
}));
|
|
86
|
+
this.logger.debug('Deleted Item from Table', data);
|
|
87
|
+
return data.$metadata.httpStatusCode === 200;
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
throw this.handleError(err);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
getItemsBySession(params) {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
try {
|
|
97
|
+
const inputData = {
|
|
98
|
+
TableName: params.tableName,
|
|
99
|
+
KeyConditionExpression: '#sid = :sid',
|
|
100
|
+
ExpressionAttributeNames: {
|
|
101
|
+
'#sid': 'sessionId',
|
|
102
|
+
},
|
|
103
|
+
ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
|
|
104
|
+
':sid': params.sessionId,
|
|
105
|
+
}),
|
|
106
|
+
};
|
|
107
|
+
const queryData = yield this.dbClient.send(new client_dynamodb_1.QueryCommand(inputData));
|
|
108
|
+
if (queryData.Items && queryData.Items.length > 0) {
|
|
109
|
+
let items = [];
|
|
110
|
+
for (let i = 0; i < queryData.Items.length; i++) {
|
|
111
|
+
items[i] = (0, util_dynamodb_1.unmarshall)(queryData.Items[i]);
|
|
112
|
+
}
|
|
113
|
+
return items;
|
|
114
|
+
}
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
throw this.handleError(err);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
handleError(errorObject) {
|
|
123
|
+
this.logger.error(errorObject);
|
|
124
|
+
const errorOutput = {
|
|
125
|
+
errorType: interfaces_1.ErrorType.ABORT,
|
|
126
|
+
error: errorObject,
|
|
127
|
+
};
|
|
128
|
+
if (errorObject.name) {
|
|
129
|
+
if (errorObject.name === 'ResourceNotFoundException' ||
|
|
130
|
+
errorObject.name === 'ResourceInUseException') {
|
|
131
|
+
errorOutput['errorType'] = interfaces_1.ErrorType.CONTINUE;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return errorOutput;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.DynamoDBAdapter = DynamoDBAdapter;
|
|
138
|
+
//# sourceMappingURL=DynamoDBAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBAdapter.js","sourceRoot":"","sources":["../../../adapters/db/DynamoDBAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Logger } from "winston";
|
|
2
|
+
import { AbstractDBAdapter, IHandleErrorOutput, IPutItemInput, IGetItemInput, IGetItems } from "../../types/interfaces";
|
|
3
|
+
import { MongoClient } from "mongodb";
|
|
4
|
+
export declare class MongoDBAdapter implements AbstractDBAdapter {
|
|
5
|
+
logger: Logger;
|
|
6
|
+
dbClient: MongoClient;
|
|
7
|
+
constructor(logger: Logger);
|
|
8
|
+
private isConnected;
|
|
9
|
+
private connect;
|
|
10
|
+
tableExists(tableName: string): Promise<boolean>;
|
|
11
|
+
putItem({ tableName, data }: IPutItemInput): Promise<boolean>;
|
|
12
|
+
getItem({ sessionId, tableName, timestamp }: IGetItemInput): Promise<any>;
|
|
13
|
+
deleteItem({ sessionId, tableName, timestamp }: IGetItemInput): Promise<boolean>;
|
|
14
|
+
getItemsBySession({ tableName, sessionId }: IGetItems): Promise<any[]>;
|
|
15
|
+
handleError(error: any): IHandleErrorOutput;
|
|
16
|
+
}
|