@multiplayer-app/session-recorder-react-native 1.3.15 → 1.3.21
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/lib/module/config/constants.js +3 -0
- package/lib/module/config/constants.js.map +1 -1
- package/lib/module/config/defaults.js +5 -1
- package/lib/module/config/defaults.js.map +1 -1
- package/lib/module/config/session-recorder.js +5 -1
- package/lib/module/config/session-recorder.js.map +1 -1
- package/lib/module/otel/CrashBufferSpanProcessor.js +41 -0
- package/lib/module/otel/CrashBufferSpanProcessor.js.map +1 -0
- package/lib/module/otel/index.js +28 -9
- package/lib/module/otel/index.js.map +1 -1
- package/lib/module/patch/fetch.js +71 -11
- package/lib/module/patch/fetch.js.map +1 -1
- package/lib/module/recorder/index.js +15 -1
- package/lib/module/recorder/index.js.map +1 -1
- package/lib/module/services/api.service.js +24 -2
- package/lib/module/services/api.service.js.map +1 -1
- package/lib/module/services/crashBuffer.service.js +248 -0
- package/lib/module/services/crashBuffer.service.js.map +1 -0
- package/lib/module/services/socket.service.js +9 -2
- package/lib/module/services/socket.service.js.map +1 -1
- package/lib/module/session-recorder.js +152 -6
- package/lib/module/session-recorder.js.map +1 -1
- package/lib/module/types/session-recorder.js.map +1 -1
- package/lib/typescript/src/config/constants.d.ts +1 -0
- package/lib/typescript/src/config/constants.d.ts.map +1 -1
- package/lib/typescript/src/config/defaults.d.ts.map +1 -1
- package/lib/typescript/src/config/session-recorder.d.ts.map +1 -1
- package/lib/typescript/src/otel/CrashBufferSpanProcessor.d.ts +18 -0
- package/lib/typescript/src/otel/CrashBufferSpanProcessor.d.ts.map +1 -0
- package/lib/typescript/src/otel/index.d.ts +8 -0
- package/lib/typescript/src/otel/index.d.ts.map +1 -1
- package/lib/typescript/src/recorder/index.d.ts +8 -1
- package/lib/typescript/src/recorder/index.d.ts.map +1 -1
- package/lib/typescript/src/services/api.service.d.ts +27 -2
- package/lib/typescript/src/services/api.service.d.ts.map +1 -1
- package/lib/typescript/src/services/crashBuffer.service.d.ts +46 -0
- package/lib/typescript/src/services/crashBuffer.service.d.ts.map +1 -0
- package/lib/typescript/src/services/socket.service.d.ts +4 -3
- package/lib/typescript/src/services/socket.service.d.ts.map +1 -1
- package/lib/typescript/src/session-recorder.d.ts +8 -0
- package/lib/typescript/src/session-recorder.d.ts.map +1 -1
- package/lib/typescript/src/types/session-recorder.d.ts +18 -0
- package/lib/typescript/src/types/session-recorder.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/config/constants.ts +3 -0
- package/src/config/defaults.ts +5 -0
- package/src/config/session-recorder.ts +5 -0
- package/src/otel/CrashBufferSpanProcessor.ts +61 -0
- package/src/otel/index.ts +90 -34
- package/src/patch/fetch.ts +73 -11
- package/src/recorder/index.ts +30 -3
- package/src/services/api.service.ts +68 -13
- package/src/services/crashBuffer.service.ts +327 -0
- package/src/services/socket.service.ts +36 -22
- package/src/session-recorder.ts +226 -19
- package/src/types/session-recorder.ts +18 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import type {
|
|
3
|
+
CrashBufferEventMap,
|
|
4
|
+
CrashBufferEventName,
|
|
5
|
+
CrashBufferErrorSpanAppendedEvent,
|
|
6
|
+
CrashBuffer,
|
|
7
|
+
} from '@multiplayer-app/session-recorder-common';
|
|
8
|
+
import { SpanStatusCode } from '@opentelemetry/api';
|
|
9
|
+
|
|
10
|
+
// Safe import for AsyncStorage with web fallback
|
|
11
|
+
let AsyncStorage: any = null;
|
|
12
|
+
const isWeb = Platform.OS === 'web';
|
|
13
|
+
|
|
14
|
+
if (!isWeb) {
|
|
15
|
+
try {
|
|
16
|
+
AsyncStorage = require('@react-native-async-storage/async-storage').default;
|
|
17
|
+
} catch (_error) {
|
|
18
|
+
AsyncStorage = null;
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
AsyncStorage = {
|
|
22
|
+
getItem: (_key: string) => Promise.resolve(null),
|
|
23
|
+
setItem: (_key: string, _value: string) => Promise.resolve(undefined),
|
|
24
|
+
removeItem: (_key: string) => Promise.resolve(undefined),
|
|
25
|
+
multiRemove: (_keys: string[]) => Promise.resolve(undefined),
|
|
26
|
+
multiGet: (_keys: string[]) => Promise.resolve([]),
|
|
27
|
+
multiSet: (_pairs: Array<[string, string]>) => Promise.resolve(undefined),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type RecordKind = 'rrweb' | 'span';
|
|
32
|
+
|
|
33
|
+
type IndexEntry = {
|
|
34
|
+
id: string;
|
|
35
|
+
ts: number;
|
|
36
|
+
kind: RecordKind;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const INDEX_KEY = 'mp_crash_buffer_index_v1';
|
|
40
|
+
const ATTRS_KEY = 'mp_crash_buffer_attrs_v1';
|
|
41
|
+
const RECORD_PREFIX = 'mp_crash_buffer_rec_v1:';
|
|
42
|
+
|
|
43
|
+
const randomId = (): string =>
|
|
44
|
+
`${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
45
|
+
|
|
46
|
+
export type CrashBufferSnapshot = {
|
|
47
|
+
rrwebEvents: Array<{ ts: number; event: any }>;
|
|
48
|
+
otelSpans: Array<{ ts: number; span: any }>;
|
|
49
|
+
attrs: any | null;
|
|
50
|
+
windowMs: number;
|
|
51
|
+
fromTs: number;
|
|
52
|
+
toTs: number;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export class CrashBufferService implements CrashBuffer {
|
|
56
|
+
private static instance: CrashBufferService | null = null;
|
|
57
|
+
|
|
58
|
+
private index: IndexEntry[] = [];
|
|
59
|
+
private indexLoaded = false;
|
|
60
|
+
private lastPruneAt = 0;
|
|
61
|
+
private opChain: Promise<any> = Promise.resolve();
|
|
62
|
+
private defaultWindowMs: number = 1 * 60 * 1000;
|
|
63
|
+
private listeners = new Map<
|
|
64
|
+
CrashBufferEventName,
|
|
65
|
+
Set<(payload: CrashBufferEventMap[CrashBufferEventName]) => void>
|
|
66
|
+
>();
|
|
67
|
+
|
|
68
|
+
static getInstance(): CrashBufferService {
|
|
69
|
+
if (!CrashBufferService.instance) {
|
|
70
|
+
CrashBufferService.instance = new CrashBufferService();
|
|
71
|
+
}
|
|
72
|
+
return CrashBufferService.instance;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private enqueue<T>(fn: () => Promise<T>): Promise<T> {
|
|
76
|
+
const next = this.opChain.then(fn, fn);
|
|
77
|
+
// Preserve chain, but don't leak rejections.
|
|
78
|
+
this.opChain = next.then(
|
|
79
|
+
() => undefined,
|
|
80
|
+
() => undefined
|
|
81
|
+
);
|
|
82
|
+
return next;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private async ensureIndexLoaded(): Promise<void> {
|
|
86
|
+
if (this.indexLoaded) return;
|
|
87
|
+
if (!AsyncStorage) {
|
|
88
|
+
this.indexLoaded = true;
|
|
89
|
+
this.index = [];
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const raw = await AsyncStorage.getItem(INDEX_KEY);
|
|
94
|
+
this.index = raw ? JSON.parse(raw) : [];
|
|
95
|
+
} catch (_e) {
|
|
96
|
+
this.index = [];
|
|
97
|
+
} finally {
|
|
98
|
+
this.indexLoaded = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async setAttrs(attrs: any): Promise<void> {
|
|
103
|
+
return this.enqueue(async () => {
|
|
104
|
+
if (!AsyncStorage) return;
|
|
105
|
+
try {
|
|
106
|
+
await AsyncStorage.setItem(ATTRS_KEY, JSON.stringify(attrs || null));
|
|
107
|
+
} catch (_e) {
|
|
108
|
+
// best-effort
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async appendEvent(
|
|
114
|
+
payload: { ts: number; event: any },
|
|
115
|
+
windowMs?: number
|
|
116
|
+
): Promise<void> {
|
|
117
|
+
return this.appendRecord(
|
|
118
|
+
'rrweb',
|
|
119
|
+
payload.ts,
|
|
120
|
+
payload,
|
|
121
|
+
windowMs ?? this.defaultWindowMs
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async appendSpans(
|
|
126
|
+
payload: Array<{ ts: number; span: any }>,
|
|
127
|
+
windowMs?: number
|
|
128
|
+
): Promise<void> {
|
|
129
|
+
if (!payload.length) return;
|
|
130
|
+
const effectiveWindowMs = windowMs ?? this.defaultWindowMs;
|
|
131
|
+
return this.enqueue(async () => {
|
|
132
|
+
if (!AsyncStorage) return;
|
|
133
|
+
await this.ensureIndexLoaded();
|
|
134
|
+
|
|
135
|
+
const pairs: Array<[string, string]> = [];
|
|
136
|
+
let errorEvent: CrashBufferErrorSpanAppendedEvent | null = null;
|
|
137
|
+
for (const p of payload) {
|
|
138
|
+
const id = randomId();
|
|
139
|
+
const key = `${RECORD_PREFIX}${id}`;
|
|
140
|
+
const entry: IndexEntry = { id, ts: p.ts, kind: 'span' };
|
|
141
|
+
this.index.push(entry);
|
|
142
|
+
pairs.push([key, JSON.stringify(p)]);
|
|
143
|
+
if (!errorEvent && p?.span?.status?.code === SpanStatusCode.ERROR) {
|
|
144
|
+
errorEvent = { ts: p.ts, span: p.span };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
await AsyncStorage.multiSet(pairs);
|
|
150
|
+
await AsyncStorage.setItem(INDEX_KEY, JSON.stringify(this.index));
|
|
151
|
+
} catch (_e) {
|
|
152
|
+
// best-effort
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
this.pruneSoon(effectiveWindowMs);
|
|
156
|
+
|
|
157
|
+
if (errorEvent) {
|
|
158
|
+
this._emit('error-span-appended', errorEvent);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
setDefaultWindowMs(windowMs: number): void {
|
|
164
|
+
this.defaultWindowMs = Math.max(10_000, windowMs || 1 * 60 * 1000);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
on<E extends CrashBufferEventName>(
|
|
168
|
+
event: E,
|
|
169
|
+
listener: (payload: CrashBufferEventMap[E]) => void
|
|
170
|
+
): () => void {
|
|
171
|
+
const set = this.listeners.get(event) || new Set();
|
|
172
|
+
set.add(listener as any);
|
|
173
|
+
this.listeners.set(event, set as any);
|
|
174
|
+
return () => this.off(event, listener as any);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
off<E extends CrashBufferEventName>(
|
|
178
|
+
event: E,
|
|
179
|
+
listener: (payload: CrashBufferEventMap[E]) => void
|
|
180
|
+
): void {
|
|
181
|
+
const set = this.listeners.get(event);
|
|
182
|
+
if (!set) return;
|
|
183
|
+
set.delete(listener as any);
|
|
184
|
+
if (set.size === 0) this.listeners.delete(event);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private _emit<E extends CrashBufferEventName>(
|
|
188
|
+
event: E,
|
|
189
|
+
payload: CrashBufferEventMap[E]
|
|
190
|
+
): void {
|
|
191
|
+
const set = this.listeners.get(event);
|
|
192
|
+
if (!set || set.size === 0) return;
|
|
193
|
+
for (const fn of Array.from(set)) {
|
|
194
|
+
try {
|
|
195
|
+
(fn as any)(payload);
|
|
196
|
+
} catch (_e) {
|
|
197
|
+
// never throw into app code
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private async appendRecord(
|
|
203
|
+
kind: RecordKind,
|
|
204
|
+
ts: number,
|
|
205
|
+
payload: any,
|
|
206
|
+
windowMs: number
|
|
207
|
+
): Promise<void> {
|
|
208
|
+
return this.enqueue(async () => {
|
|
209
|
+
if (!AsyncStorage) return;
|
|
210
|
+
await this.ensureIndexLoaded();
|
|
211
|
+
|
|
212
|
+
const id = randomId();
|
|
213
|
+
const key = `${RECORD_PREFIX}${id}`;
|
|
214
|
+
const entry: IndexEntry = { id, ts, kind };
|
|
215
|
+
this.index.push(entry);
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
await AsyncStorage.setItem(key, JSON.stringify(payload));
|
|
219
|
+
await AsyncStorage.setItem(INDEX_KEY, JSON.stringify(this.index));
|
|
220
|
+
} catch (_e) {
|
|
221
|
+
// best-effort
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
this.pruneSoon(windowMs);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private pruneSoon(windowMs: number) {
|
|
229
|
+
const now = Date.now();
|
|
230
|
+
if (now - this.lastPruneAt < 2000) return;
|
|
231
|
+
this.lastPruneAt = now;
|
|
232
|
+
const cutoff = Math.max(0, now - windowMs);
|
|
233
|
+
void this.pruneOlderThan(cutoff);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async pruneOlderThan(cutoffTs: number): Promise<void> {
|
|
237
|
+
return this.enqueue(async () => {
|
|
238
|
+
if (!AsyncStorage) return;
|
|
239
|
+
await this.ensureIndexLoaded();
|
|
240
|
+
const toRemove = this.index.filter((e) => e.ts < cutoffTs);
|
|
241
|
+
if (toRemove.length === 0) return;
|
|
242
|
+
|
|
243
|
+
const removeKeys = toRemove.map((e) => `${RECORD_PREFIX}${e.id}`);
|
|
244
|
+
this.index = this.index.filter((e) => e.ts >= cutoffTs);
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
await AsyncStorage.multiRemove(removeKeys);
|
|
248
|
+
await AsyncStorage.setItem(INDEX_KEY, JSON.stringify(this.index));
|
|
249
|
+
} catch (_e) {
|
|
250
|
+
// best-effort
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async snapshot(
|
|
256
|
+
windowMs?: number,
|
|
257
|
+
now: number = Date.now()
|
|
258
|
+
): Promise<CrashBufferSnapshot> {
|
|
259
|
+
return this.enqueue(async () => {
|
|
260
|
+
await this.ensureIndexLoaded();
|
|
261
|
+
const effectiveWindowMs = windowMs ?? this.defaultWindowMs;
|
|
262
|
+
const toTs = now;
|
|
263
|
+
const fromTs = Math.max(0, toTs - effectiveWindowMs);
|
|
264
|
+
const entries = this.index.filter((e) => e.ts >= fromTs && e.ts <= toTs);
|
|
265
|
+
const keys = entries.map((e) => `${RECORD_PREFIX}${e.id}`);
|
|
266
|
+
|
|
267
|
+
let pairs: Array<[string, string | null]> = [];
|
|
268
|
+
try {
|
|
269
|
+
pairs = AsyncStorage ? await AsyncStorage.multiGet(keys) : [];
|
|
270
|
+
} catch (_e) {
|
|
271
|
+
pairs = [];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const byKey = new Map<string, any>();
|
|
275
|
+
for (const [k, v] of pairs) {
|
|
276
|
+
if (!v) continue;
|
|
277
|
+
try {
|
|
278
|
+
byKey.set(k, JSON.parse(v));
|
|
279
|
+
} catch (_e) {
|
|
280
|
+
// ignore
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const rrwebEvents: Array<{ ts: number; event: any }> = [];
|
|
285
|
+
const otelSpans: Array<{ ts: number; span: any }> = [];
|
|
286
|
+
|
|
287
|
+
for (const e of entries.sort((a, b) => a.ts - b.ts)) {
|
|
288
|
+
const key = `${RECORD_PREFIX}${e.id}`;
|
|
289
|
+
const payload = byKey.get(key);
|
|
290
|
+
if (!payload) continue;
|
|
291
|
+
if (e.kind === 'rrweb') rrwebEvents.push(payload);
|
|
292
|
+
if (e.kind === 'span') otelSpans.push(payload);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let attrs: any | null = null;
|
|
296
|
+
try {
|
|
297
|
+
const raw = AsyncStorage ? await AsyncStorage.getItem(ATTRS_KEY) : null;
|
|
298
|
+
attrs = raw ? JSON.parse(raw) : null;
|
|
299
|
+
} catch (_e) {
|
|
300
|
+
attrs = null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
rrwebEvents,
|
|
305
|
+
otelSpans,
|
|
306
|
+
attrs,
|
|
307
|
+
windowMs: effectiveWindowMs,
|
|
308
|
+
fromTs,
|
|
309
|
+
toTs,
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async clear(): Promise<void> {
|
|
315
|
+
return this.enqueue(async () => {
|
|
316
|
+
if (!AsyncStorage) return;
|
|
317
|
+
await this.ensureIndexLoaded();
|
|
318
|
+
const keys = this.index.map((e) => `${RECORD_PREFIX}${e.id}`);
|
|
319
|
+
this.index = [];
|
|
320
|
+
try {
|
|
321
|
+
await AsyncStorage.multiRemove([INDEX_KEY, ATTRS_KEY, ...keys]);
|
|
322
|
+
} catch (_e) {
|
|
323
|
+
// best-effort
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
@@ -13,8 +13,13 @@ import {
|
|
|
13
13
|
REMOTE_SESSION_RECORDING_START,
|
|
14
14
|
REMOTE_SESSION_RECORDING_STOP,
|
|
15
15
|
SESSION_STARTED_EVENT,
|
|
16
|
+
SESSION_SAVE_BUFFER_EVENT,
|
|
16
17
|
} from '../config';
|
|
17
|
-
import
|
|
18
|
+
import {
|
|
19
|
+
type ISession,
|
|
20
|
+
type IUserAttributes,
|
|
21
|
+
ATTR_MULTIPLAYER_SESSION_CLIENT_ID,
|
|
22
|
+
} from '@multiplayer-app/session-recorder-common';
|
|
18
23
|
|
|
19
24
|
const MAX_RECONNECTION_ATTEMPTS = 2;
|
|
20
25
|
|
|
@@ -22,12 +27,14 @@ export type SocketServiceEvents =
|
|
|
22
27
|
| typeof SESSION_STOPPED_EVENT
|
|
23
28
|
| typeof SESSION_AUTO_CREATED
|
|
24
29
|
| typeof REMOTE_SESSION_RECORDING_START
|
|
25
|
-
| typeof REMOTE_SESSION_RECORDING_STOP
|
|
30
|
+
| typeof REMOTE_SESSION_RECORDING_STOP
|
|
31
|
+
| typeof SESSION_SAVE_BUFFER_EVENT;
|
|
26
32
|
|
|
27
33
|
export interface SocketServiceOptions {
|
|
28
34
|
apiKey: string;
|
|
29
35
|
socketUrl: string;
|
|
30
36
|
keepAlive?: boolean;
|
|
37
|
+
clientId?: string;
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
export class SocketService extends Observable<SocketServiceEvents> {
|
|
@@ -72,15 +79,13 @@ export class SocketService extends Observable<SocketServiceEvents> {
|
|
|
72
79
|
*/
|
|
73
80
|
public updateConfigs(config: Partial<SocketServiceOptions>): void {
|
|
74
81
|
// If any config changed, reconnect if connected
|
|
75
|
-
const hasChanges = Object.keys(config).some(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
);
|
|
82
|
+
const hasChanges = Object.keys(config).some((key) => {
|
|
83
|
+
const typedKey = key as keyof SocketServiceOptions;
|
|
84
|
+
return (
|
|
85
|
+
config[typedKey] !== undefined &&
|
|
86
|
+
config[typedKey] !== this.options[typedKey]
|
|
87
|
+
);
|
|
88
|
+
});
|
|
84
89
|
|
|
85
90
|
if (hasChanges) {
|
|
86
91
|
this.options = { ...this.options, ...config };
|
|
@@ -106,6 +111,9 @@ export class SocketService extends Observable<SocketServiceEvents> {
|
|
|
106
111
|
path: '/v0/radar/ws',
|
|
107
112
|
auth: {
|
|
108
113
|
'x-api-key': this.options.apiKey,
|
|
114
|
+
...(this.options.clientId
|
|
115
|
+
? { [ATTR_MULTIPLAYER_SESSION_CLIENT_ID]: this.options.clientId }
|
|
116
|
+
: {}),
|
|
109
117
|
},
|
|
110
118
|
reconnectionAttempts: 2,
|
|
111
119
|
transports: ['websocket'],
|
|
@@ -146,6 +154,10 @@ export class SocketService extends Observable<SocketServiceEvents> {
|
|
|
146
154
|
this.socket.on(REMOTE_SESSION_RECORDING_STOP, (data: any) => {
|
|
147
155
|
this.emit(REMOTE_SESSION_RECORDING_STOP, [data]);
|
|
148
156
|
});
|
|
157
|
+
|
|
158
|
+
this.socket.on(SESSION_SAVE_BUFFER_EVENT, (data: any) => {
|
|
159
|
+
this.emit(SESSION_SAVE_BUFFER_EVENT, [data]);
|
|
160
|
+
});
|
|
149
161
|
}
|
|
150
162
|
|
|
151
163
|
private checkReconnectionAttempts(): void {
|
|
@@ -156,10 +168,10 @@ export class SocketService extends Observable<SocketServiceEvents> {
|
|
|
156
168
|
|
|
157
169
|
private emitSocketEvent(name: string, data: any): void {
|
|
158
170
|
if (this.socket && this.isConnected) {
|
|
159
|
-
this.socket.emit(name, data)
|
|
171
|
+
this.socket.emit(name, data);
|
|
160
172
|
} else {
|
|
161
|
-
this.queue.push({ data, name })
|
|
162
|
-
this._initConnection()
|
|
173
|
+
this.queue.push({ data, name });
|
|
174
|
+
this._initConnection();
|
|
163
175
|
}
|
|
164
176
|
}
|
|
165
177
|
|
|
@@ -174,12 +186,10 @@ export class SocketService extends Observable<SocketServiceEvents> {
|
|
|
174
186
|
}
|
|
175
187
|
}
|
|
176
188
|
|
|
177
|
-
|
|
178
189
|
public send(event: any): void {
|
|
179
|
-
this.emitSocketEvent(SESSION_ADD_EVENT, event)
|
|
190
|
+
this.emitSocketEvent(SESSION_ADD_EVENT, event);
|
|
180
191
|
}
|
|
181
192
|
|
|
182
|
-
|
|
183
193
|
public subscribeToSession(session: ISession): void {
|
|
184
194
|
this.sessionId = session.shortId || session._id;
|
|
185
195
|
const payload = {
|
|
@@ -188,22 +198,26 @@ export class SocketService extends Observable<SocketServiceEvents> {
|
|
|
188
198
|
debugSessionId: this.sessionId,
|
|
189
199
|
sessionType: session.creationType,
|
|
190
200
|
};
|
|
191
|
-
this.emitSocketEvent(SESSION_SUBSCRIBE_EVENT, payload)
|
|
201
|
+
this.emitSocketEvent(SESSION_SUBSCRIBE_EVENT, payload);
|
|
192
202
|
// use long id instead of short id
|
|
193
|
-
this.emitSocketEvent(SESSION_STARTED_EVENT, {
|
|
203
|
+
this.emitSocketEvent(SESSION_STARTED_EVENT, {
|
|
204
|
+
debugSessionId: session._id,
|
|
205
|
+
});
|
|
194
206
|
}
|
|
195
207
|
|
|
196
208
|
public unsubscribeFromSession(stopSession?: boolean) {
|
|
197
209
|
if (this.sessionId) {
|
|
198
|
-
this.emitSocketEvent(SESSION_UNSUBSCRIBE_EVENT, {
|
|
210
|
+
this.emitSocketEvent(SESSION_UNSUBSCRIBE_EVENT, {
|
|
211
|
+
debugSessionId: this.sessionId,
|
|
212
|
+
});
|
|
199
213
|
if (stopSession) {
|
|
200
|
-
this.emitSocketEvent(SESSION_STOPPED_EVENT, {})
|
|
214
|
+
this.emitSocketEvent(SESSION_STOPPED_EVENT, {});
|
|
201
215
|
}
|
|
202
216
|
}
|
|
203
217
|
}
|
|
204
218
|
|
|
205
219
|
public setUser(userAttributes: IUserAttributes | null): void {
|
|
206
|
-
this.emitSocketEvent(SOCKET_SET_USER_EVENT, userAttributes)
|
|
220
|
+
this.emitSocketEvent(SOCKET_SET_USER_EVENT, userAttributes);
|
|
207
221
|
}
|
|
208
222
|
|
|
209
223
|
public close(): Promise<void> {
|