aws-classify-server 0.1.3 → 0.1.5
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
CHANGED
|
@@ -274,7 +274,7 @@ plugins:
|
|
|
274
274
|
- serverless-dynamodb-local
|
|
275
275
|
- serverless-offline
|
|
276
276
|
```
|
|
277
|
-
The provider section details configuration the Serverless Framework handles. Many of the details are in included files to keep this simple and
|
|
277
|
+
The provider section details configuration the Serverless Framework handles. Many of the details are in included files to keep this simple and resilient to change
|
|
278
278
|
```
|
|
279
279
|
provider:
|
|
280
280
|
name: aws
|
|
@@ -285,6 +285,7 @@ provider:
|
|
|
285
285
|
websocket: true
|
|
286
286
|
environment:
|
|
287
287
|
APIG_ENDPOINT: ${file(${self:custom.yml}/apig.yml)}
|
|
288
|
+
DOMAIN: ${self:custom.domainName}
|
|
288
289
|
iam:
|
|
289
290
|
role:
|
|
290
291
|
statements:
|
|
@@ -4,7 +4,9 @@ export declare class ClassifyServerless {
|
|
|
4
4
|
logLevel: Partial<typeof EndPointsLogging>;
|
|
5
5
|
classDefs: Map<any, ClassDef<any, any>>;
|
|
6
6
|
requests: Map<any, any>;
|
|
7
|
+
expirationMinutes: number;
|
|
7
8
|
log: (_message: string) => void;
|
|
9
|
+
setExpirationMinutes(minutes: number): void;
|
|
8
10
|
setLogger(log: (_message: string) => void): void;
|
|
9
11
|
setLogLevel(logLevel: Partial<typeof EndPointsLogging>): void;
|
|
10
12
|
registerResponse<T>(responseClass: new () => T, authorizer?: (_endPoint: T, _method: string, _args: IArguments) => Promise<boolean>): void;
|
|
@@ -17,9 +19,12 @@ export declare class ClassifyServerless {
|
|
|
17
19
|
createRequestForSession<T>(sessionId: string, requestClass: new () => T): Promise<T>;
|
|
18
20
|
createResponse<T, R>(responseClass: new () => T, sessionId: string, callback: (_obj: T) => Promise<R>, classes?: any): Promise<R>;
|
|
19
21
|
getSessionsForUserId(userId: string): Promise<any[]>;
|
|
22
|
+
getSessions(): Promise<any[]>;
|
|
23
|
+
deleteSessionsForUserId(userId: string): Promise<void>;
|
|
24
|
+
deleteSessions(): Promise<void>;
|
|
20
25
|
}
|
|
21
26
|
export declare function getSessionData(sessionId: string, interfaceName?: string): Promise<Record<string, any> | undefined>;
|
|
22
|
-
export declare function saveSessionData(sessionId: string, interfaceName?: string, sessionData?: string, connectionId?: string, userId?: string): Promise<string>;
|
|
27
|
+
export declare function saveSessionData(sessionId: string, interfaceName?: string, sessionData?: string, connectionId?: string, userId?: string, expirationMinutes?: number): Promise<string>;
|
|
23
28
|
export declare const EndPointsLogging: {
|
|
24
29
|
create: boolean;
|
|
25
30
|
connect: boolean;
|
|
@@ -21,8 +21,12 @@ class ClassifyServerless {
|
|
|
21
21
|
this.logLevel = {};
|
|
22
22
|
this.classDefs = new Map();
|
|
23
23
|
this.requests = new Map();
|
|
24
|
+
this.expirationMinutes = 60 * 24;
|
|
24
25
|
this.log = msg => console.log(msg);
|
|
25
26
|
}
|
|
27
|
+
setExpirationMinutes(minutes) {
|
|
28
|
+
this.expirationMinutes = minutes;
|
|
29
|
+
}
|
|
26
30
|
setLogger(log) {
|
|
27
31
|
this.log = log;
|
|
28
32
|
}
|
|
@@ -54,7 +58,7 @@ class ClassifyServerless {
|
|
|
54
58
|
const socketResult = yield getSessionData(sessionId, "");
|
|
55
59
|
if (!socketResult) {
|
|
56
60
|
sessionId = context.awsRequestId;
|
|
57
|
-
yield saveSessionData(sessionId, undefined, undefined, undefined);
|
|
61
|
+
yield saveSessionData(sessionId, undefined, undefined, undefined, undefined, this.expirationMinutes);
|
|
58
62
|
}
|
|
59
63
|
const lambdaResponse = {
|
|
60
64
|
data: process.env.IS_OFFLINE ? 'ws://localhost:3001' : `wss://${process.env.APIG_ENDPOINT}`,
|
|
@@ -106,7 +110,7 @@ class ClassifyServerless {
|
|
|
106
110
|
}
|
|
107
111
|
const updatedSessionData = (0, js_freeze_dry_1.serialize)(obj, classes);
|
|
108
112
|
if (!result || updatedSessionData !== result.sessionData)
|
|
109
|
-
sessionId = yield saveSessionData(sessionId, request.interfaceName, updatedSessionData, undefined, obj.__userId__);
|
|
113
|
+
sessionId = yield saveSessionData(sessionId, request.interfaceName, updatedSessionData, undefined, obj.__userId__, this.expirationMinutes);
|
|
110
114
|
// Formulate response
|
|
111
115
|
const lambdaResponse = {
|
|
112
116
|
data: fnResponse,
|
|
@@ -174,7 +178,7 @@ class ClassifyServerless {
|
|
|
174
178
|
catch (e) {
|
|
175
179
|
if (expressServer.logLevel.exceptions)
|
|
176
180
|
expressServer.log(e.message);
|
|
177
|
-
throw e;
|
|
181
|
+
throw new Error(`Unable to send message via Websocket ${e.message}`);
|
|
178
182
|
}
|
|
179
183
|
});
|
|
180
184
|
};
|
|
@@ -238,10 +242,10 @@ class ClassifyServerless {
|
|
|
238
242
|
this.log(`creating response for ${interfaceName} with sessionId=${sessionId} connectionId= ${obj.__connectionId__} sessionData=${sessionData}`);
|
|
239
243
|
const ret = yield callback(obj);
|
|
240
244
|
const updatedSessionData = (0, js_freeze_dry_1.serialize)(obj, classes);
|
|
241
|
-
if (updatedSessionData !== result.sessionData) {
|
|
245
|
+
if (updatedSessionData !== result.sessionData || Math.floor(Date.now() / 1000 / 60) !== result.expires / 60) {
|
|
242
246
|
if (this.logLevel.calls)
|
|
243
247
|
this.log(`saving session data for ${interfaceName} with sessionId=${sessionId} connectionId= ${obj.__connectionId__} sessionData=${updatedSessionData}`);
|
|
244
|
-
yield saveSessionData(sessionId, interfaceName, updatedSessionData, undefined);
|
|
248
|
+
yield saveSessionData(sessionId, interfaceName, updatedSessionData, undefined, undefined, this.expirationMinutes);
|
|
245
249
|
}
|
|
246
250
|
return ret;
|
|
247
251
|
});
|
|
@@ -263,8 +267,54 @@ class ClassifyServerless {
|
|
|
263
267
|
return [];
|
|
264
268
|
});
|
|
265
269
|
}
|
|
270
|
+
getSessions() {
|
|
271
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
272
|
+
const data = yield ddbDocClient.scan({
|
|
273
|
+
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
274
|
+
ProjectionExpression: `sessionId`
|
|
275
|
+
});
|
|
276
|
+
return data.Items ? data.Items.map(i => i.sessionId) : [];
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
deleteSessionsForUserId(userId) {
|
|
280
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
281
|
+
if (userId) {
|
|
282
|
+
const data = yield ddbDocClient.query({
|
|
283
|
+
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
284
|
+
KeyConditionExpression: 'userId = :userId',
|
|
285
|
+
IndexName: 'userId',
|
|
286
|
+
ExpressionAttributeValues: {
|
|
287
|
+
':userId': userId,
|
|
288
|
+
},
|
|
289
|
+
ProjectionExpression: `sessionId`
|
|
290
|
+
});
|
|
291
|
+
const keys = data.Items ? data.Items.map(i => i.sessionId) : [];
|
|
292
|
+
yield deleteSessionByKeys(keys);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
deleteSessions() {
|
|
297
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
298
|
+
const data = yield ddbDocClient.scan({
|
|
299
|
+
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
300
|
+
ProjectionExpression: `sessionId`
|
|
301
|
+
});
|
|
302
|
+
const keys = data.Items ? data.Items.map(i => i.sessionId) : [];
|
|
303
|
+
yield deleteSessionByKeys(keys);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
266
306
|
}
|
|
267
307
|
exports.ClassifyServerless = ClassifyServerless;
|
|
308
|
+
function deleteSessionByKeys(keys) {
|
|
309
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
310
|
+
for (let ix = 0; ix < keys.length; ++ix) {
|
|
311
|
+
yield ddbDocClient.delete({
|
|
312
|
+
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
313
|
+
Key: { sessionId: keys[ix] }
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
268
318
|
function getSessionData(sessionId, interfaceName = "") {
|
|
269
319
|
return __awaiter(this, void 0, void 0, function* () {
|
|
270
320
|
if (sessionId) {
|
|
@@ -272,7 +322,7 @@ function getSessionData(sessionId, interfaceName = "") {
|
|
|
272
322
|
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
273
323
|
Key: { sessionId },
|
|
274
324
|
ConsistentRead: true,
|
|
275
|
-
ProjectionExpression: `interface_${interfaceName}, connectionId, userId, updated`
|
|
325
|
+
ProjectionExpression: `interface_${interfaceName}, connectionId, userId, updated, expires`
|
|
276
326
|
});
|
|
277
327
|
return data.Item;
|
|
278
328
|
}
|
|
@@ -280,10 +330,16 @@ function getSessionData(sessionId, interfaceName = "") {
|
|
|
280
330
|
});
|
|
281
331
|
}
|
|
282
332
|
exports.getSessionData = getSessionData;
|
|
283
|
-
function saveSessionData(sessionId, interfaceName, sessionData, connectionId, userId) {
|
|
333
|
+
function saveSessionData(sessionId, interfaceName, sessionData, connectionId, userId, expirationMinutes) {
|
|
284
334
|
return __awaiter(this, void 0, void 0, function* () {
|
|
285
335
|
const updateExpressionComponents = ['updated = :time'];
|
|
286
336
|
const expressionAttributeValues = { ':time': new Date().getTime() };
|
|
337
|
+
if (typeof expirationMinutes === 'number') {
|
|
338
|
+
const expires = new Date();
|
|
339
|
+
expires.setMinutes(expires.getMinutes() + expirationMinutes);
|
|
340
|
+
updateExpressionComponents.push('expires = :expires');
|
|
341
|
+
expressionAttributeValues[':expires'] = expires.getTime() / 1000;
|
|
342
|
+
}
|
|
287
343
|
if (sessionData && interfaceName) {
|
|
288
344
|
updateExpressionComponents.push(`interface_${interfaceName} = :data`);
|
|
289
345
|
expressionAttributeValues[`:data`] = sessionData;
|
|
@@ -4,7 +4,9 @@ export declare class ClassifyServerless {
|
|
|
4
4
|
logLevel: Partial<typeof EndPointsLogging>;
|
|
5
5
|
classDefs: Map<any, ClassDef<any, any>>;
|
|
6
6
|
requests: Map<any, any>;
|
|
7
|
+
expirationMinutes: number;
|
|
7
8
|
log: (_message: string) => void;
|
|
9
|
+
setExpirationMinutes(minutes: number): void;
|
|
8
10
|
setLogger(log: (_message: string) => void): void;
|
|
9
11
|
setLogLevel(logLevel: Partial<typeof EndPointsLogging>): void;
|
|
10
12
|
registerResponse<T>(responseClass: new () => T, authorizer?: (_endPoint: T, _method: string, _args: IArguments) => Promise<boolean>): void;
|
|
@@ -17,9 +19,12 @@ export declare class ClassifyServerless {
|
|
|
17
19
|
createRequestForSession<T>(sessionId: string, requestClass: new () => T): Promise<T>;
|
|
18
20
|
createResponse<T, R>(responseClass: new () => T, sessionId: string, callback: (_obj: T) => Promise<R>, classes?: any): Promise<R>;
|
|
19
21
|
getSessionsForUserId(userId: string): Promise<any[]>;
|
|
22
|
+
getSessions(): Promise<any[]>;
|
|
23
|
+
deleteSessionsForUserId(userId: string): Promise<void>;
|
|
24
|
+
deleteSessions(): Promise<void>;
|
|
20
25
|
}
|
|
21
26
|
export declare function getSessionData(sessionId: string, interfaceName?: string): Promise<Record<string, any> | undefined>;
|
|
22
|
-
export declare function saveSessionData(sessionId: string, interfaceName?: string, sessionData?: string, connectionId?: string, userId?: string): Promise<string>;
|
|
27
|
+
export declare function saveSessionData(sessionId: string, interfaceName?: string, sessionData?: string, connectionId?: string, userId?: string, expirationMinutes?: number): Promise<string>;
|
|
23
28
|
export declare const EndPointsLogging: {
|
|
24
29
|
create: boolean;
|
|
25
30
|
connect: boolean;
|
|
@@ -18,8 +18,12 @@ export class ClassifyServerless {
|
|
|
18
18
|
this.logLevel = {};
|
|
19
19
|
this.classDefs = new Map();
|
|
20
20
|
this.requests = new Map();
|
|
21
|
+
this.expirationMinutes = 60 * 24;
|
|
21
22
|
this.log = msg => console.log(msg);
|
|
22
23
|
}
|
|
24
|
+
setExpirationMinutes(minutes) {
|
|
25
|
+
this.expirationMinutes = minutes;
|
|
26
|
+
}
|
|
23
27
|
setLogger(log) {
|
|
24
28
|
this.log = log;
|
|
25
29
|
}
|
|
@@ -51,7 +55,7 @@ export class ClassifyServerless {
|
|
|
51
55
|
const socketResult = yield getSessionData(sessionId, "");
|
|
52
56
|
if (!socketResult) {
|
|
53
57
|
sessionId = context.awsRequestId;
|
|
54
|
-
yield saveSessionData(sessionId, undefined, undefined, undefined);
|
|
58
|
+
yield saveSessionData(sessionId, undefined, undefined, undefined, undefined, this.expirationMinutes);
|
|
55
59
|
}
|
|
56
60
|
const lambdaResponse = {
|
|
57
61
|
data: process.env.IS_OFFLINE ? 'ws://localhost:3001' : `wss://${process.env.APIG_ENDPOINT}`,
|
|
@@ -103,7 +107,7 @@ export class ClassifyServerless {
|
|
|
103
107
|
}
|
|
104
108
|
const updatedSessionData = serialize(obj, classes);
|
|
105
109
|
if (!result || updatedSessionData !== result.sessionData)
|
|
106
|
-
sessionId = yield saveSessionData(sessionId, request.interfaceName, updatedSessionData, undefined, obj.__userId__);
|
|
110
|
+
sessionId = yield saveSessionData(sessionId, request.interfaceName, updatedSessionData, undefined, obj.__userId__, this.expirationMinutes);
|
|
107
111
|
// Formulate response
|
|
108
112
|
const lambdaResponse = {
|
|
109
113
|
data: fnResponse,
|
|
@@ -171,7 +175,7 @@ export class ClassifyServerless {
|
|
|
171
175
|
catch (e) {
|
|
172
176
|
if (expressServer.logLevel.exceptions)
|
|
173
177
|
expressServer.log(e.message);
|
|
174
|
-
throw e;
|
|
178
|
+
throw new Error(`Unable to send message via Websocket ${e.message}`);
|
|
175
179
|
}
|
|
176
180
|
});
|
|
177
181
|
};
|
|
@@ -235,10 +239,10 @@ export class ClassifyServerless {
|
|
|
235
239
|
this.log(`creating response for ${interfaceName} with sessionId=${sessionId} connectionId= ${obj.__connectionId__} sessionData=${sessionData}`);
|
|
236
240
|
const ret = yield callback(obj);
|
|
237
241
|
const updatedSessionData = serialize(obj, classes);
|
|
238
|
-
if (updatedSessionData !== result.sessionData) {
|
|
242
|
+
if (updatedSessionData !== result.sessionData || Math.floor(Date.now() / 1000 / 60) !== result.expires / 60) {
|
|
239
243
|
if (this.logLevel.calls)
|
|
240
244
|
this.log(`saving session data for ${interfaceName} with sessionId=${sessionId} connectionId= ${obj.__connectionId__} sessionData=${updatedSessionData}`);
|
|
241
|
-
yield saveSessionData(sessionId, interfaceName, updatedSessionData, undefined);
|
|
245
|
+
yield saveSessionData(sessionId, interfaceName, updatedSessionData, undefined, undefined, this.expirationMinutes);
|
|
242
246
|
}
|
|
243
247
|
return ret;
|
|
244
248
|
});
|
|
@@ -260,6 +264,52 @@ export class ClassifyServerless {
|
|
|
260
264
|
return [];
|
|
261
265
|
});
|
|
262
266
|
}
|
|
267
|
+
getSessions() {
|
|
268
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
269
|
+
const data = yield ddbDocClient.scan({
|
|
270
|
+
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
271
|
+
ProjectionExpression: `sessionId`
|
|
272
|
+
});
|
|
273
|
+
return data.Items ? data.Items.map(i => i.sessionId) : [];
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
deleteSessionsForUserId(userId) {
|
|
277
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
278
|
+
if (userId) {
|
|
279
|
+
const data = yield ddbDocClient.query({
|
|
280
|
+
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
281
|
+
KeyConditionExpression: 'userId = :userId',
|
|
282
|
+
IndexName: 'userId',
|
|
283
|
+
ExpressionAttributeValues: {
|
|
284
|
+
':userId': userId,
|
|
285
|
+
},
|
|
286
|
+
ProjectionExpression: `sessionId`
|
|
287
|
+
});
|
|
288
|
+
const keys = data.Items ? data.Items.map(i => i.sessionId) : [];
|
|
289
|
+
yield deleteSessionByKeys(keys);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
deleteSessions() {
|
|
294
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
295
|
+
const data = yield ddbDocClient.scan({
|
|
296
|
+
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
297
|
+
ProjectionExpression: `sessionId`
|
|
298
|
+
});
|
|
299
|
+
const keys = data.Items ? data.Items.map(i => i.sessionId) : [];
|
|
300
|
+
yield deleteSessionByKeys(keys);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function deleteSessionByKeys(keys) {
|
|
305
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
306
|
+
for (let ix = 0; ix < keys.length; ++ix) {
|
|
307
|
+
yield ddbDocClient.delete({
|
|
308
|
+
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
309
|
+
Key: { sessionId: keys[ix] }
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
});
|
|
263
313
|
}
|
|
264
314
|
export function getSessionData(sessionId, interfaceName = "") {
|
|
265
315
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -268,17 +318,23 @@ export function getSessionData(sessionId, interfaceName = "") {
|
|
|
268
318
|
TableName: `classifySessionStore.${process.env.DOMAIN}`,
|
|
269
319
|
Key: { sessionId },
|
|
270
320
|
ConsistentRead: true,
|
|
271
|
-
ProjectionExpression: `interface_${interfaceName}, connectionId, userId, updated`
|
|
321
|
+
ProjectionExpression: `interface_${interfaceName}, connectionId, userId, updated, expires`
|
|
272
322
|
});
|
|
273
323
|
return data.Item;
|
|
274
324
|
}
|
|
275
325
|
return undefined;
|
|
276
326
|
});
|
|
277
327
|
}
|
|
278
|
-
export function saveSessionData(sessionId, interfaceName, sessionData, connectionId, userId) {
|
|
328
|
+
export function saveSessionData(sessionId, interfaceName, sessionData, connectionId, userId, expirationMinutes) {
|
|
279
329
|
return __awaiter(this, void 0, void 0, function* () {
|
|
280
330
|
const updateExpressionComponents = ['updated = :time'];
|
|
281
331
|
const expressionAttributeValues = { ':time': new Date().getTime() };
|
|
332
|
+
if (typeof expirationMinutes === 'number') {
|
|
333
|
+
const expires = new Date();
|
|
334
|
+
expires.setMinutes(expires.getMinutes() + expirationMinutes);
|
|
335
|
+
updateExpressionComponents.push('expires = :expires');
|
|
336
|
+
expressionAttributeValues[':expires'] = expires.getTime() / 1000;
|
|
337
|
+
}
|
|
282
338
|
if (sessionData && interfaceName) {
|
|
283
339
|
updateExpressionComponents.push(`interface_${interfaceName} = :data`);
|
|
284
340
|
expressionAttributeValues[`:data`] = sessionData;
|
package/package.json
CHANGED