active-connect-ng2 0.2.39 → 0.2.41
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/ng-package.json +7 -0
- package/package.json +13 -32
- package/src/lib/active-connect-ng2.module.ts +34 -0
- package/src/lib/websocket/client.ts +438 -0
- package/src/lib/websocket/decorators/function.ts +44 -0
- package/src/lib/websocket/decorators/websocket/handle.ts +12 -0
- package/src/lib/websocket/decorators/websocket/on-reconnect.ts +6 -0
- package/src/lib/websocket/decorators/websocket/on-success.ts +11 -0
- package/src/lib/websocket/decorators/websocket/outbound.ts +212 -0
- package/src/lib/websocket/decorators/websocket/route.ts +32 -0
- package/src/lib/websocket/decorators/websocket/shared.ts +11 -0
- package/{lib/websocket/decorators/websocket/websocket-route-service.d.ts → src/lib/websocket/decorators/websocket/websocket-route-service.ts} +3 -2
- package/src/lib/websocket/json/json-parser.ts +26 -0
- package/src/lib/websocket/lifecycle/loading-status.ts +32 -0
- package/src/lib/websocket/objects/outbound-object.ts +430 -0
- package/{public-api.d.ts → src/public-api.ts} +4 -0
- package/tsconfig.lib.json +14 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +14 -0
- package/esm2020/active-connect-ng2.mjs +0 -5
- package/esm2020/lib/active-connect-ng2.module.mjs +0 -42
- package/esm2020/lib/websocket/client.mjs +0 -345
- package/esm2020/lib/websocket/decorators/function.mjs +0 -40
- package/esm2020/lib/websocket/decorators/websocket/handle.mjs +0 -9
- package/esm2020/lib/websocket/decorators/websocket/on-reconnect.mjs +0 -6
- package/esm2020/lib/websocket/decorators/websocket/on-success.mjs +0 -8
- package/esm2020/lib/websocket/decorators/websocket/outbound.mjs +0 -213
- package/esm2020/lib/websocket/decorators/websocket/route.mjs +0 -31
- package/esm2020/lib/websocket/decorators/websocket/shared.mjs +0 -10
- package/esm2020/lib/websocket/decorators/websocket/websocket-route-service.mjs +0 -2
- package/esm2020/lib/websocket/index.mjs +0 -11
- package/esm2020/lib/websocket/json/json-parser.mjs +0 -23
- package/esm2020/lib/websocket/lifecycle/loading-status.mjs +0 -31
- package/esm2020/lib/websocket/objects/outbound-object.mjs +0 -398
- package/esm2020/public-api.mjs +0 -7
- package/fesm2015/active-connect-ng2.mjs +0 -1176
- package/fesm2015/active-connect-ng2.mjs.map +0 -1
- package/fesm2020/active-connect-ng2.mjs +0 -1158
- package/fesm2020/active-connect-ng2.mjs.map +0 -1
- package/index.d.ts +0 -5
- package/lib/active-connect-ng2.module.d.ts +0 -7
- package/lib/websocket/client.d.ts +0 -59
- package/lib/websocket/decorators/function.d.ts +0 -30
- package/lib/websocket/decorators/websocket/handle.d.ts +0 -1
- package/lib/websocket/decorators/websocket/on-reconnect.d.ts +0 -1
- package/lib/websocket/decorators/websocket/on-success.d.ts +0 -1
- package/lib/websocket/decorators/websocket/outbound.d.ts +0 -1
- package/lib/websocket/decorators/websocket/route.d.ts +0 -1
- package/lib/websocket/decorators/websocket/shared.d.ts +0 -4
- package/lib/websocket/json/json-parser.d.ts +0 -5
- package/lib/websocket/lifecycle/loading-status.d.ts +0 -9
- package/lib/websocket/objects/outbound-object.d.ts +0 -48
- /package/{lib/websocket/index.d.ts → src/lib/websocket/index.ts} +0 -0
package/ng-package.json
ADDED
package/package.json
CHANGED
|
@@ -1,32 +1,13 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "active-connect-ng2",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"peerDependencies": {
|
|
5
|
-
"@angular/common": "^15.1.0",
|
|
6
|
-
"@angular/core": "^15.1.0",
|
|
7
|
-
"ngx-indexed-db": "^16.0.0"
|
|
8
|
-
},
|
|
9
|
-
"dependencies": {
|
|
10
|
-
"tslib": "^2.3.0"
|
|
11
|
-
},
|
|
12
|
-
"sideEffects": false
|
|
13
|
-
|
|
14
|
-
"es2020": "fesm2020/active-connect-ng2.mjs",
|
|
15
|
-
"esm2020": "esm2020/active-connect-ng2.mjs",
|
|
16
|
-
"fesm2020": "fesm2020/active-connect-ng2.mjs",
|
|
17
|
-
"fesm2015": "fesm2015/active-connect-ng2.mjs",
|
|
18
|
-
"typings": "index.d.ts",
|
|
19
|
-
"exports": {
|
|
20
|
-
"./package.json": {
|
|
21
|
-
"default": "./package.json"
|
|
22
|
-
},
|
|
23
|
-
".": {
|
|
24
|
-
"types": "./index.d.ts",
|
|
25
|
-
"esm2020": "./esm2020/active-connect-ng2.mjs",
|
|
26
|
-
"es2020": "./fesm2020/active-connect-ng2.mjs",
|
|
27
|
-
"es2015": "./fesm2015/active-connect-ng2.mjs",
|
|
28
|
-
"node": "./fesm2015/active-connect-ng2.mjs",
|
|
29
|
-
"default": "./fesm2020/active-connect-ng2.mjs"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "active-connect-ng2",
|
|
3
|
+
"version": "0.2.41",
|
|
4
|
+
"peerDependencies": {
|
|
5
|
+
"@angular/common": "^15.1.0",
|
|
6
|
+
"@angular/core": "^15.1.0",
|
|
7
|
+
"ngx-indexed-db": "^16.0.0"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"tslib": "^2.3.0"
|
|
11
|
+
},
|
|
12
|
+
"sideEffects": false
|
|
13
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { NgxIndexedDBModule, DBConfig } from 'ngx-indexed-db';
|
|
3
|
+
|
|
4
|
+
const dbConfig: DBConfig = {
|
|
5
|
+
name: 'activeconnect_cache',
|
|
6
|
+
version: 2,
|
|
7
|
+
objectStoresMeta: [
|
|
8
|
+
{
|
|
9
|
+
store: 'outbound',
|
|
10
|
+
storeConfig: { keyPath: 'method', autoIncrement: false },
|
|
11
|
+
storeSchema: [
|
|
12
|
+
{ name: 'method', keypath: 'method', options: { unique: true } },
|
|
13
|
+
{ name: 'data', keypath: 'data', options: { unique: false } },
|
|
14
|
+
{
|
|
15
|
+
name: 'specificHash',
|
|
16
|
+
keypath: 'specificHash',
|
|
17
|
+
options: { unique: false },
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'length',
|
|
21
|
+
keypath: 'length',
|
|
22
|
+
options: { unique: false },
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
@NgModule({
|
|
30
|
+
declarations: [],
|
|
31
|
+
imports: [NgxIndexedDBModule.forRoot(dbConfig)],
|
|
32
|
+
exports: [NgxIndexedDBModule],
|
|
33
|
+
})
|
|
34
|
+
export class ActiveConnectNg2Module {}
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { NgxIndexedDBService } from 'ngx-indexed-db';
|
|
2
|
+
import { DecorableFunction } from './decorators/function';
|
|
3
|
+
import { JsonParser } from './json/json-parser';
|
|
4
|
+
|
|
5
|
+
export class WebsocketClient {
|
|
6
|
+
ws!: WebSocket;
|
|
7
|
+
pool!: { WssConnected: boolean } | null;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
private url?: string,
|
|
11
|
+
private supportsCache?: boolean,
|
|
12
|
+
public dbService?: NgxIndexedDBService
|
|
13
|
+
) {
|
|
14
|
+
if (supportsCache) this.initCache();
|
|
15
|
+
this.setUrl(this.url);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
protected setUrl(url: string | undefined) {
|
|
19
|
+
if (!url) {
|
|
20
|
+
let protocol;
|
|
21
|
+
let port;
|
|
22
|
+
switch (document.location.protocol) {
|
|
23
|
+
case 'https:': {
|
|
24
|
+
protocol = 'wss:';
|
|
25
|
+
port = ':443';
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
default: {
|
|
29
|
+
protocol = 'ws:';
|
|
30
|
+
port = ':80';
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
url = protocol + '//' + document.location.hostname + port + '/wss';
|
|
35
|
+
}
|
|
36
|
+
this.url = url;
|
|
37
|
+
this.disconnect();
|
|
38
|
+
this.connect(this.url as string);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
subject: any;
|
|
42
|
+
|
|
43
|
+
private connect(url: string) {
|
|
44
|
+
if (!this.subject) {
|
|
45
|
+
this.create(url);
|
|
46
|
+
}
|
|
47
|
+
return this.subject;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public initTabSuspendedListener() {
|
|
51
|
+
if (document) {
|
|
52
|
+
document.addEventListener('visibilitychange', () => {
|
|
53
|
+
if (document.visibilityState === 'hidden') {
|
|
54
|
+
console.log(
|
|
55
|
+
'ActiveConnect: Closing WebSocket due to tab suspension...'
|
|
56
|
+
);
|
|
57
|
+
this.disconnect(true);
|
|
58
|
+
} else if (document.visibilityState === 'visible') {
|
|
59
|
+
console.log('ActiveConnect: Reconnecting WebSocket...');
|
|
60
|
+
this.connect(this.url as string);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private requestStack: any[] = [];
|
|
67
|
+
private requestHistoryLogs: { timestamp: Date; method: string }[] = [];
|
|
68
|
+
private logEntry(method: string) {
|
|
69
|
+
this.requestHistoryLogs.push({ timestamp: new Date(Date.now()), method });
|
|
70
|
+
}
|
|
71
|
+
public get logs(): { timestamp: Date; method: string }[] {
|
|
72
|
+
return this.requestHistoryLogs;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private _token = '';
|
|
76
|
+
public get Token(): string {
|
|
77
|
+
if (!this._token) {
|
|
78
|
+
if (window.localStorage)
|
|
79
|
+
this._token = window.localStorage.getItem('token') || '';
|
|
80
|
+
}
|
|
81
|
+
return this._token;
|
|
82
|
+
}
|
|
83
|
+
public set Token(val: string) {
|
|
84
|
+
this._token = val;
|
|
85
|
+
if (window.localStorage) window.localStorage.setItem('token', val);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private set Connected(value: boolean) {
|
|
89
|
+
if (value) {
|
|
90
|
+
this.sendBrowserInfoToServer();
|
|
91
|
+
|
|
92
|
+
this.auth(this.Token).then(() => {
|
|
93
|
+
Promise.all(
|
|
94
|
+
WebsocketClient.onReconnectCallback.map((c) =>
|
|
95
|
+
c.Func ? c.Func() : null
|
|
96
|
+
)
|
|
97
|
+
).then(() => {
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
this.resetRequestedState();
|
|
100
|
+
this.requestStack.forEach((e) => {
|
|
101
|
+
this.sendToSocket(e.method, e.data);
|
|
102
|
+
this.requestStack = this.requestStack.filter((e1) => e1 != e);
|
|
103
|
+
});
|
|
104
|
+
}, 2000);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
if (this.pool && this.pool.WssConnected) this.pool.WssConnected = value;
|
|
109
|
+
}
|
|
110
|
+
private static resetRequestedStateCallbacks: Function[] = [];
|
|
111
|
+
private connectionEstablishedOnce: boolean = false;
|
|
112
|
+
private resetRequestedState() {
|
|
113
|
+
if (this.connectionEstablishedOnce) {
|
|
114
|
+
// reset requested state for outbounds
|
|
115
|
+
WebsocketClient.resetRequestedStateCallbacks.forEach((reset) => {
|
|
116
|
+
reset();
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
this.connectionEstablishedOnce = true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
public static addResetRequestingStateCallback(callback: Function) {
|
|
123
|
+
WebsocketClient.resetRequestedStateCallbacks.push(callback);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private create(url: string) {
|
|
127
|
+
// create new connection
|
|
128
|
+
this.logEntry('TCP/HTTP:CONNECT-SERVER');
|
|
129
|
+
this.ws = new WebSocket(url + (this.supportsCache ? '?cache=true' : ''));
|
|
130
|
+
this.ws.onerror = (err) => {
|
|
131
|
+
this.ws.close();
|
|
132
|
+
this.logEntry('TCP/HTTP:ERROR:' + err);
|
|
133
|
+
console.log('ActiveConnect: ' + err);
|
|
134
|
+
};
|
|
135
|
+
this.ws.onopen = () => {
|
|
136
|
+
this.logEntry('TCP/HTTP:CONNECTED');
|
|
137
|
+
this.Connected = true;
|
|
138
|
+
};
|
|
139
|
+
this.ws.onmessage = (e) => {
|
|
140
|
+
this.messageReceived(JsonParser.parse(e.data.toString()));
|
|
141
|
+
};
|
|
142
|
+
this.ws.onclose = () => {
|
|
143
|
+
this.logEntry('TCP/HTTP:CLOSED');
|
|
144
|
+
if (!this.closed) {
|
|
145
|
+
if (this.pool && this.pool.WssConnected) this.pool.WssConnected = false;
|
|
146
|
+
this.logEntry('TCP/HTTP:RESET-REQUESTED-OUTBOUND-STATE');
|
|
147
|
+
this.resetRequestedState();
|
|
148
|
+
setTimeout(() => {
|
|
149
|
+
this.connect(url);
|
|
150
|
+
}, 1000);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private messageId: number = 0;
|
|
156
|
+
protected sendToSocket(
|
|
157
|
+
method: string,
|
|
158
|
+
data: any,
|
|
159
|
+
dontEnsureTransmission?: boolean
|
|
160
|
+
) {
|
|
161
|
+
const messageId = ++this.messageId;
|
|
162
|
+
if (this.ws.readyState != this.ws.OPEN) {
|
|
163
|
+
if (!dontEnsureTransmission)
|
|
164
|
+
this.requestStack.push({ method, data, messageId });
|
|
165
|
+
else return false;
|
|
166
|
+
} else {
|
|
167
|
+
this.ws.send(JsonParser.stringify({ method, value: data, messageId }));
|
|
168
|
+
}
|
|
169
|
+
return messageId;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async auth(token: string): Promise<any> {
|
|
173
|
+
return this.sendToSocket('auth.token', token);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public send(
|
|
177
|
+
method: string,
|
|
178
|
+
data: any,
|
|
179
|
+
dontEnsureTransmission?: boolean
|
|
180
|
+
): Promise<any> {
|
|
181
|
+
this.logEntry('SEND:' + method);
|
|
182
|
+
const messageId = this.sendToSocket(
|
|
183
|
+
method,
|
|
184
|
+
data,
|
|
185
|
+
dontEnsureTransmission || false
|
|
186
|
+
);
|
|
187
|
+
if (messageId) {
|
|
188
|
+
return this.expectMethod(`m.${method}`, messageId);
|
|
189
|
+
} else {
|
|
190
|
+
return new Promise((resolve) => {
|
|
191
|
+
resolve(false);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private rejectCallbacks: Map<number, Function> = new Map();
|
|
197
|
+
private expectedMethods: Map<string | number, Array<Function>> = new Map();
|
|
198
|
+
private expectMethod(method: string, messageId?: number | null) {
|
|
199
|
+
return new Promise((resolve, reject) => {
|
|
200
|
+
if (messageId) {
|
|
201
|
+
this.expectedMethods.set(messageId, [resolve]);
|
|
202
|
+
this.rejectCallbacks.set(messageId, reject);
|
|
203
|
+
} else {
|
|
204
|
+
if (this.expectedMethods.has(method)) {
|
|
205
|
+
let arr = this.expectedMethods.get(method);
|
|
206
|
+
(arr as Array<Function>).push(resolve);
|
|
207
|
+
} else {
|
|
208
|
+
this.expectedMethods.set(method, [resolve]);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private messageReceived({
|
|
215
|
+
method,
|
|
216
|
+
value,
|
|
217
|
+
messageId,
|
|
218
|
+
specificHash,
|
|
219
|
+
inserted,
|
|
220
|
+
updated,
|
|
221
|
+
deleted,
|
|
222
|
+
length,
|
|
223
|
+
}: {
|
|
224
|
+
method: string;
|
|
225
|
+
value: any;
|
|
226
|
+
messageId: number | null;
|
|
227
|
+
specificHash: number | null;
|
|
228
|
+
inserted: any[] | null;
|
|
229
|
+
updated: any[] | null;
|
|
230
|
+
deleted: any[] | null;
|
|
231
|
+
length: number | null;
|
|
232
|
+
}) {
|
|
233
|
+
this.logEntry('RECEIVED:' + method);
|
|
234
|
+
if (method == '___cache') {
|
|
235
|
+
this.handleOutboundCacheRequest(value);
|
|
236
|
+
}
|
|
237
|
+
if (messageId) {
|
|
238
|
+
if (method == 'm.error') {
|
|
239
|
+
const reject = this.rejectCallbacks.get(messageId);
|
|
240
|
+
if (reject) {
|
|
241
|
+
reject(value);
|
|
242
|
+
}
|
|
243
|
+
messageId = -1;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (messageId != null) {
|
|
248
|
+
const callback = this.expectedMethods.get(messageId);
|
|
249
|
+
if (callback) {
|
|
250
|
+
const func = callback.shift();
|
|
251
|
+
if (func) func(value);
|
|
252
|
+
this.invokeSuccessHandlers(method);
|
|
253
|
+
} else {
|
|
254
|
+
const callback = this.expectedMethods.get(method);
|
|
255
|
+
if (callback && callback.length > 0) {
|
|
256
|
+
const func = callback.shift();
|
|
257
|
+
if (func) func(value);
|
|
258
|
+
} else {
|
|
259
|
+
const out = WebsocketClient.outbounds.get(method);
|
|
260
|
+
if (out) {
|
|
261
|
+
out(value, specificHash, inserted, updated, deleted, length, this);
|
|
262
|
+
}
|
|
263
|
+
const handle = WebsocketClient.handles.get(method);
|
|
264
|
+
if (handle) {
|
|
265
|
+
(handle.Func as Function)(value);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
throw Error(
|
|
271
|
+
'No MessageId was provided, the connection is not supported.'
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
private handleOutboundCacheRequest(method: string) {
|
|
277
|
+
if (this.dbService) {
|
|
278
|
+
try {
|
|
279
|
+
this.dbService.getByKey('outbound', method).subscribe((item: any) => {
|
|
280
|
+
if (item) {
|
|
281
|
+
this.send('___cache', {
|
|
282
|
+
method,
|
|
283
|
+
specificHash: item.specificHash || null,
|
|
284
|
+
});
|
|
285
|
+
} else {
|
|
286
|
+
this.send('___cache', {
|
|
287
|
+
method,
|
|
288
|
+
specificHash: null,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
} catch (e) {
|
|
293
|
+
this.send('___cache', {
|
|
294
|
+
method,
|
|
295
|
+
specificHash: null,
|
|
296
|
+
});
|
|
297
|
+
console.error('ActiveConnect: ' + e);
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
this.send('___cache', {
|
|
301
|
+
method,
|
|
302
|
+
specificHash: null,
|
|
303
|
+
});
|
|
304
|
+
console.error(
|
|
305
|
+
'Active-Connect: Caching not possible as the indexedDB has not been initialized'
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private static outbounds: Map<
|
|
311
|
+
string,
|
|
312
|
+
(
|
|
313
|
+
data: any,
|
|
314
|
+
specificHash: number | null,
|
|
315
|
+
inserted: any[] | null,
|
|
316
|
+
updated: any[] | null,
|
|
317
|
+
deleted: any[] | null,
|
|
318
|
+
length: number | null,
|
|
319
|
+
_this: WebsocketClient
|
|
320
|
+
) => void
|
|
321
|
+
> = new Map();
|
|
322
|
+
static expectOutbound(
|
|
323
|
+
method: string,
|
|
324
|
+
callback: (
|
|
325
|
+
data: any,
|
|
326
|
+
specificHash: number | null,
|
|
327
|
+
inserted: any[] | null,
|
|
328
|
+
updated: any[] | null,
|
|
329
|
+
deleted: any[] | null,
|
|
330
|
+
length: number | null,
|
|
331
|
+
_this: WebsocketClient
|
|
332
|
+
) => void
|
|
333
|
+
) {
|
|
334
|
+
WebsocketClient.outbounds.set(method, callback);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
private static handles: Map<string, DecorableFunction> = new Map();
|
|
338
|
+
static registerHandle(method: string, callback: DecorableFunction) {
|
|
339
|
+
WebsocketClient.handles.set(method, callback);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
public get isConnected(): boolean {
|
|
343
|
+
if (this.ws) return this.ws.readyState == WebSocket.OPEN;
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private sendBrowserInfoToServer() {
|
|
348
|
+
// send browser / os information
|
|
349
|
+
const browser = this.getBrowser();
|
|
350
|
+
const os = this.getOS();
|
|
351
|
+
this.send('___browser', {
|
|
352
|
+
browser: `${browser.name} ${browser.version} ${os}`,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
public getBrowser(): { name: string; version: string } {
|
|
357
|
+
// https://www.gregoryvarghese.com/how-to-get-browser-name-and-version-via-javascript/
|
|
358
|
+
var ua = navigator.userAgent,
|
|
359
|
+
tem,
|
|
360
|
+
M =
|
|
361
|
+
ua.match(
|
|
362
|
+
/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i
|
|
363
|
+
) || [];
|
|
364
|
+
if (/trident/i.test(M[1])) {
|
|
365
|
+
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
|
|
366
|
+
return { name: 'IE ', version: tem[1] || '' };
|
|
367
|
+
}
|
|
368
|
+
if (M[1] === 'Chrome') {
|
|
369
|
+
tem = ua.match(/\bOPR\/(\d+)/);
|
|
370
|
+
if (tem != null) {
|
|
371
|
+
return { name: 'Opera', version: tem[1] };
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
|
|
375
|
+
if ((tem = ua.match(/version\/(\d+)/i)) != null) {
|
|
376
|
+
M.splice(1, 1, tem[1]);
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
name: M[0],
|
|
380
|
+
version: M[1],
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
public getOS(): string {
|
|
385
|
+
var userAgent = window.navigator.userAgent,
|
|
386
|
+
platform = window.navigator.platform,
|
|
387
|
+
macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'],
|
|
388
|
+
windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'],
|
|
389
|
+
iosPlatforms = ['iPhone', 'iPad', 'iPod'],
|
|
390
|
+
os = null;
|
|
391
|
+
|
|
392
|
+
if (macosPlatforms.indexOf(platform) !== -1) {
|
|
393
|
+
os = 'Mac OS';
|
|
394
|
+
} else if (iosPlatforms.indexOf(platform) !== -1) {
|
|
395
|
+
os = 'iOS';
|
|
396
|
+
} else if (windowsPlatforms.indexOf(platform) !== -1) {
|
|
397
|
+
os = 'Windows';
|
|
398
|
+
} else if (/Android/.test(userAgent)) {
|
|
399
|
+
os = 'Android';
|
|
400
|
+
} else if (!os && /Linux/.test(platform)) {
|
|
401
|
+
os = 'Linux';
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return os || '';
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
private static onSuccessHandlers: {
|
|
408
|
+
callback: DecorableFunction;
|
|
409
|
+
regexp: RegExp;
|
|
410
|
+
}[] = [];
|
|
411
|
+
public static onSuccess(callback: DecorableFunction, regexp: RegExp) {
|
|
412
|
+
this.onSuccessHandlers.push({ callback, regexp });
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
private static onReconnectCallback: DecorableFunction[] = [];
|
|
416
|
+
static onReconnect(callback: DecorableFunction) {
|
|
417
|
+
WebsocketClient.onReconnectCallback.push(callback);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
private invokeSuccessHandlers(method: string) {
|
|
421
|
+
WebsocketClient.onSuccessHandlers
|
|
422
|
+
.filter((e) => e.regexp.test(method))
|
|
423
|
+
.forEach((e) => {
|
|
424
|
+
var res = (e.callback.Func as Function)();
|
|
425
|
+
if (res && res.then) {
|
|
426
|
+
res.then();
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
public closed = false;
|
|
432
|
+
public disconnect(restart?: boolean) {
|
|
433
|
+
if (!restart) this.closed = true;
|
|
434
|
+
this.ws.close();
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
private initCache() {}
|
|
438
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents the reference to an object method used for websocket routes and outbounds.
|
|
3
|
+
*/
|
|
4
|
+
export class DecorableFunction {
|
|
5
|
+
/**
|
|
6
|
+
* Creates an instance of DecorableFunction.
|
|
7
|
+
* @param objConfig - The configuration object for the object method.
|
|
8
|
+
* @param objConfig.target - The target object.
|
|
9
|
+
* @param objConfig.propertyKey - The property key of the target object.
|
|
10
|
+
*/
|
|
11
|
+
constructor(protected objConfig: { target: any; propertyKey: string }) {
|
|
12
|
+
// singelton service - fetch from angular
|
|
13
|
+
const prototype = this.objConfig.target.prototype || this.objConfig.target;
|
|
14
|
+
if (!prototype.___constructorOverridden) {
|
|
15
|
+
prototype.___constructorOverridden = true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Returns the decorated function.
|
|
21
|
+
* @returns - The decorated function.
|
|
22
|
+
*/
|
|
23
|
+
public get Func(): ((...data: any[]) => Promise<any> | any) | null {
|
|
24
|
+
if (
|
|
25
|
+
this.objConfig?.target &&
|
|
26
|
+
this.objConfig.target[this.objConfig.propertyKey]
|
|
27
|
+
) {
|
|
28
|
+
return this.objConfig.target[this.objConfig.propertyKey].bind(
|
|
29
|
+
this.getBindObject()
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Returns the bind object.
|
|
37
|
+
* @private
|
|
38
|
+
* @returns - The bind object.
|
|
39
|
+
*/
|
|
40
|
+
private getBindObject(): any {
|
|
41
|
+
const prototype = this.objConfig.target.prototype || this.objConfig.target;
|
|
42
|
+
return prototype.___data._obj;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { WebsocketClient } from '../../client';
|
|
2
|
+
import { DecorableFunction } from '../function';
|
|
3
|
+
|
|
4
|
+
export function Handle(method: string) {
|
|
5
|
+
return function _Handle(target: any, propertyKey: string): any {
|
|
6
|
+
// method annotation
|
|
7
|
+
WebsocketClient.registerHandle(
|
|
8
|
+
method,
|
|
9
|
+
new DecorableFunction({ target, propertyKey })
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { WebsocketClient } from '../../client';
|
|
2
|
+
import { DecorableFunction } from '../function';
|
|
3
|
+
|
|
4
|
+
export function OnSuccess(regexp: RegExp) {
|
|
5
|
+
return function _Route(target: any, propertyKey: string): any {
|
|
6
|
+
WebsocketClient.onSuccess(
|
|
7
|
+
new DecorableFunction({ target, propertyKey }),
|
|
8
|
+
regexp
|
|
9
|
+
);
|
|
10
|
+
};
|
|
11
|
+
}
|