@observertc/observer-js 1.0.1-c3edea3.0 → 1.0.1-ec27289.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/lib/ObservedCall.d.ts +41 -7
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +125 -13
- package/lib/ObservedCallSummary.d.ts +18 -0
- package/lib/ObservedCallSummary.d.ts.map +1 -0
- package/lib/ObservedClient.d.ts +70 -11
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +394 -72
- package/lib/ObservedClientEventMonitor.d.ts +89 -0
- package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
- package/lib/ObservedClientEventMonitor.js +247 -0
- package/lib/ObservedClientSummary.d.ts +23 -0
- package/lib/ObservedClientSummary.d.ts.map +1 -0
- package/lib/ObservedClientSummary.js +2 -0
- package/lib/ObservedDataChannel.d.ts +6 -0
- package/lib/ObservedDataChannel.d.ts.map +1 -1
- package/lib/ObservedDataChannel.js +30 -0
- package/lib/ObservedIceCandidatePair.d.ts +4 -0
- package/lib/ObservedIceCandidatePair.d.ts.map +1 -1
- package/lib/ObservedIceCandidatePair.js +28 -0
- package/lib/ObservedIceTransport.d.ts +4 -0
- package/lib/ObservedIceTransport.d.ts.map +1 -1
- package/lib/ObservedIceTransport.js +28 -0
- package/lib/ObservedInboundTrack.d.ts +2 -0
- package/lib/ObservedInboundTrack.d.ts.map +1 -1
- package/lib/ObservedInboundTrack.js +2 -0
- package/lib/ObservedOutboundTrack.d.ts +2 -0
- package/lib/ObservedOutboundTrack.d.ts.map +1 -1
- package/lib/ObservedOutboundTrack.js +2 -0
- package/lib/ObservedPeerConnection.d.ts +14 -2
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +106 -14
- package/lib/ObservedTURN.d.ts +31 -0
- package/lib/ObservedTURN.d.ts.map +1 -0
- package/lib/ObservedTURN.js +58 -0
- package/lib/ObservedTurnServer.d.ts +25 -0
- package/lib/ObservedTurnServer.d.ts.map +1 -0
- package/lib/ObservedTurnServer.js +59 -0
- package/lib/Observer.d.ts +38 -21
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +114 -40
- package/lib/ObserverSummary.d.ts +13 -0
- package/lib/ObserverSummary.d.ts.map +1 -0
- package/lib/ObserverSummary.js +2 -0
- package/lib/common/utils.d.ts +2 -1
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +11 -3
- package/lib/index.d.ts +5 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +7 -1
- package/lib/schema/ClientEventTypes.d.ts +100 -0
- package/lib/schema/ClientEventTypes.d.ts.map +1 -0
- package/lib/schema/ClientEventTypes.js +38 -0
- package/lib/schema/{metaTypes.d.ts → ClientMetaTypes.d.ts} +2 -2
- package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
- package/lib/schema/ClientMetaTypes.js +16 -0
- package/lib/updaters/CallUpdater.d.ts.map +1 -0
- package/lib/updaters/CallUpdater.js +2 -0
- package/lib/updaters/ObserverUpdater.d.ts +5 -0
- package/lib/updaters/ObserverUpdater.d.ts.map +1 -0
- package/lib/updaters/ObserverUpdater.js +2 -0
- package/lib/updaters/OnAllCallObserverUpdater_.d.ts +13 -0
- package/lib/updaters/OnAllCallObserverUpdater_.d.ts.map +1 -0
- package/lib/updaters/OnAllCallObserverUpdater_.js +38 -0
- package/lib/updaters/OnAllClientCallUpdater.d.ts +13 -0
- package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -0
- package/lib/updaters/OnAllClientCallUpdater.js +37 -0
- package/lib/updaters/OnAnyCallObserverUpdater_.d.ts +11 -0
- package/lib/updaters/OnAnyCallObserverUpdater_.d.ts.map +1 -0
- package/lib/updaters/OnAnyCallObserverUpdater_.js +27 -0
- package/lib/updaters/OnAnyClientCallUpdater.d.ts +11 -0
- package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -0
- package/lib/updaters/OnAnyClientCallUpdater.js +27 -0
- package/lib/updaters/OnIntervalUpdater.d.ts +10 -0
- package/lib/updaters/OnIntervalUpdater.d.ts.map +1 -0
- package/lib/updaters/OnIntervalUpdater.js +17 -0
- package/lib/updaters/Updater.d.ts +6 -0
- package/lib/updaters/Updater.d.ts.map +1 -0
- package/lib/updaters/Updater.js +2 -0
- package/package.json +1 -1
- package/src/ObservedCall.ts +205 -16
- package/src/ObservedCallSummary.ts +22 -0
- package/src/ObservedClient.ts +492 -78
- package/src/ObservedClientEventMonitor.ts +301 -0
- package/src/ObservedClientSummary.ts +24 -0
- package/src/ObservedDataChannel.ts +32 -0
- package/src/ObservedIceCandidatePair.ts +26 -0
- package/src/ObservedIceTransport.ts +29 -0
- package/src/ObservedInboundTrack.ts +3 -0
- package/src/ObservedOutboundTrack.ts +3 -0
- package/src/ObservedPeerConnection.ts +120 -16
- package/src/ObservedTURN.ts +86 -0
- package/src/ObservedTurnServer.ts +72 -0
- package/src/Observer.ts +164 -64
- package/src/ObserverSummary.ts +15 -0
- package/src/common/utils.ts +12 -2
- package/src/index.ts +5 -0
- package/src/schema/ClientEventTypes.ts +112 -0
- package/src/schema/{metaTypes.ts → ClientMetaTypes.ts} +1 -1
- package/src/updaters/ObserverUpdater.ts +5 -0
- package/src/updaters/OnAllCallObserverUpdater_.ts +46 -0
- package/src/updaters/OnAllClientCallUpdater.ts +46 -0
- package/src/updaters/OnAnyCallObserverUpdater_.ts +32 -0
- package/src/updaters/OnAnyClientCallUpdater.ts +32 -0
- package/src/updaters/OnIntervalUpdater.ts +19 -0
- package/src/updaters/Updater.ts +5 -0
- package/tsconfig.json +1 -1
- package/lib/schema/eventTypes.d.ts +0 -33
- package/lib/schema/eventTypes.d.ts.map +0 -1
- package/lib/schema/eventTypes.js +0 -38
- package/lib/schema/metaTypes.d.ts.map +0 -1
- package/lib/schema/metaTypes.js +0 -16
- package/lib/utils/CallUpdater.d.ts.map +0 -1
- package/lib/utils/OnAllClientCallUpdater.d.ts +0 -16
- package/lib/utils/OnAllClientCallUpdater.d.ts.map +0 -1
- package/lib/utils/OnAllClientCallUpdater.js +0 -58
- package/lib/utils/onAnyClientCallUpdater.d.ts +0 -14
- package/lib/utils/onAnyClientCallUpdater.d.ts.map +0 -1
- package/lib/utils/onAnyClientCallUpdater.js +0 -51
- package/src/schema/eventTypes.ts +0 -36
- package/src/utils/OnAllClientCallUpdater.ts +0 -68
- package/src/utils/onAnyClientCallUpdater.ts +0 -59
- /package/lib/{utils/CallUpdater.js → ObservedCallSummary.js} +0 -0
- /package/lib/{utils → updaters}/CallUpdater.d.ts +0 -0
- /package/src/{utils → updaters}/CallUpdater.ts +0 -0
package/src/ObservedClient.ts
CHANGED
|
@@ -3,13 +3,14 @@ import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
|
3
3
|
import { createLogger } from './common/logger';
|
|
4
4
|
// eslint-disable-next-line camelcase
|
|
5
5
|
import { ClientEvent, ClientMetaData, ClientSample, PeerConnectionSample, ClientIssue, ExtensionStat } from './schema/ClientSample';
|
|
6
|
-
import * as MetaData from './schema/
|
|
7
|
-
import {
|
|
6
|
+
import * as MetaData from './schema/ClientMetaTypes';
|
|
7
|
+
import { ClientEventTypes } from './schema/ClientEventTypes';
|
|
8
8
|
import { ObservedCall } from './ObservedCall';
|
|
9
|
-
import {
|
|
9
|
+
import { ClientMetaTypes } from './schema/ClientMetaTypes';
|
|
10
10
|
import { parseJsonAs } from './common/utils';
|
|
11
11
|
import { CalculatedScore } from './scores/CalculatedScore';
|
|
12
12
|
import { Detectors } from './detectors/Detectors';
|
|
13
|
+
import { ObservedClientEventMonitor } from './ObservedClientEventMonitor';
|
|
13
14
|
|
|
14
15
|
const logger = createLogger('ObservedClient');
|
|
15
16
|
|
|
@@ -27,6 +28,8 @@ export type ObservedClientEvents = {
|
|
|
27
28
|
];
|
|
28
29
|
close: [];
|
|
29
30
|
joined: [];
|
|
31
|
+
issue: [ClientIssue];
|
|
32
|
+
metaData: [ClientMetaData];
|
|
30
33
|
rejoined: [timestamp: number];
|
|
31
34
|
left: [];
|
|
32
35
|
usingturn: [boolean];
|
|
@@ -53,7 +56,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
53
56
|
value: undefined,
|
|
54
57
|
};
|
|
55
58
|
|
|
56
|
-
public appData
|
|
59
|
+
public appData: AppData;
|
|
57
60
|
public attachments?: Record<string, unknown>;
|
|
58
61
|
|
|
59
62
|
public updated = Date.now();
|
|
@@ -62,6 +65,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
62
65
|
|
|
63
66
|
public joinedAt?: number;
|
|
64
67
|
public leftAt?: number;
|
|
68
|
+
public closedAt?: number;
|
|
65
69
|
// the timestamp of the CLIENT_JOINED event
|
|
66
70
|
public operationSystem?: MetaData.OperationSystem;
|
|
67
71
|
public engine?: MetaData.Engine;
|
|
@@ -70,47 +74,85 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
70
74
|
public mediaConstraints: string[] = [];
|
|
71
75
|
|
|
72
76
|
public usingTURN = false;
|
|
77
|
+
public usingTCP = false;
|
|
73
78
|
public availableOutgoingBitrate = 0;
|
|
74
79
|
public availableIncomingBitrate = 0;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
public
|
|
98
|
-
public
|
|
99
|
-
public
|
|
100
|
-
public
|
|
101
|
-
public
|
|
80
|
+
|
|
81
|
+
public totalInboundPacketsLost = 0;
|
|
82
|
+
public totalInboundPacketsReceived = 0;
|
|
83
|
+
public totalOutboundPacketsSent = 0;
|
|
84
|
+
public totalDataChannelBytesSent = 0;
|
|
85
|
+
public totalDataChannelBytesReceived = 0;
|
|
86
|
+
public totalDataChannelMessagesSent = 0;
|
|
87
|
+
public totalDataChannelMessagesReceived = 0;
|
|
88
|
+
public totalReceivedAudioBytes = 0;
|
|
89
|
+
public totalReceivedVideoBytes = 0;
|
|
90
|
+
public totalSentAudioBytes = 0;
|
|
91
|
+
public totalSentVideoBytes = 0;
|
|
92
|
+
public totalSentBytes = 0;
|
|
93
|
+
public totalReceivedBytes = 0;
|
|
94
|
+
|
|
95
|
+
public deltaReceivedAudioBytes = 0;
|
|
96
|
+
public deltaReceivedVideoBytes = 0;
|
|
97
|
+
public deltaSentAudioBytes = 0;
|
|
98
|
+
public deltaSentVideoBytes = 0;
|
|
99
|
+
public deltaDataChannelBytesSent = 0;
|
|
100
|
+
public deltaDataChannelBytesReceived = 0;
|
|
101
|
+
public deltaDataChannelMessagesSent = 0;
|
|
102
|
+
public deltaDataChannelMessagesReceived = 0;
|
|
103
|
+
public deltaInboundPacketsLost = 0;
|
|
104
|
+
public deltaInboundPacketsReceived = 0;
|
|
105
|
+
public deltaOutboundPacketsSent = 0;
|
|
106
|
+
public deltaTransportSentBytes = 0;
|
|
107
|
+
public deltaTransportReceivedBytes = 0;
|
|
108
|
+
public deltaRttLt50Measurements = 0;
|
|
109
|
+
public deltaRttLt150Measurements = 0;
|
|
110
|
+
public deltaRttLt300Measurements = 0;
|
|
111
|
+
public deltaRttGtOrEq300Measurements = 0;
|
|
112
|
+
|
|
113
|
+
public currentMaxRttInMs?: number;
|
|
114
|
+
public currentMinRttInMs?: number;
|
|
115
|
+
public currentAvgRttInMs?: number;
|
|
116
|
+
|
|
117
|
+
public sendingAudioBitrate = 0;
|
|
118
|
+
public sendingVideoBitrate = 0;
|
|
119
|
+
public receivingAudioBitrate = 0;
|
|
120
|
+
public receivingVideoBitrate = 0;
|
|
121
|
+
|
|
122
|
+
public numberOfInboundRtpStreams = 0;
|
|
123
|
+
public numberOfInbundTracks = 0;
|
|
124
|
+
public numberOfOutboundRtpStreams = 0;
|
|
125
|
+
public numberOfOutboundTracks = 0;
|
|
126
|
+
public numberOfDataChannels = 0;
|
|
127
|
+
|
|
128
|
+
public totalRttLt50Measurements = 0;
|
|
129
|
+
public totalRttLt150Measurements = 0;
|
|
130
|
+
public totalRttLt300Measurements = 0;
|
|
131
|
+
public totalRttGtOrEq300Measurements = 0;
|
|
132
|
+
public deltaNumberOfIssues = 0;
|
|
133
|
+
|
|
134
|
+
public totalScoreSum = 0;
|
|
135
|
+
public numberOfScoreMeasurements = 0;
|
|
136
|
+
public totalNumberOfIssues = 0;
|
|
102
137
|
|
|
103
138
|
public readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];
|
|
104
139
|
public issues: ClientIssue[] = [];
|
|
105
140
|
|
|
141
|
+
private _injections: Pick<ClientSample, 'clientEvents' | 'clientIssues' | 'extensionStats' | 'attachments' | 'clientMetaItems'> = {};
|
|
142
|
+
|
|
106
143
|
public constructor(settings: ObservedClientSettings<AppData>, public readonly call: ObservedCall) {
|
|
107
144
|
super();
|
|
108
145
|
this.setMaxListeners(Infinity);
|
|
109
146
|
|
|
110
147
|
this.clientId = settings.clientId;
|
|
111
|
-
this.appData = settings.appData;
|
|
148
|
+
this.appData = settings.appData ?? {} as AppData;
|
|
149
|
+
|
|
112
150
|
this.detectors = new Detectors();
|
|
113
151
|
}
|
|
152
|
+
|
|
153
|
+
public get numberOfPeerConnections() {
|
|
154
|
+
return this.observedPeerConnections.size;
|
|
155
|
+
}
|
|
114
156
|
|
|
115
157
|
public get score() {
|
|
116
158
|
return this.calculatedScore.value;
|
|
@@ -122,6 +164,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
122
164
|
|
|
123
165
|
Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
|
|
124
166
|
|
|
167
|
+
this.closedAt = Date.now();
|
|
168
|
+
|
|
125
169
|
this.emit('close');
|
|
126
170
|
}
|
|
127
171
|
|
|
@@ -129,16 +173,157 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
129
173
|
if (this.closed) throw new Error(`Client ${this.clientId} is closed`);
|
|
130
174
|
|
|
131
175
|
const now = Date.now();
|
|
176
|
+
const elapsedInMs = now - this.updated;
|
|
177
|
+
const elapsedInSeconds = elapsedInMs / 1000;
|
|
178
|
+
let sumOfRtts = 0;
|
|
179
|
+
let numberOfRttMeasurements = 0;
|
|
180
|
+
|
|
181
|
+
++this.acceptedSamples;
|
|
182
|
+
|
|
183
|
+
this.availableIncomingBitrate = 0;
|
|
184
|
+
this.availableOutgoingBitrate = 0;
|
|
185
|
+
this.deltaDataChannelBytesReceived = 0;
|
|
186
|
+
this.deltaDataChannelBytesSent = 0;
|
|
187
|
+
this.deltaDataChannelMessagesReceived = 0;
|
|
188
|
+
this.deltaDataChannelMessagesSent = 0;
|
|
189
|
+
this.deltaInboundPacketsLost = 0;
|
|
190
|
+
this.deltaInboundPacketsReceived = 0;
|
|
191
|
+
this.deltaOutboundPacketsSent = 0;
|
|
192
|
+
this.deltaReceivedAudioBytes = 0;
|
|
193
|
+
this.deltaReceivedVideoBytes = 0;
|
|
194
|
+
this.deltaSentAudioBytes = 0;
|
|
195
|
+
this.deltaSentVideoBytes = 0;
|
|
196
|
+
this.deltaTransportReceivedBytes = 0;
|
|
197
|
+
this.deltaTransportSentBytes = 0;
|
|
198
|
+
this.deltaRttLt50Measurements = 0;
|
|
199
|
+
this.deltaRttLt150Measurements = 0;
|
|
200
|
+
this.deltaRttLt300Measurements = 0;
|
|
201
|
+
this.deltaRttGtOrEq300Measurements = 0;
|
|
202
|
+
this.deltaNumberOfIssues = 0;
|
|
203
|
+
|
|
204
|
+
this.numberOfDataChannels = 0;
|
|
205
|
+
this.numberOfInboundRtpStreams = 0;
|
|
206
|
+
this.numberOfInbundTracks = 0;
|
|
207
|
+
this.numberOfOutboundRtpStreams = 0;
|
|
208
|
+
this.numberOfOutboundTracks = 0;
|
|
209
|
+
this.usingTURN = false;
|
|
210
|
+
this.usingTCP = false;
|
|
211
|
+
this.currentMinRttInMs = undefined;
|
|
212
|
+
this.currentMaxRttInMs = undefined;
|
|
213
|
+
|
|
214
|
+
this._mergeInjections(sample);
|
|
215
|
+
|
|
216
|
+
const clientEventsPostBuffer: ClientEvent[] = [];
|
|
217
|
+
|
|
218
|
+
for (const clientEvent of sample.clientEvents ?? []) {
|
|
219
|
+
this._processClientEvent(clientEvent, clientEventsPostBuffer);
|
|
220
|
+
|
|
221
|
+
this.call.observer.emit('client-event', this, clientEvent);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
for (const metaData of sample.clientMetaItems ?? []) {
|
|
225
|
+
this.addMetadata(metaData);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
for (const issue of sample.clientIssues ?? []) {
|
|
229
|
+
this.addIssue(issue);
|
|
230
|
+
|
|
231
|
+
++this.deltaNumberOfIssues;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
for (const extensionStat of sample.extensionStats ?? []) {
|
|
235
|
+
this.addExtensionStats(extensionStat);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
for (const pcSample of sample.peerConnections ?? []) {
|
|
239
|
+
const observedPeerConnection = this._updatePeerConnection(pcSample);
|
|
240
|
+
|
|
241
|
+
if (!observedPeerConnection) continue;
|
|
242
|
+
|
|
243
|
+
this.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;
|
|
244
|
+
this.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;
|
|
245
|
+
this.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;
|
|
246
|
+
this.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;
|
|
247
|
+
this.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;
|
|
248
|
+
this.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;
|
|
249
|
+
this.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;
|
|
250
|
+
this.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;
|
|
251
|
+
this.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;
|
|
252
|
+
this.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;
|
|
253
|
+
this.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;
|
|
254
|
+
this.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;
|
|
255
|
+
this.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;
|
|
256
|
+
|
|
257
|
+
this.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;
|
|
258
|
+
this.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;
|
|
259
|
+
|
|
260
|
+
this.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;
|
|
261
|
+
this.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;
|
|
262
|
+
this.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;
|
|
263
|
+
this.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;
|
|
264
|
+
this.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;
|
|
265
|
+
|
|
266
|
+
if (observedPeerConnection.usingTURN) {
|
|
267
|
+
this.usingTURN = true;
|
|
268
|
+
}
|
|
269
|
+
if (observedPeerConnection.usingTCP) {
|
|
270
|
+
this.usingTCP = true;
|
|
271
|
+
}
|
|
132
272
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
273
|
+
if (observedPeerConnection.currentRttInMs) {
|
|
274
|
+
if (this.currentMinRttInMs === undefined || observedPeerConnection.currentRttInMs < this.currentMinRttInMs) {
|
|
275
|
+
this.currentMinRttInMs = observedPeerConnection.currentRttInMs;
|
|
276
|
+
}
|
|
277
|
+
if (this.currentMaxRttInMs === undefined || observedPeerConnection.currentRttInMs > this.currentMaxRttInMs) {
|
|
278
|
+
this.currentMaxRttInMs = observedPeerConnection.currentRttInMs;
|
|
279
|
+
}
|
|
280
|
+
if (observedPeerConnection.currentRttInMs < 50) {
|
|
281
|
+
this.deltaRttLt50Measurements += 1;
|
|
282
|
+
} else if (observedPeerConnection.currentRttInMs < 150) {
|
|
283
|
+
this.deltaRttLt150Measurements += 1;
|
|
284
|
+
} else if (observedPeerConnection.currentRttInMs < 300) {
|
|
285
|
+
this.deltaRttLt300Measurements += 1;
|
|
286
|
+
} else if (300 <= observedPeerConnection.currentRttInMs) {
|
|
287
|
+
this.deltaRttGtOrEq300Measurements += 1;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
sumOfRtts += observedPeerConnection.currentRttInMs;
|
|
291
|
+
++numberOfRttMeasurements;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
for (const clientEvent of clientEventsPostBuffer) {
|
|
296
|
+
this._processClientEvent(clientEvent);
|
|
297
|
+
}
|
|
138
298
|
|
|
139
299
|
// emit new attachments?
|
|
140
300
|
this.attachments = sample.attachments;
|
|
141
301
|
|
|
302
|
+
this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
|
|
303
|
+
this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
|
|
304
|
+
this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
|
|
305
|
+
this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
|
|
306
|
+
this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
|
|
307
|
+
this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
|
|
308
|
+
this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
|
|
309
|
+
this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
|
|
310
|
+
this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
|
|
311
|
+
this.totalSentAudioBytes += this.deltaSentAudioBytes;
|
|
312
|
+
this.totalSentVideoBytes += this.deltaSentVideoBytes;
|
|
313
|
+
this.totalReceivedBytes += this.deltaTransportReceivedBytes;
|
|
314
|
+
this.totalSentBytes += this.deltaTransportSentBytes;
|
|
315
|
+
this.totalRttLt50Measurements += this.deltaRttLt50Measurements;
|
|
316
|
+
this.totalRttLt150Measurements += this.deltaRttLt150Measurements;
|
|
317
|
+
this.totalRttLt300Measurements += this.deltaRttLt300Measurements;
|
|
318
|
+
this.totalRttGtOrEq300Measurements += this.deltaRttGtOrEq300Measurements;
|
|
319
|
+
this.totalNumberOfIssues += this.deltaNumberOfIssues;
|
|
320
|
+
|
|
321
|
+
this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (elapsedInSeconds);
|
|
322
|
+
this.receivingVideoBitrate = (this.totalReceivedVideoBytes * 8) / (elapsedInSeconds);
|
|
323
|
+
this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / (elapsedInSeconds);
|
|
324
|
+
this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / (elapsedInSeconds);
|
|
325
|
+
this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : undefined;
|
|
326
|
+
|
|
142
327
|
this.calculatedScore.value = sample.score;
|
|
143
328
|
this.detectors.update();
|
|
144
329
|
|
|
@@ -148,19 +333,19 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
148
333
|
elapsedTimeInMs: now - this.updated,
|
|
149
334
|
});
|
|
150
335
|
this.updated = now;
|
|
336
|
+
|
|
337
|
+
// if result changed after update
|
|
338
|
+
if (this.calculatedScore.value) {
|
|
339
|
+
this.totalScoreSum += this.calculatedScore.value;
|
|
340
|
+
++this.numberOfScoreMeasurements;
|
|
341
|
+
}
|
|
151
342
|
}
|
|
152
343
|
|
|
153
|
-
private _processClientEvent(event: ClientEvent) {
|
|
344
|
+
private _processClientEvent(event: ClientEvent, postBuffer?: ClientEvent[]) {
|
|
345
|
+
// eslint-disable-next-line no-console
|
|
346
|
+
// console.warn('ClientEvent', event);
|
|
154
347
|
switch (event.type) {
|
|
155
|
-
case
|
|
156
|
-
// update call timestamp if it's the first time
|
|
157
|
-
break;
|
|
158
|
-
}
|
|
159
|
-
case ClientEventType.CALL_ENDED: {
|
|
160
|
-
// update call timestamp if it's the first time
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
case ClientEventType.CLIENT_JOINED: {
|
|
348
|
+
case ClientEventTypes.CLIENT_JOINED: {
|
|
164
349
|
if (event.timestamp) {
|
|
165
350
|
if (!this.joinedAt) {
|
|
166
351
|
this.joinedAt = event.timestamp;
|
|
@@ -174,76 +359,208 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
174
359
|
}
|
|
175
360
|
break;
|
|
176
361
|
}
|
|
177
|
-
case
|
|
362
|
+
case ClientEventTypes.CLIENT_LEFT: {
|
|
178
363
|
if (event.timestamp) {
|
|
179
364
|
if (!this.leftAt) {
|
|
180
365
|
this.leftAt = event.timestamp;
|
|
181
366
|
this.emit('left');
|
|
367
|
+
} else {
|
|
368
|
+
logger.warn(`Client ${this.clientId} leftAt timestamp was already set`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
case ClientEventTypes.PEER_CONNECTION_OPENED: {
|
|
374
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
375
|
+
|
|
376
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
|
|
377
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
378
|
+
|
|
379
|
+
if (observedPeerConnection) {
|
|
380
|
+
observedPeerConnection.openedAt = event.timestamp;
|
|
381
|
+
} else if (postBuffer) {
|
|
382
|
+
postBuffer.push(event);
|
|
383
|
+
} else {
|
|
384
|
+
logger.warn('Received PEER_CONNECTION_OPENED event without a corresponding observedPeerConnection', event);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
case ClientEventTypes.PEER_CONNECTION_CLOSED: {
|
|
391
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
392
|
+
|
|
393
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
|
|
394
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
395
|
+
|
|
396
|
+
if (observedPeerConnection) {
|
|
397
|
+
observedPeerConnection.closedAt = event.timestamp;
|
|
398
|
+
} else if (postBuffer) {
|
|
399
|
+
postBuffer.push(event);
|
|
400
|
+
} else {
|
|
401
|
+
logger.warn('Received PEER_CONNECTION_CLOSED event without a corresponding observedPeerConnection', event);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
case ClientEventTypes.MEDIA_TRACK_ADDED: {
|
|
407
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
408
|
+
|
|
409
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
410
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
411
|
+
const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
412
|
+
|
|
413
|
+
if (observedTrack) {
|
|
414
|
+
observedTrack.addedAt = event.timestamp;
|
|
415
|
+
} else if (postBuffer) {
|
|
416
|
+
postBuffer.push(event);
|
|
417
|
+
} else {
|
|
418
|
+
logger.warn('Received MEDIA_TRACK_ADDED event without a corresponding observedPeerConnection or observedTrack', event);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
case ClientEventTypes.MEDIA_TRACK_REMOVED: {
|
|
424
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
425
|
+
|
|
426
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
427
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
428
|
+
const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
429
|
+
|
|
430
|
+
if (observedTrack) {
|
|
431
|
+
observedTrack.removedAt = event.timestamp;
|
|
432
|
+
} else if (postBuffer) {
|
|
433
|
+
postBuffer.push(event);
|
|
434
|
+
} else {
|
|
435
|
+
logger.warn('Received MEDIA_TRACK_REMOVED event without a corresponding observedPeerConnection or observedTrack', event);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
case ClientEventTypes.DATA_CHANNEL_OPEN: {
|
|
441
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
442
|
+
|
|
443
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
|
|
444
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
445
|
+
const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
|
|
446
|
+
|
|
447
|
+
if (observedDataChannel) {
|
|
448
|
+
observedDataChannel.addedAt = event.timestamp;
|
|
449
|
+
} else if (postBuffer) {
|
|
450
|
+
postBuffer.push(event);
|
|
451
|
+
} else {
|
|
452
|
+
logger.warn('Received DATA_CHANNEL_OPENED event without a corresponding observedPeerConnection or observedDataChannel', event);
|
|
182
453
|
}
|
|
183
454
|
}
|
|
184
455
|
break;
|
|
185
456
|
}
|
|
457
|
+
case ClientEventTypes.DATA_CHANNEL_CLOSED: {
|
|
458
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
459
|
+
|
|
460
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
|
|
461
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
462
|
+
const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
|
|
463
|
+
|
|
464
|
+
if (observedDataChannel) {
|
|
465
|
+
observedDataChannel.removedAt = event.timestamp;
|
|
466
|
+
} else if (postBuffer) {
|
|
467
|
+
postBuffer.push(event);
|
|
468
|
+
} else {
|
|
469
|
+
logger.warn('Received DATA_CHANNEL_CLOSE event without a corresponding observedPeerConnection or observedDataChannel', event);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
|
|
186
475
|
}
|
|
476
|
+
}
|
|
187
477
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
478
|
+
public injectMetaData(metaData: ClientMetaData) {
|
|
479
|
+
if (this.closed) return;
|
|
480
|
+
|
|
481
|
+
if (!this._injections.clientMetaItems) this._injections.clientMetaItems = [];
|
|
482
|
+
|
|
483
|
+
this._injections.clientMetaItems.push(metaData);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
public injectEvent(event: ClientEvent) {
|
|
487
|
+
if (this.closed) return;
|
|
488
|
+
|
|
489
|
+
if (!this._injections.clientEvents) this._injections.clientEvents = [];
|
|
490
|
+
|
|
491
|
+
this._injections.clientEvents.push(event);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
public injectIssue(issue: ClientIssue) {
|
|
495
|
+
if (this.closed) return;
|
|
496
|
+
|
|
497
|
+
if (!this._injections.clientIssues) this._injections.clientIssues = [];
|
|
498
|
+
|
|
499
|
+
this._injections.clientIssues.push(issue);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
public injectExtensionStat(stat: ExtensionStat) {
|
|
503
|
+
if (this.closed) return;
|
|
504
|
+
|
|
505
|
+
if (!this._injections.extensionStats) this._injections.extensionStats = [];
|
|
506
|
+
|
|
507
|
+
this._injections.extensionStats.push(stat);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
public injectAttachment(key: string, value: unknown) {
|
|
511
|
+
if (this.closed) return;
|
|
512
|
+
|
|
513
|
+
if (!this._injections.attachments) this._injections.attachments = {};
|
|
514
|
+
|
|
515
|
+
this._injections.attachments[key] = value;
|
|
516
|
+
|
|
193
517
|
}
|
|
194
518
|
|
|
195
|
-
public
|
|
519
|
+
public addMetadata(metadata: ClientMetaData) {
|
|
520
|
+
if (this.closed) return;
|
|
521
|
+
|
|
196
522
|
switch (metadata.type) {
|
|
197
|
-
case
|
|
523
|
+
case ClientMetaTypes.BROWSER: {
|
|
198
524
|
this.browser = parseJsonAs(metadata.payload);
|
|
199
525
|
break;
|
|
200
526
|
}
|
|
201
|
-
case
|
|
527
|
+
case ClientMetaTypes.ENGINE: {
|
|
202
528
|
this.engine = parseJsonAs(metadata.payload);
|
|
203
529
|
break;
|
|
204
530
|
}
|
|
205
|
-
case
|
|
531
|
+
case ClientMetaTypes.PLATFORM: {
|
|
206
532
|
this.platform = parseJsonAs(metadata.payload);
|
|
207
533
|
break;
|
|
208
534
|
}
|
|
209
|
-
case
|
|
535
|
+
case ClientMetaTypes.OPERATION_SYSTEM: {
|
|
210
536
|
this.operationSystem = parseJsonAs(metadata.payload);
|
|
211
537
|
break;
|
|
212
538
|
}
|
|
213
539
|
}
|
|
214
540
|
|
|
215
|
-
this.call.observer.
|
|
216
|
-
call: this.call,
|
|
217
|
-
client: this,
|
|
218
|
-
data: metadata,
|
|
219
|
-
});
|
|
541
|
+
this.call.observer.emit('client-metadata', this, metadata);
|
|
220
542
|
}
|
|
221
543
|
|
|
222
|
-
public
|
|
223
|
-
this.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
});
|
|
544
|
+
public addIssue(issue: ClientIssue) {
|
|
545
|
+
if (this.closed) return;
|
|
546
|
+
|
|
547
|
+
this.emit('issue', issue);
|
|
548
|
+
this.call.observer.emit('client-issue', this, issue);
|
|
228
549
|
}
|
|
229
550
|
|
|
230
|
-
public
|
|
231
|
-
this.call.observer.
|
|
232
|
-
call: this.call,
|
|
233
|
-
client: this,
|
|
234
|
-
data: stats,
|
|
235
|
-
});
|
|
551
|
+
public addExtensionStats(stats: ExtensionStat) {
|
|
552
|
+
this.call.observer.emit('client-extension-stats', this, stats);
|
|
236
553
|
}
|
|
237
554
|
|
|
238
|
-
private _updatePeerConnection(sample: PeerConnectionSample) {
|
|
555
|
+
private _updatePeerConnection(sample: PeerConnectionSample): ObservedPeerConnection | undefined {
|
|
239
556
|
let observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);
|
|
240
557
|
|
|
241
558
|
if (!observedPeerConnection) {
|
|
242
559
|
if (!sample.peerConnectionId) {
|
|
243
|
-
return logger.warn(
|
|
560
|
+
return (logger.warn(
|
|
244
561
|
`ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,
|
|
245
562
|
sample
|
|
246
|
-
);
|
|
563
|
+
), void 0);
|
|
247
564
|
}
|
|
248
565
|
|
|
249
566
|
observedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
|
|
@@ -252,8 +569,105 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
252
569
|
this.observedPeerConnections.delete(sample.peerConnectionId);
|
|
253
570
|
});
|
|
254
571
|
this.observedPeerConnections.set(sample.peerConnectionId, observedPeerConnection);
|
|
572
|
+
|
|
573
|
+
this.emit('newpeerconnection', observedPeerConnection);
|
|
255
574
|
}
|
|
256
575
|
|
|
257
576
|
observedPeerConnection.accept(sample);
|
|
577
|
+
|
|
578
|
+
return observedPeerConnection;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
public createEventMonitor<CTX = unknown>(ctx?: CTX): ObservedClientEventMonitor<CTX> {
|
|
582
|
+
return new ObservedClientEventMonitor<CTX>(this, ctx ?? {} as CTX);
|
|
258
583
|
}
|
|
584
|
+
|
|
585
|
+
private _mergeInjections(sample: ClientSample): ClientSample {
|
|
586
|
+
if (this.closed) return sample;
|
|
587
|
+
|
|
588
|
+
if (this._injections.clientEvents) {
|
|
589
|
+
if (!sample.clientEvents) sample.clientEvents = [];
|
|
590
|
+
sample.clientEvents.push(...this._injections.clientEvents);
|
|
591
|
+
|
|
592
|
+
this._injections.clientEvents = undefined;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (this._injections.clientIssues) {
|
|
596
|
+
if (!sample.clientIssues) sample.clientIssues = [];
|
|
597
|
+
sample.clientIssues.push(...this._injections.clientIssues);
|
|
598
|
+
|
|
599
|
+
this._injections.clientIssues = undefined;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if (this._injections.extensionStats) {
|
|
603
|
+
if (!sample.extensionStats) sample.extensionStats = [];
|
|
604
|
+
sample.extensionStats.push(...this._injections.extensionStats);
|
|
605
|
+
|
|
606
|
+
this._injections.extensionStats = undefined;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (this._injections.attachments) {
|
|
610
|
+
if (!sample.attachments) sample.attachments = {};
|
|
611
|
+
Object.assign(sample.attachments, this._injections.attachments);
|
|
612
|
+
|
|
613
|
+
this._injections.attachments = undefined;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if (this._injections.clientMetaItems) {
|
|
617
|
+
if (!sample.clientMetaItems) sample.clientMetaItems = [];
|
|
618
|
+
sample.clientMetaItems.push(...this._injections.clientMetaItems);
|
|
619
|
+
|
|
620
|
+
this._injections.clientMetaItems = undefined;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
return sample;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// public resetSummaryMetrics() {
|
|
627
|
+
// this.totalDataChannelBytesReceived = 0;
|
|
628
|
+
// this.totalDataChannelBytesSent = 0;
|
|
629
|
+
// this.totalDataChannelMessagesReceived = 0;
|
|
630
|
+
// this.totalDataChannelMessagesSent = 0;
|
|
631
|
+
// this.totalInboundPacketsLost = 0;
|
|
632
|
+
// this.totalInboundPacketsReceived = 0;
|
|
633
|
+
// this.totalOutboundPacketsSent = 0;
|
|
634
|
+
// this.totalReceivedAudioBytes = 0;
|
|
635
|
+
// this.totalReceivedVideoBytes = 0;
|
|
636
|
+
// this.totalSentAudioBytes = 0;
|
|
637
|
+
// this.totalSentVideoBytes = 0;
|
|
638
|
+
// this.totalSentBytes = 0;
|
|
639
|
+
// this.totalReceivedBytes = 0;
|
|
640
|
+
|
|
641
|
+
// this.totalNumberOfIssues = 0;
|
|
642
|
+
|
|
643
|
+
// this.totalScoreSum = 0;
|
|
644
|
+
// this.numberOfScoreMeasurements = 0;
|
|
645
|
+
// }
|
|
646
|
+
|
|
647
|
+
// public createSummary(): ObservedClientSummary {
|
|
648
|
+
// return {
|
|
649
|
+
// totalRttLt50Measurements: this.totalRttLt50Measurements,
|
|
650
|
+
// totalRttLt150Measurements: this.totalRttLt150Measurements,
|
|
651
|
+
// totalRttLt300Measurements: this.totalRttLt300Measurements,
|
|
652
|
+
// totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
|
|
653
|
+
// totalDataChannelBytesReceived: this.totalDataChannelBytesReceived,
|
|
654
|
+
// totalDataChannelBytesSent: this.totalDataChannelBytesSent,
|
|
655
|
+
// totalDataChannelMessagesReceived: this.totalDataChannelMessagesReceived,
|
|
656
|
+
// totalDataChannelMessagesSent: this.totalDataChannelMessagesSent,
|
|
657
|
+
// totalInboundPacketsLost: this.totalInboundPacketsLost,
|
|
658
|
+
// totalInboundPacketsReceived: this.totalInboundPacketsReceived,
|
|
659
|
+
// totalOutboundPacketsSent: this.totalOutboundPacketsSent,
|
|
660
|
+
// totalReceivedAudioBytes: this.totalReceivedAudioBytes,
|
|
661
|
+
// totalReceivedVideoBytes: this.totalReceivedVideoBytes,
|
|
662
|
+
// totalSentAudioBytes: this.totalSentAudioBytes,
|
|
663
|
+
// totalSentVideoBytes: this.totalSentVideoBytes,
|
|
664
|
+
// totalSentBytes: this.totalSentBytes,
|
|
665
|
+
// totalReceivedBytes: this.totalReceivedBytes,
|
|
666
|
+
|
|
667
|
+
// numberOfIssues: this.totalNumberOfIssues,
|
|
668
|
+
|
|
669
|
+
// totalScoreSum: this.totalScoreSum,
|
|
670
|
+
// numberOfScoreMeasurements: this.numberOfScoreMeasurements,
|
|
671
|
+
// };
|
|
672
|
+
// }
|
|
259
673
|
}
|