@nu-art/push-pub-sub-backend 0.401.9 → 0.500.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/core/module-pack.d.ts +1 -1
- package/core/permissions.d.ts +1 -1
- package/core/permissions.js +10 -10
- package/modules/ModuleBE_PushMessagesHistoryDB.d.ts +4 -5
- package/modules/ModuleBE_PushMessagesHistoryDB.js +1 -1
- package/modules/ModuleBE_PushPubSub.d.ts +16 -3
- package/modules/ModuleBE_PushPubSub.js +236 -172
- package/modules/ModuleBE_PushSessionDB.d.ts +4 -5
- package/modules/ModuleBE_PushSessionDB.js +1 -1
- package/modules/ModuleBE_PushSubscriptionDB.d.ts +5 -6
- package/modules/ModuleBE_PushSubscriptionDB.js +2 -2
- package/package.json +13 -14
package/core/module-pack.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const ModulePackBE_PushPubSub: (import("../modules/ModuleBE_PushSessionDB.js").ModuleBE_PushSessionDB_Class | import("../modules/ModuleBE_PushSubscriptionDB.js").ModuleBE_PushSubscriptionDB_Class | import("@nu-art/
|
|
1
|
+
export declare const ModulePackBE_PushPubSub: (import("../modules/ModuleBE_PushSessionDB.js").ModuleBE_PushSessionDB_Class | import("../modules/ModuleBE_PushSubscriptionDB.js").ModuleBE_PushSubscriptionDB_Class | import("@nu-art/db-api-backend").ModuleBE_BaseApi_Class<import("@nu-art/push-pub-sub-shared/push-subscription/types").DatabaseDef_PushSubscription & import("@nu-art/db-api-shared").DB_Prototype> | import("../modules/ModuleBE_PushMessagesHistoryDB.js").ModuleBE_PushMessagesHistoryDB_Class | import("../modules/ModuleBE_PushPubSub.js").ModuleBE_PushPubSub_Class)[];
|
|
2
2
|
export * from '../modules/ModuleBE_PushPubSub.js';
|
|
3
3
|
export * from '../modules/PushKey.js';
|
package/core/permissions.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DefaultDef_Group } from '@nu-art/permissions-shared';
|
|
2
|
-
import { DefaultDef_Domain, DefaultDef_Package } from '@nu-art/permissions-backend
|
|
2
|
+
import { DefaultDef_Domain, DefaultDef_Package } from '@nu-art/permissions-backend';
|
|
3
3
|
export declare const PermissionsDomain_PushMessages: Readonly<DefaultDef_Domain>;
|
|
4
4
|
export declare const PermissionsGroup_PushMessanger: Readonly<DefaultDef_Group>;
|
|
5
5
|
export declare const PermissionsPackage_PushMessages: DefaultDef_Package;
|
package/core/permissions.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CreateDefaultAccessLevels, DefaultAccessLevel_Admin } from '@nu-art/permissions-shared';
|
|
1
|
+
import { CreateDefaultAccessLevels, DefaultAccessLevel_Admin, toPermissionAccessLevelId, toPermissionDomainId, toPermissionGroupId } from '@nu-art/permissions-shared';
|
|
2
2
|
import { ApiDef_PushMessages } from '@nu-art/push-pub-sub-shared';
|
|
3
|
-
import { Domain_Developer } from '@nu-art/permissions-backend
|
|
3
|
+
import { Domain_Developer } from '@nu-art/permissions-backend';
|
|
4
4
|
import { ModuleBE_PushSubscriptionAPI } from '../modules/ModuleBE_PushSubscriptionDB.js';
|
|
5
5
|
import { _values } from '@nu-art/ts-common';
|
|
6
6
|
const Domain_PushMessages_ID = 'ce2e840bb639c34887ae19c2c7c82c11';
|
|
@@ -9,28 +9,28 @@ const DefaultAccessLevel_Active = Object.freeze({ name: 'Active', value: 0 });
|
|
|
9
9
|
const DefaultAccessLevel_Tester = Object.freeze({ name: 'Tester', value: 600 });
|
|
10
10
|
const accessLevels = [{ ...DefaultAccessLevel_Passive }, { ...DefaultAccessLevel_Active }, { ...DefaultAccessLevel_Tester }];
|
|
11
11
|
const _PermissionsDomain_PushMessages = {
|
|
12
|
-
_id: Domain_PushMessages_ID,
|
|
12
|
+
_id: toPermissionDomainId(Domain_PushMessages_ID),
|
|
13
13
|
namespace: 'Push Messages',
|
|
14
14
|
dbNames: [],
|
|
15
|
-
levels: CreateDefaultAccessLevels(Domain_PushMessages_ID, accessLevels),
|
|
15
|
+
levels: CreateDefaultAccessLevels(Domain_PushMessages_ID, accessLevels).map(level => ({ ...level, _id: toPermissionAccessLevelId(level._id) })),
|
|
16
16
|
customApis: [
|
|
17
|
-
..._values(ModuleBE_PushSubscriptionAPI.
|
|
17
|
+
..._values(ModuleBE_PushSubscriptionAPI.crudApiDef).map(api => {
|
|
18
18
|
return {
|
|
19
19
|
path: api.path,
|
|
20
20
|
accessLevel: DefaultAccessLevel_Admin.name,
|
|
21
21
|
domainId: Domain_Developer._id
|
|
22
22
|
};
|
|
23
23
|
}),
|
|
24
|
-
{ path: ApiDef_PushMessages.
|
|
25
|
-
{ path: ApiDef_PushMessages.
|
|
26
|
-
{ path: ApiDef_PushMessages.
|
|
27
|
-
{ path: ApiDef_PushMessages.
|
|
24
|
+
{ path: ApiDef_PushMessages.test.path, accessLevel: DefaultAccessLevel_Admin.name, domainId: Domain_Developer._id },
|
|
25
|
+
{ path: ApiDef_PushMessages.register.path, accessLevel: DefaultAccessLevel_Active.name },
|
|
26
|
+
{ path: ApiDef_PushMessages.registerAll.path, accessLevel: DefaultAccessLevel_Active.name },
|
|
27
|
+
{ path: ApiDef_PushMessages.unregister.path, accessLevel: DefaultAccessLevel_Active.name },
|
|
28
28
|
]
|
|
29
29
|
};
|
|
30
30
|
export const PermissionsDomain_PushMessages = Object.freeze(_PermissionsDomain_PushMessages);
|
|
31
31
|
const PermissionsGroupId_ProactivePushMessanger = '7f2c8925a6fdd2bcb9be3c1c0932deef';
|
|
32
32
|
const _PermissionsGroup_ProactivePushMessanger = {
|
|
33
|
-
_id: PermissionsGroupId_ProactivePushMessanger,
|
|
33
|
+
_id: toPermissionGroupId(PermissionsGroupId_ProactivePushMessanger),
|
|
34
34
|
name: 'Push Messanger',
|
|
35
35
|
uiLabel: 'Push Messenger',
|
|
36
36
|
accessLevels: {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export declare class ModuleBE_PushMessagesHistoryDB_Class extends ModuleBE_BaseDB<
|
|
1
|
+
import type { DB_Prototype } from '@nu-art/db-api-shared';
|
|
2
|
+
import { ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
3
|
+
import { DatabaseDef_PushMessagesHistory } from '@nu-art/push-pub-sub-shared/push-messages-history/index';
|
|
4
|
+
export declare class ModuleBE_PushMessagesHistoryDB_Class extends ModuleBE_BaseDB<DatabaseDef_PushMessagesHistory & DB_Prototype, object> {
|
|
5
5
|
constructor();
|
|
6
6
|
}
|
|
7
7
|
export declare const ModuleBE_PushMessagesHistoryDB: ModuleBE_PushMessagesHistoryDB_Class;
|
|
8
|
-
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ModuleBE_BaseDB
|
|
1
|
+
import { ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
2
2
|
import { DBDef_PushMessagesHistory } from '@nu-art/push-pub-sub-shared/push-messages-history/index';
|
|
3
3
|
export class ModuleBE_PushMessagesHistoryDB_Class extends ModuleBE_BaseDB {
|
|
4
4
|
constructor() {
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { Module } from '@nu-art/ts-common';
|
|
2
2
|
import { FirebaseType_BatchResponse } from '@nu-art/firebase-backend';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { API_PushMessages, PushMessage } from '@nu-art/push-pub-sub-shared';
|
|
4
|
+
export type CleanupDetails = {
|
|
5
|
+
cleanup: () => Promise<void>;
|
|
6
|
+
interval: number;
|
|
7
|
+
moduleKey: string;
|
|
8
|
+
};
|
|
9
|
+
export interface OnCleanupSchedulerAct {
|
|
10
|
+
__onCleanupSchedulerAct: () => CleanupDetails;
|
|
11
|
+
}
|
|
5
12
|
import { Message } from 'firebase-admin/messaging';
|
|
6
13
|
type Config = {
|
|
7
14
|
messageLengthLimit: number;
|
|
@@ -12,7 +19,13 @@ export declare class ModuleBE_PushPubSub_Class extends Module<Config> implements
|
|
|
12
19
|
private messaging;
|
|
13
20
|
constructor();
|
|
14
21
|
protected init(): void;
|
|
15
|
-
|
|
22
|
+
test(body: {
|
|
23
|
+
message: PushMessage<any, any, any>;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
register(body: API_PushMessages['register']['Body']): Promise<API_PushMessages['register']['Response']>;
|
|
26
|
+
unregister(body: API_PushMessages['unregister']['Body']): Promise<API_PushMessages['unregister']['Response']>;
|
|
27
|
+
registerAll(body: API_PushMessages['registerAll']['Body']): Promise<API_PushMessages['registerAll']['Response']>;
|
|
28
|
+
private processRegistration;
|
|
16
29
|
pushToKey: <MessageType extends PushMessage<any, any, any>>(message: MessageType) => Promise<void>;
|
|
17
30
|
sendMessage: (messages: Message[]) => Promise<{
|
|
18
31
|
response: FirebaseType_BatchResponse;
|
|
@@ -15,191 +15,255 @@
|
|
|
15
15
|
* See the License for the specific language governing permissions and
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
19
|
+
var useValue = arguments.length > 2;
|
|
20
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
21
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
22
|
+
}
|
|
23
|
+
return useValue ? value : void 0;
|
|
24
|
+
};
|
|
25
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
26
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
27
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
28
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
29
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
30
|
+
var _, done = false;
|
|
31
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
32
|
+
var context = {};
|
|
33
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
34
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
35
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
36
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
37
|
+
if (kind === "accessor") {
|
|
38
|
+
if (result === void 0) continue;
|
|
39
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
40
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
41
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
42
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
43
|
+
}
|
|
44
|
+
else if (_ = accept(result)) {
|
|
45
|
+
if (kind === "field") initializers.unshift(_);
|
|
46
|
+
else descriptor[key] = _;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
50
|
+
done = true;
|
|
51
|
+
};
|
|
18
52
|
import { arrayToMap, batchActionParallel, compare, currentTimeMillis, Day, filterDuplicates, filterKeys, KB, LogLevel, Module } from '@nu-art/ts-common';
|
|
19
53
|
import { ModuleBE_Firebase } from '@nu-art/firebase-backend';
|
|
20
54
|
import { ApiDef_PushMessages } from '@nu-art/push-pub-sub-shared';
|
|
21
|
-
import {
|
|
55
|
+
import { ApiHandler, HttpServer } from '@nu-art/http-server';
|
|
22
56
|
import { MemKey_AccountId } from '@nu-art/user-account-backend';
|
|
23
57
|
import { ModuleBE_PushSessionDB } from './ModuleBE_PushSessionDB.js';
|
|
24
58
|
import { ModuleBE_PushSubscriptionDB } from './ModuleBE_PushSubscriptionDB.js';
|
|
25
59
|
import { ModuleBE_PushMessagesHistoryDB } from './ModuleBE_PushMessagesHistoryDB.js';
|
|
26
60
|
import { HttpCodes } from '@nu-art/ts-common/core/exceptions/http-codes';
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
let ModuleBE_PushPubSub_Class = (() => {
|
|
62
|
+
let _classSuper = Module;
|
|
63
|
+
let _instanceExtraInitializers = [];
|
|
64
|
+
let _test_decorators;
|
|
65
|
+
let _register_decorators;
|
|
66
|
+
let _unregister_decorators;
|
|
67
|
+
let _registerAll_decorators;
|
|
68
|
+
return class ModuleBE_PushPubSub_Class extends _classSuper {
|
|
69
|
+
static {
|
|
70
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
71
|
+
_test_decorators = [ApiHandler(ApiDef_PushMessages.test, { httpServer: () => HttpServer.getDefault() })];
|
|
72
|
+
_register_decorators = [ApiHandler(ApiDef_PushMessages.register, { httpServer: () => HttpServer.getDefault() })];
|
|
73
|
+
_unregister_decorators = [ApiHandler(ApiDef_PushMessages.unregister, { httpServer: () => HttpServer.getDefault() })];
|
|
74
|
+
_registerAll_decorators = [ApiHandler(ApiDef_PushMessages.registerAll, { httpServer: () => HttpServer.getDefault() })];
|
|
75
|
+
__esDecorate(this, null, _test_decorators, { kind: "method", name: "test", static: false, private: false, access: { has: obj => "test" in obj, get: obj => obj.test }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
76
|
+
__esDecorate(this, null, _register_decorators, { kind: "method", name: "register", static: false, private: false, access: { has: obj => "register" in obj, get: obj => obj.register }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
77
|
+
__esDecorate(this, null, _unregister_decorators, { kind: "method", name: "unregister", static: false, private: false, access: { has: obj => "unregister" in obj, get: obj => obj.unregister }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
78
|
+
__esDecorate(this, null, _registerAll_decorators, { kind: "method", name: "registerAll", static: false, private: false, access: { has: obj => "registerAll" in obj, get: obj => obj.registerAll }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
79
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
80
|
+
}
|
|
81
|
+
// private pushSessions!: FirestoreCollection<DB_PushSession>;
|
|
82
|
+
// private topics!: FirestoreCollection<DB_PushSubscription>;
|
|
83
|
+
messaging = __runInitializers(this, _instanceExtraInitializers);
|
|
84
|
+
constructor() {
|
|
85
|
+
super();
|
|
86
|
+
this.setMinLevel(LogLevel.Verbose);
|
|
87
|
+
this.setDefaultConfig({ messageLengthLimit: 10 * KB });
|
|
88
|
+
}
|
|
89
|
+
init() {
|
|
90
|
+
super.init();
|
|
91
|
+
const session = ModuleBE_Firebase.createAdminSession();
|
|
92
|
+
this.messaging = session.getMessaging();
|
|
93
|
+
}
|
|
94
|
+
async test(body) {
|
|
95
|
+
await this.pushToKey(body.message);
|
|
96
|
+
}
|
|
97
|
+
async register(body) {
|
|
98
|
+
await this.processRegistration(body);
|
|
99
|
+
return body.subscriptions?.[0] ?? { topic: '', filter: undefined };
|
|
100
|
+
}
|
|
101
|
+
async unregister(body) {
|
|
102
|
+
await this.processRegistration(body);
|
|
103
|
+
return body.subscriptions?.[0] ?? { topic: '', filter: undefined };
|
|
104
|
+
}
|
|
105
|
+
async registerAll(body) {
|
|
106
|
+
await this.processRegistration(body);
|
|
107
|
+
return body.subscriptions ?? [];
|
|
108
|
+
}
|
|
109
|
+
processRegistration = async (body) => {
|
|
110
|
+
const accountId = MemKey_AccountId.get();
|
|
111
|
+
const session = {
|
|
112
|
+
firebaseToken: body.firebaseToken,
|
|
58
113
|
pushSessionId: body.pushSessionId,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return ModuleBE_PushSubscriptionDB.create.all(toInsert, transaction);
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
// ---------------------------
|
|
72
|
-
pushToKey = async (message) => {
|
|
73
|
-
const originatingAccountId = MemKey_AccountId.get();
|
|
74
|
-
const messageLength = JSON.stringify(message).length;
|
|
75
|
-
if (messageLength > this.config.messageLengthLimit)
|
|
76
|
-
throw HttpCodes._4XX.BAD_REQUEST(`Message content too long, ${messageLength} > ${this.config.messageLengthLimit}`);
|
|
77
|
-
const messageSubscription = { topic: message.topic, props: message.filter };
|
|
78
|
-
const newVar = async (transaction) => {
|
|
79
|
-
let subscriptions = await ModuleBE_PushSubscriptionDB.query.where({ topic: message.topic }, transaction);
|
|
80
|
-
this.logVerbose(`Found ${subscriptions.length} subscribers for message: `, messageSubscription);
|
|
81
|
-
if (message.filter)
|
|
82
|
-
subscriptions = subscriptions.filter(subscription => !subscription.filter || compare(subscription.filter, message.filter));
|
|
83
|
-
if (subscriptions.length === 0)
|
|
84
|
-
return this.logDebug('No subscribers match message: ', message);
|
|
85
|
-
const sessionsIds = subscriptions.map(d => d.pushSessionId);
|
|
86
|
-
// I get the tokens relative to those sessions (query)
|
|
87
|
-
this.logDebug(`Sending push to:`, ` -- Sessions:`, sessionsIds, ` -- Message: `, message);
|
|
88
|
-
const pushSessions = await batchActionParallel(sessionsIds, 10, async (elements) => ModuleBE_PushSessionDB.query.where({ pushSessionId: { $in: elements } }, transaction));
|
|
89
|
-
const map_sessionIdToSession = arrayToMap(pushSessions, session => session.pushSessionId);
|
|
90
|
-
subscriptions = subscriptions.filter(subscription => map_sessionIdToSession[subscription.pushSessionId]);
|
|
91
|
-
const messagesToCreate = subscriptions.map((subscription) => {
|
|
92
|
-
return {
|
|
93
|
-
pushSessionId: subscription.pushSessionId,
|
|
94
|
-
token: map_sessionIdToSession[subscription.pushSessionId].firebaseToken,
|
|
95
|
-
message: message,
|
|
96
|
-
read: false,
|
|
97
|
-
originatingAccountId
|
|
98
|
-
};
|
|
114
|
+
timestamp: currentTimeMillis(),
|
|
115
|
+
accountId
|
|
116
|
+
};
|
|
117
|
+
await ModuleBE_PushSessionDB.set.item(session);
|
|
118
|
+
const subscriptions = body.subscriptions.map((subscription) => {
|
|
119
|
+
return filterKeys({
|
|
120
|
+
pushSessionId: body.pushSessionId,
|
|
121
|
+
...subscription
|
|
122
|
+
});
|
|
99
123
|
});
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
message: dbMessage.message,
|
|
108
|
-
topic: message.topic,
|
|
109
|
-
filter: message.filter,
|
|
110
|
-
};
|
|
111
|
-
const data = {
|
|
112
|
-
sessionId: dbMessage.pushSessionId,
|
|
113
|
-
payload: JSON.stringify(messageBody)
|
|
114
|
-
};
|
|
115
|
-
return {
|
|
116
|
-
token: dbMessage.token,
|
|
117
|
-
data: data
|
|
118
|
-
};
|
|
124
|
+
await ModuleBE_PushSubscriptionDB.runTransaction(async (transaction) => {
|
|
125
|
+
const data = await ModuleBE_PushSubscriptionDB.query.where({ pushSessionId: body.pushSessionId }, transaction);
|
|
126
|
+
const toInsert = subscriptions.filter(s => !data.find(d => d.topic === s.topic && compare(s.filter, d.filter)));
|
|
127
|
+
if (toInsert.length === 0)
|
|
128
|
+
return;
|
|
129
|
+
this.logWarning(`Subscribe on: `, toInsert);
|
|
130
|
+
return ModuleBE_PushSubscriptionDB.create.all(toInsert, transaction);
|
|
119
131
|
});
|
|
120
|
-
const { response, messages } = await this.sendMessage(messagesToSend);
|
|
121
|
-
this.logInfo(`${response.successCount} sent, ${response.failureCount} failed`, 'messages', messages);
|
|
122
|
-
// return this.cleanUp(response, messages);
|
|
123
132
|
};
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
133
|
+
// ---------------------------
|
|
134
|
+
pushToKey = async (message) => {
|
|
135
|
+
const originatingAccountId = MemKey_AccountId.get();
|
|
136
|
+
const messageLength = JSON.stringify(message).length;
|
|
137
|
+
if (messageLength > this.config.messageLengthLimit)
|
|
138
|
+
throw HttpCodes._4XX.BAD_REQUEST(`Message content too long, ${messageLength} > ${this.config.messageLengthLimit}`);
|
|
139
|
+
const messageSubscription = { topic: message.topic, props: message.filter };
|
|
140
|
+
const newVar = async (transaction) => {
|
|
141
|
+
let subscriptions = await ModuleBE_PushSubscriptionDB.query.where({ topic: message.topic }, transaction);
|
|
142
|
+
this.logVerbose(`Found ${subscriptions.length} subscribers for message: `, messageSubscription);
|
|
143
|
+
if (message.filter)
|
|
144
|
+
subscriptions = subscriptions.filter(subscription => !subscription.filter || compare(subscription.filter, message.filter));
|
|
145
|
+
if (subscriptions.length === 0)
|
|
146
|
+
return this.logDebug('No subscribers match message: ', message);
|
|
147
|
+
const sessionsIds = subscriptions.map(d => d.pushSessionId);
|
|
148
|
+
// I get the tokens relative to those sessions (query)
|
|
149
|
+
this.logDebug(`Sending push to:`, ` -- Sessions:`, sessionsIds, ` -- Message: `, message);
|
|
150
|
+
const pushSessions = await batchActionParallel(sessionsIds, 10, async (elements) => ModuleBE_PushSessionDB.query.where({ pushSessionId: { $in: elements } }, transaction));
|
|
151
|
+
const map_sessionIdToSession = arrayToMap(pushSessions, session => session.pushSessionId);
|
|
152
|
+
subscriptions = subscriptions.filter(subscription => map_sessionIdToSession[subscription.pushSessionId]);
|
|
153
|
+
const messagesToCreate = subscriptions.map((subscription) => {
|
|
154
|
+
return {
|
|
155
|
+
pushSessionId: subscription.pushSessionId,
|
|
156
|
+
token: map_sessionIdToSession[subscription.pushSessionId].firebaseToken,
|
|
157
|
+
message: message,
|
|
158
|
+
read: false,
|
|
159
|
+
originatingAccountId
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
if (messagesToCreate.length === 0)
|
|
163
|
+
return this.logDebug('No subscribers match message: ', message);
|
|
164
|
+
const dbMessages = await ModuleBE_PushMessagesHistoryDB.create.all(messagesToCreate);
|
|
165
|
+
const messagesToSend = dbMessages.map(dbMessage => {
|
|
166
|
+
const messageBody = {
|
|
167
|
+
_id: dbMessage._id,
|
|
168
|
+
timestamp: dbMessage.__created,
|
|
169
|
+
message: dbMessage.message,
|
|
170
|
+
topic: message.topic,
|
|
171
|
+
filter: message.filter,
|
|
172
|
+
};
|
|
173
|
+
const data = {
|
|
174
|
+
sessionId: dbMessage.pushSessionId,
|
|
175
|
+
payload: JSON.stringify(messageBody)
|
|
176
|
+
};
|
|
177
|
+
return {
|
|
178
|
+
token: dbMessage.token,
|
|
179
|
+
data: data
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
const { response, messages } = await this.sendMessage(messagesToSend);
|
|
183
|
+
this.logInfo(`${response.successCount} sent, ${response.failureCount} failed`, 'messages', messages);
|
|
184
|
+
// return this.cleanUp(response, messages);
|
|
185
|
+
};
|
|
186
|
+
return ModuleBE_PushSubscriptionDB.runTransaction(newVar);
|
|
170
187
|
};
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const docs = await ModuleBE_PushSessionDB.query.where({ timestamp: { $lt: currentTimeMillis() - sessionsCleanupTime } });
|
|
175
|
-
await Promise.all([
|
|
176
|
-
this.cleanUpImpl(docs.map(d => d.firebaseToken))
|
|
177
|
-
]);
|
|
178
|
-
};
|
|
179
|
-
cleanUp = async (response) => {
|
|
180
|
-
this.logInfo(`${response.successCount} sent, ${response.failureCount} failed`);
|
|
181
|
-
if (response.failureCount > 0)
|
|
182
|
-
this.logWarning(response.responses.filter(r => r.error));
|
|
183
|
-
// const toDelete = response.responses.reduce((carry, resp, i) => {
|
|
184
|
-
// if (!resp.success && messages[i])
|
|
185
|
-
// carry.push(messages[i].token);
|
|
188
|
+
// async pushToUser<MessageType extends PushMessage<any, any, any>>(accountId: string, message: MessageType) {
|
|
189
|
+
// const notification = this.buildNotification(message);
|
|
190
|
+
// this.logInfo(`Account ${notification.originatingAccountId} is pushing to user ${accountId}`, message.filter);
|
|
186
191
|
//
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
192
|
+
// const docs = await ModuleBE_PushSessionDB.query.where({accountId});
|
|
193
|
+
// if (docs.length === 0)
|
|
194
|
+
// return;
|
|
195
|
+
//
|
|
196
|
+
// const sessionsIds = docs.map(d => d.pushSessionId);
|
|
197
|
+
// const sessions = await batchActionParallel(sessionsIds, 10, async elements =>
|
|
198
|
+
// ModuleBE_PushSessionDB.query.where({pushSessionId: {$in: elements}}));
|
|
199
|
+
//
|
|
200
|
+
// const _messages = docs.reduce((carry: TempMessages, db_topic) => {
|
|
201
|
+
// const session = sessions.find(s => s.pushSessionId === db_topic.pushSessionId);
|
|
202
|
+
// if (!session)
|
|
203
|
+
// return carry;
|
|
204
|
+
//
|
|
205
|
+
// carry[session.firebaseToken] = [notification];
|
|
206
|
+
//
|
|
207
|
+
// return carry;
|
|
208
|
+
// }, {} as TempMessages);
|
|
209
|
+
//
|
|
210
|
+
// await this.sendMessage(_messages);
|
|
211
|
+
// }
|
|
212
|
+
// private buildNotification<MessageType extends PushMessage<any, any, any>>(message: MessageType) {
|
|
213
|
+
// const originatingAccountId = MemKey_AccountId.get();
|
|
214
|
+
//
|
|
215
|
+
// return {
|
|
216
|
+
// message: JSON.stringify(message),
|
|
217
|
+
// read: false,
|
|
218
|
+
// originatingAccountId
|
|
219
|
+
// };
|
|
220
|
+
// }
|
|
221
|
+
sendMessage = async (messages) => {
|
|
222
|
+
this.logInfo('sending a message to \n' + Object.keys(messages).join('\n'));
|
|
223
|
+
const response = await this.messaging.sendAll(messages);
|
|
224
|
+
this.logInfo('and this is the response: ' + response.responses.map(_response => _response.success));
|
|
225
|
+
return { response, messages };
|
|
226
|
+
};
|
|
227
|
+
__onCleanupSchedulerAct = () => {
|
|
228
|
+
return {
|
|
229
|
+
cleanup: this.scheduledCleanup,
|
|
230
|
+
interval: Day,
|
|
231
|
+
moduleKey: this.getName()
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
scheduledCleanup = async () => {
|
|
235
|
+
const sessionsCleanupTime = this.config?.sessionsCleanupTime || Day;
|
|
236
|
+
const docs = await ModuleBE_PushSessionDB.query.where({ timestamp: { $lt: currentTimeMillis() - sessionsCleanupTime } });
|
|
237
|
+
await Promise.all([
|
|
238
|
+
this.cleanUpImpl(docs.map(d => d.firebaseToken))
|
|
239
|
+
]);
|
|
240
|
+
};
|
|
241
|
+
cleanUp = async (response) => {
|
|
242
|
+
this.logInfo(`${response.successCount} sent, ${response.failureCount} failed`);
|
|
243
|
+
if (response.failureCount > 0)
|
|
244
|
+
this.logWarning(response.responses.filter(r => r.error));
|
|
245
|
+
// const toDelete = response.responses.reduce((carry, resp, i) => {
|
|
246
|
+
// if (!resp.success && messages[i])
|
|
247
|
+
// carry.push(messages[i].token);
|
|
248
|
+
//
|
|
249
|
+
// return carry;
|
|
250
|
+
// }, [] as string[]);
|
|
251
|
+
//TODO: delete notifications for the user that are older than X
|
|
252
|
+
// return this.cleanUpImpl(toDelete); <== THIS WAS THE PROBLEM!!
|
|
253
|
+
};
|
|
254
|
+
async cleanUpImpl(_toDelete) {
|
|
255
|
+
if (_toDelete.length === 0)
|
|
256
|
+
return;
|
|
257
|
+
const toDelete = filterDuplicates(_toDelete);
|
|
258
|
+
const _sessions = await batchActionParallel(toDelete, 10, async (elements) => ModuleBE_PushSessionDB.query.where({ firebaseToken: { $in: elements } }));
|
|
259
|
+
const sessions = filterDuplicates(_sessions.map(s => s.pushSessionId));
|
|
260
|
+
const async = [
|
|
261
|
+
batchActionParallel(toDelete, 10, async (elements) => ModuleBE_PushSessionDB.query.where({ firebaseToken: { $in: elements } })),
|
|
262
|
+
batchActionParallel(sessions, 10, async (elements) => ModuleBE_PushSubscriptionDB.delete.where({ pushSessionId: { $in: elements } }))
|
|
263
|
+
];
|
|
264
|
+
await Promise.all(async);
|
|
265
|
+
}
|
|
191
266
|
};
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return;
|
|
195
|
-
const toDelete = filterDuplicates(_toDelete);
|
|
196
|
-
const _sessions = await batchActionParallel(toDelete, 10, async (elements) => ModuleBE_PushSessionDB.query.where({ firebaseToken: { $in: elements } }));
|
|
197
|
-
const sessions = filterDuplicates(_sessions.map(s => s.pushSessionId));
|
|
198
|
-
const async = [
|
|
199
|
-
batchActionParallel(toDelete, 10, async (elements) => ModuleBE_PushSessionDB.query.where({ firebaseToken: { $in: elements } })),
|
|
200
|
-
batchActionParallel(sessions, 10, async (elements) => ModuleBE_PushSubscriptionDB.delete.where({ pushSessionId: { $in: elements } }))
|
|
201
|
-
];
|
|
202
|
-
await Promise.all(async);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
267
|
+
})();
|
|
268
|
+
export { ModuleBE_PushPubSub_Class };
|
|
205
269
|
export const ModuleBE_PushPubSub = new ModuleBE_PushPubSub_Class();
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export declare class ModuleBE_PushSessionDB_Class extends ModuleBE_BaseDB<
|
|
1
|
+
import type { DB_Prototype } from '@nu-art/db-api-shared';
|
|
2
|
+
import { ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
3
|
+
import { DatabaseDef_PushSession } from '@nu-art/push-pub-sub-shared/push-session/index';
|
|
4
|
+
export declare class ModuleBE_PushSessionDB_Class extends ModuleBE_BaseDB<DatabaseDef_PushSession & DB_Prototype, object> {
|
|
5
5
|
constructor();
|
|
6
6
|
}
|
|
7
7
|
export declare const ModuleBE_PushSessionDB: ModuleBE_PushSessionDB_Class;
|
|
8
|
-
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ModuleBE_BaseDB
|
|
1
|
+
import { ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
2
2
|
import { DBDef_PushSession } from '@nu-art/push-pub-sub-shared/push-session/index';
|
|
3
3
|
export class ModuleBE_PushSessionDB_Class extends ModuleBE_BaseDB {
|
|
4
4
|
constructor() {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export declare class ModuleBE_PushSubscriptionDB_Class extends ModuleBE_BaseDB<
|
|
1
|
+
import type { DB_Prototype } from '@nu-art/db-api-shared';
|
|
2
|
+
import { ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
3
|
+
import { DatabaseDef_PushSubscription } from '@nu-art/push-pub-sub-shared/push-subscription/index';
|
|
4
|
+
export declare class ModuleBE_PushSubscriptionDB_Class extends ModuleBE_BaseDB<DatabaseDef_PushSubscription & DB_Prototype, object> {
|
|
5
5
|
constructor();
|
|
6
6
|
}
|
|
7
7
|
export declare const ModuleBE_PushSubscriptionDB: ModuleBE_PushSubscriptionDB_Class;
|
|
8
|
-
export declare const ModuleBE_PushSubscriptionAPI: import("@nu-art/
|
|
9
|
-
export {};
|
|
8
|
+
export declare const ModuleBE_PushSubscriptionAPI: import("@nu-art/db-api-backend").ModuleBE_BaseApi_Class<DatabaseDef_PushSubscription & DB_Prototype>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createApisForDBModule, ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
2
2
|
import { DBDef_PushSubscription } from '@nu-art/push-pub-sub-shared/push-subscription/index';
|
|
3
3
|
export class ModuleBE_PushSubscriptionDB_Class extends ModuleBE_BaseDB {
|
|
4
4
|
constructor() {
|
|
@@ -6,4 +6,4 @@ export class ModuleBE_PushSubscriptionDB_Class extends ModuleBE_BaseDB {
|
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
export const ModuleBE_PushSubscriptionDB = new ModuleBE_PushSubscriptionDB_Class();
|
|
9
|
-
export const ModuleBE_PushSubscriptionAPI =
|
|
9
|
+
export const ModuleBE_PushSubscriptionAPI = createApisForDBModule(ModuleBE_PushSubscriptionDB);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nu-art/push-pub-sub-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.500.0",
|
|
4
4
|
"description": "push-pub-sub Backend",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"TacB0sS",
|
|
@@ -21,20 +21,19 @@
|
|
|
21
21
|
},
|
|
22
22
|
"license": "Apache-2.0",
|
|
23
23
|
"author": "TacB0sS",
|
|
24
|
-
"scripts": {
|
|
25
|
-
"build": "tsc -b -f"
|
|
26
|
-
},
|
|
24
|
+
"scripts": {},
|
|
27
25
|
"dependencies": {
|
|
28
|
-
"@nu-art/push-pub-sub-shared": "0.
|
|
29
|
-
"@nu-art/firebase-backend": "0.
|
|
30
|
-
"@nu-art/firebase-shared": "0.
|
|
31
|
-
"@nu-art/permissions-backend": "0.
|
|
32
|
-
"@nu-art/permissions-shared": "0.
|
|
33
|
-
"@nu-art/
|
|
34
|
-
"@nu-art/
|
|
35
|
-
"@nu-art/
|
|
36
|
-
"@nu-art/
|
|
37
|
-
"@nu-art/user-account-
|
|
26
|
+
"@nu-art/push-pub-sub-shared": "0.500.0",
|
|
27
|
+
"@nu-art/firebase-backend": "0.500.0",
|
|
28
|
+
"@nu-art/firebase-shared": "0.500.0",
|
|
29
|
+
"@nu-art/permissions-backend": "0.500.0",
|
|
30
|
+
"@nu-art/permissions-shared": "0.500.0",
|
|
31
|
+
"@nu-art/db-api-backend": "0.500.0",
|
|
32
|
+
"@nu-art/db-api-shared": "0.500.0",
|
|
33
|
+
"@nu-art/http-server": "{{THUNDERSTORM_VERSION}}",
|
|
34
|
+
"@nu-art/ts-common": "0.500.0",
|
|
35
|
+
"@nu-art/user-account-backend": "0.500.0",
|
|
36
|
+
"@nu-art/user-account-shared": "0.500.0",
|
|
38
37
|
"firebase": "^11.9.0",
|
|
39
38
|
"firebase-admin": "13.4.0",
|
|
40
39
|
"moment": "^2.29.4",
|