diff --git a/src/WsHandler.js b/src/WsHandler.js index 38d88c41..3edee5c1 100644 --- a/src/WsHandler.js +++ b/src/WsHandler.js @@ -1,4 +1,5 @@ const JSONStream = require('JSONStream'); +const path = require('path'); const { pipeline } = require('stream'); const url = require('url'); const WebSocket = require('ws'); @@ -8,8 +9,8 @@ const DemuxSink = require('./demux'); const logger = require('./logging'); const PromCollector = require('./metrics/PromCollector'); const { getStatsFormat } = require('./utils/stats-detection'); -const { extractTenantDataFromUrl } = require('./utils/utils'); const { RequestType } = require('./utils/utils'); +const cwd = process.cwd(); /** * @@ -20,13 +21,14 @@ class WsHandler { * */ constructor({ tempPath, reconnectTimeout, sequenceNumberSendingInterval, workerPool, config }) { - this.sessionTimeoutId = {}; + this.sessionTimeoutIds = {}; this.tempPath = tempPath; this.reconnectTimeout = reconnectTimeout; this.sequenceNumberSendingInterval = sequenceNumberSendingInterval; this.processData = this.processData.bind(this); this.workerPool = workerPool; this.config = config; + this.dumpFolder = './temp'; } /** @@ -46,29 +48,15 @@ class WsHandler { * @param {*} meta * @param {*} connectionInfo */ - processData(id, meta, connectionInfo, tenantInfo) { + processData(id, dumpPath, connectionInfo) { logger.info('[WsHandler] Queue for processing id %s', id); // Metadata associated with a dump can get large so just select the necessary fields. const dumpData = { - app: meta.applicationName || 'Undefined', clientId: id, - conferenceId: meta.confName, - conferenceUrl: meta.confID, - dumpPath: meta.dumpPath, + dumpPath, endDate: Date.now(), - endpointId: meta.endpointId, - startDate: meta.startDate, - sessionId: meta.meetingUniqueId, - userId: meta.displayName, - ampSessionId: meta.sessionId, - ampUserId: meta.userId, - ampDeviceId: meta.deviceId, - statsFormat: connectionInfo.statsFormat, - isBreakoutRoom: meta.isBreakoutRoom, - breakoutRoomId: meta.roomId, - parentStatsSessionId: meta.parentStatsSessionId, - ...tenantInfo + startDate: connectionInfo.startDate }; // Don't process dumps generated by JVB & Jigasi, there should be a more formal process to @@ -101,10 +89,11 @@ class WsHandler { const ua = upgradeReq.headers['user-agent']; const queryObject = url.parse(referer, true).query; const statsSessionId = queryObject?.statsSessionId; + const dumpPath = this._getDumpPath(statsSessionId); this._clearConnectionTimeout(statsSessionId); const connectionInfo = this._createConnectionInfo(upgradeReq, referer, ua, client); - const demuxSink = this._createDemuxSink(connectionInfo); + const demuxSink = this._createDemuxSink(dumpPath, connectionInfo); logger.info('[WsHandler] Client connected: %s', statsSessionId); @@ -113,7 +102,7 @@ class WsHandler { clientMessageHandler.sendLastSequenceNumber(true); - demuxSink.on('close-sink', ({ id, meta }) => { + demuxSink.on('close-sink', ({ id }) => { logger.info( '[WsHandler] Websocket disconnected waiting for processing the data %s in %d ms', @@ -121,15 +110,12 @@ class WsHandler { this.reconnectTimeout ); - const { confID = '' } = meta; - const tenantInfo = extractTenantDataFromUrl(confID); - const timeoutId = setTimeout(this.processData, this.reconnectTimeout, - id, meta, connectionInfo, tenantInfo + id, dumpPath, connectionInfo ); - this.sessionTimeoutId[id] = timeoutId; + this.sessionTimeoutIds[id] = timeoutId; }); const connectionPipeline = pipeline( @@ -175,17 +161,25 @@ class WsHandler { /** * */ - _createDemuxSink(connectionInfo) { + _createDemuxSink(dumpPath, connectionInfo) { const demuxSinkOptions = { tempPath: this.tempPath, connectionInfo, - dumpFolder: './temp', + dumpPath, + dumpFolder: this.dumpFolder, log: logger }; return new DemuxSink(demuxSinkOptions); } + /** + * + */ + _getDumpPath(statsSessionId) { + return path.resolve(cwd, this.dumpFolder, statsSessionId); + } + /** * */ @@ -212,7 +206,8 @@ class WsHandler { origin: upgradeReq.headers.origin, url: referer, userAgent: ua, - clientProtocol: client.protocol + clientProtocol: client.protocol, + startDate: Date.now() }; connectionInfo.statsFormat = getStatsFormat(connectionInfo); @@ -226,11 +221,11 @@ class WsHandler { * @param {*} timeoutId */ _clearConnectionTimeout(sessionId) { - const timeoutId = this.sessionTimeoutId[sessionId]; + const timeoutId = this.sessionTimeoutIds[sessionId]; if (timeoutId) { clearTimeout(timeoutId); - delete this.sessionTimeoutId[timeoutId]; + delete this.sessionTimeoutIds[timeoutId]; logger.info('[WsHandler] Client reconnected. Clear timeout for connectionId: %s', sessionId); PromCollector.clientReconnectedCount.inc(); } diff --git a/src/app.js b/src/app.js index 46d7651f..d3bba40b 100644 --- a/src/app.js +++ b/src/app.js @@ -16,9 +16,6 @@ const FeaturesPublisher = require('./database/FeaturesPublisher'); const FirehoseConnector = require('./database/FirehoseConnector'); const logger = require('./logging'); const PromCollector = require('./metrics/PromCollector'); -const S3Manager = require('./store/S3Manager'); -const { saveEntryAssureUnique } = require('./store/dynamo'); -const { getStatsFormat } = require('./utils/stats-detection'); const { getEnvName, getIdealWorkerCount, ResponseType, diff --git a/src/demux.js b/src/demux.js index e1d6b100..397bf618 100644 --- a/src/demux.js +++ b/src/demux.js @@ -1,17 +1,12 @@ const fs = require('fs'); const sizeof = require('object-sizeof'); -const path = require('path'); const { Writable } = require('stream'); const util = require('util'); const PromCollector = require('./metrics/PromCollector.js'); -const fileStore = require('./store/file'); const utils = require('./utils/utils'); const { uuidV4 } = require('./utils/utils.js'); - -const cwd = process.cwd(); - // we are using this because we want the regular file descriptors returned, // not the FileHandle objects from fs.promises.open const fsOpen = util.promisify(fs.open); @@ -45,10 +40,11 @@ class DemuxSink extends Writable { * @param {boolean} persistDump - Flag used for generating a complete dump of the data coming to the stream. * Required when creating mock tests. */ - constructor({ tempPath, dumpFolder, connectionInfo, log, persistDump = false }) { + constructor({ tempPath, dumpFolder, dumpPath, connectionInfo, log, persistDump = false }) { super({ objectMode: true }); this.dumpFolder = dumpFolder; + this.dumpPath = dumpPath; this.connectionInfo = connectionInfo; this.log = log; this.timeoutId = -1; @@ -144,7 +140,7 @@ class DemuxSink extends Writable { * * @param {string} id - sink id as saved in the sinkMap */ - _handleSinkClose(id, meta) { + _handleSinkClose(id) { const sinkData = this.sinkMap.get(id); // Sanity check, make sure the data is available if not log an error and just send the id such that any @@ -152,8 +148,7 @@ class DemuxSink extends Writable { if (sinkData) { // we need to emit this on file stream finish this.emit('close-sink', { - id: sinkData.id, - meta: this._updateMeta(sinkData.meta, meta) + id: sinkData.id }); } else { this.log.error('[Demux] sink on close meta should be available id:', id); @@ -173,50 +168,29 @@ class DemuxSink extends Writable { PromCollector.sessionCount.inc(); const resolvedId = id; - let fd; - - const idealPath = path.resolve(cwd, this.dumpFolder, id); - const filePath = idealPath; - const isReconnect = fs.existsSync(filePath); - - // If a client reconnects the same client id will be provided thus cases can occur where the previous dump - // with the same id is still present on the disk, in order to avoid conflicts and states where multiple - // handles are taken on the same file, we establish a convention appending an incremental number at the end - // of the file ${id}_${i}. Thus any client that needs to read the dumps can search for ${id} and get an - // incremental list. - // Warning. This will resolve local reconnect conflicts, when uploading the associated metadata to a store - // logic that handles conflicts at the store level also needs to be added e.g. when uploading to dynamodb - // if the entry already exists because some other instance uploaded first, the same incremental approach needs - // to be taken. - while (!fd) { - fd = await fsOpen(filePath, 'a'); - } + const isReconnect = fs.existsSync(this.dumpPath); + const fd = await fsOpen(this.dumpPath, 'a'); - this.log.info('[Demux] open-sink id: %s; path %s; connection: %o', id, filePath, this.connectionInfo); + this.log.info('[Demux] open-sink id: %s; path %s; connection: %o', id, this.dumpPath, this.connectionInfo); - const sink = fs.createWriteStream(idealPath, { fd }); + const sink = fs.createWriteStream(this.dumpPath, { fd }); // Add the associated data to a map in order to properly direct requests to the appropriate sink. const sinkData = { id: resolvedId, sink, meta: { - startDate: Date.now(), - dumpPath: filePath + startDate: this.startDate, + dumpPath: this.dumpPath } }; this.sinkMap.set(id, sinkData); sink.on('error', error => this.log.error('[Demux] sink on error id: ', id, ' error:', error)); - let identity; - - if (isReconnect) { - identity = await this._getIdentityFromFile(sinkData.id); - } // The close event should be emitted both on error and happy flow. - sink.on('close', this._handleSinkClose.bind(this, id, identity)); + sink.on('close', this._handleSinkClose.bind(this, id)); if (!isReconnect) { // Initialize the dump file by adding the connection metadata at the beginning. This data is usually used @@ -237,48 +211,10 @@ class DemuxSink extends Writable { * @param {Object} data - New metadata. */ async _sinkUpdateMetadata(sinkData, data) { - let metadata; - - // Browser clients will send identity data as an array so we need to extract the element that contains - // the actual metadata - if (Array.isArray(data)) { - metadata = data[2]; - } else { - metadata = data; - } - - const meta = sinkData.meta; - - // A first level update of the properties will suffice. - sinkData.meta = this._updateMeta(meta, metadata); - // We expect metadata to be objects thus we need to stringify them before writing to the sink. this._sinkWrite(sinkData.sink, JSON.stringify(data)); } - /** - * - * @param {*} meta - * @param {*} metadata - * @returns - */ - _updateMeta(meta, metadata) { - return { - ...meta, - ...metadata - }; - } - - /** - * Getting identity from file in case of reconnect. - */ - async _getIdentityFromFile(fname) { - const filePath = utils.getDumpPath(this.tempPath, fname); - const { identity = '' } = await fileStore.getObjectsByKeys(filePath, [ 'identity' ]); - - return identity; - } - /** * Self explanatory. * diff --git a/src/features/FeatureExtractor.js b/src/features/FeatureExtractor.js index a703aee8..40f8b7cb 100644 --- a/src/features/FeatureExtractor.js +++ b/src/features/FeatureExtractor.js @@ -8,6 +8,7 @@ const readline = require('readline'); const logger = require('../logging'); const statsDecompressor = require('../utils//getstats-deltacompression').decompress; const { getStatsFormat, getBrowserDetails } = require('../utils/stats-detection'); +const { extractTenantDataFromUrl } = require('../utils/utils'); const QualityStatsCollector = require('./quality-stats/QualityStatsCollector'); const StatsAggregator = require('./quality-stats/StatsAggregator'); @@ -30,10 +31,13 @@ class FeatureExtractor { statsFormat } = dumpInfo; + this.dumpInfo = {}; + this.dumpPath = dumpPath; this.endpointId = endpointId; if (statsFormat) { this.statsFormat = statsFormat; + this.dumpInfo.statsFormat = statsFormat; this.collector = new QualityStatsCollector(statsFormat); } @@ -142,9 +146,14 @@ class FeatureExtractor { if (!this.statsFormat) { this.statsFormat = getStatsFormat(connectionInfoJson); + this.dumpInfo.statsFormat = this.statsFormat; this.collector = new QualityStatsCollector(this.statsFormat); } + if (typeof connectionInfoJson?.startDate !== 'undefined') { + this.dumpInfo.startDate = connectionInfoJson?.startDate; + } + const browserDetails = getBrowserDetails(connectionInfoJson); if (browserDetails) { @@ -154,17 +163,32 @@ class FeatureExtractor { _handleIdentity = dumpLineObj => { const [ , , identityEntry ] = dumpLineObj; + const { deploymentInfo: { crossRegion, envType, environment, region, releaseNumber, shard, - userRegion } = { } } = identityEntry; + userRegion } = {} } = identityEntry; - if (!this.endpointId) { - const { endpointId } = identityEntry; + const { + endpointId, + confID, + applicationName, + confName, + meetingUniqueId, + displayName, + sessionId, + userId, + deviceId, + isBreakoutRoom, + roomId, + parentStatsSessionId + } = identityEntry; + + if (!this.endpointId) { this.endpointId = endpointId; } @@ -180,6 +204,50 @@ class FeatureExtractor { shard, userRegion }; + + if (typeof applicationName !== 'undefined') { + this.dumpInfo.app = applicationName; + } + if (typeof confName !== 'undefined') { + this.dumpInfo.conferenceId = confName; + } + if (typeof confID !== 'undefined') { + this.dumpInfo.conferenceUrl = confID; + } + if (typeof endpointId !== 'undefined') { + this.dumpInfo.endpointId = endpointId; + } + if (typeof meetingUniqueId !== 'undefined') { + this.dumpInfo.sessionId = meetingUniqueId; + } + if (typeof displayName !== 'undefined') { + this.dumpInfo.userId = displayName; + } + if (typeof sessionId !== 'undefined') { + this.dumpInfo.ampSessionId = sessionId; + } + if (typeof userId !== 'undefined') { + this.dumpInfo.ampUserId = userId; + } + if (typeof deviceId !== 'undefined') { + this.dumpInfo.ampDeviceId = deviceId; + } + if (typeof isBreakoutRoom !== 'undefined') { + this.dumpInfo.isBreakoutRoom = isBreakoutRoom; + } + if (typeof roomId !== 'undefined') { + this.dumpInfo.breakoutRoomId = roomId; + } + if (typeof parentStatsSessionId !== 'undefined') { + this.dumpInfo.parentStatsSessionId = parentStatsSessionId; + } + + const tenantInfo = extractTenantDataFromUrl(confID); + + this.dumpInfo.tenant = tenantInfo.tenant; + this.dumpInfo.jaasMeetingFqn = tenantInfo.jaasMeetingFqn; + this.dumpInfo.jaasClientId = tenantInfo.jaasClientId; + this.dumpInfo.isJaaSTenant = tenantInfo.isJaaSTenant; }; /** @@ -252,19 +320,25 @@ class FeatureExtractor { // Check if the current sessions's user is the new dominant speaker, if so mark it with an event. if (newDominantSpeaker === this.endpointId) { - dominantSpeakerEvents.push({ type: 'DOMINANT_SPEAKER_STARTED', - timestamp }); + dominantSpeakerEvents.push({ + type: 'DOMINANT_SPEAKER_STARTED', + timestamp + }); - // If the previous dominant speaker was the current session's user that means that he is no longer the dominant - // speaker so we mark that with an event. + // If the previous dominant speaker was the current session's user that means that he is no longer the dominant + // speaker so we mark that with an event. } else if (currentDominantSpeaker === this.endpointId) { - dominantSpeakerEvents.push({ type: 'DOMINANT_SPEAKER_STOPPED', - timestamp }); + dominantSpeakerEvents.push({ + type: 'DOMINANT_SPEAKER_STOPPED', + timestamp + }); } // Initialize speakerStats for endpoint if not present. - speakerStats[newDominantSpeaker] ??= { speakerTime: 0, - dominantSpeakerChanges: 0 }; + speakerStats[newDominantSpeaker] ??= { + speakerTime: 0, + dominantSpeakerChanges: 0 + }; const { [newDominantSpeaker]: newDominantSpeakerStats } = speakerStats; @@ -524,7 +598,10 @@ class FeatureExtractor { logger.debug('Aggregate results: %o', aggregateResults); - return this.features; + return { + features: this.features, + dumpInfo: this.dumpInfo + }; } } diff --git a/src/test/client.js b/src/test/client.js index c7e95413..516df8eb 100644 --- a/src/test/client.js +++ b/src/test/client.js @@ -11,6 +11,9 @@ const server = require('../app'); const logger = require('../logging'); const { uuidV4, ResponseType } = require('../utils/utils'); +const dumpPath = './src/test/dumps/'; +const jestResultsPath = './src/test/jest/results/'; + let testCheckRouter; process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // ignore self-signed cert @@ -40,10 +43,10 @@ class RtcstatsConnection extends EventEmitter { * * @param {*} param0 */ - constructor({ id, serverUrl, dumpPath, readDelay = 1000, wsOptions, protocolV, statsSessionId }) { + constructor({ id, serverUrl, filePath, readDelay = 1000, wsOptions, protocolV, statsSessionId }) { super(); this.id = id; - this.dumpPath = dumpPath; + this.filePath = filePath; this.serverUrl = serverUrl; this.wsOptions = wsOptions; this.readDelay = readDelay; @@ -51,8 +54,6 @@ class RtcstatsConnection extends EventEmitter { this.statsSessionId = statsSessionId; this.lastLine = 0; this.disconnected = false; - - this._createIdentityData(); } /** @@ -62,13 +63,6 @@ class RtcstatsConnection extends EventEmitter { return this.statsSessionId; } - /** - * - */ - getIdentityData() { - return this.identityData; - } - /** * */ @@ -81,41 +75,6 @@ class RtcstatsConnection extends EventEmitter { this.ws.on('error', this._error); } - /** - * - */ - _createIdentityData() { - this.identityData = { - sessionId: new Date().getTime(), - deviceId: uuidV4(), - applicationName: 'Integration Test', - confID: `192.168.1.1/conf-${this.statsSessionId}`, - displayName: `test-${this.statsSessionId}`, - meetingUniqueId: uuidV4(), - statsSessionId: this.statsSessionId - }; - } - - /** - * - */ - _sendIdentity() { - const identity = [ - 'identity', - null, - this.identityData, - new Date() - ]; - - const identityRequest = { - statsSessionId: this.statsSessionId, - type: 'identity', - data: identity - }; - - this._sendRequest(identityRequest); - } - /** * * @param {*} data @@ -148,12 +107,11 @@ class RtcstatsConnection extends EventEmitter { if (this.lastLine === 0) { logger.info(`Connected ws ${this.id} setup time ${endWSOpen}`); - this._sendIdentity(); } else { logger.info(`Reconnected ws ${this.id} setup time ${endWSOpen}`); } - this.lineReader = new LineByLine(this.dumpPath); + this.lineReader = new LineByLine(this.filePath); let lineNumber = 0; this.lineReader.on('line', line => { @@ -287,7 +245,7 @@ class TestCheckRouter { */ function checkTestCompletion(appServer) { - if (appServer.PromCollector.processed.get().values[0].value === 7) { + if (appServer.PromCollector.processed.get().values[0].value === 4) { appServer.stop(); } else { setTimeout(checkTestCompletion, 8000, appServer); @@ -296,12 +254,17 @@ function checkTestCompletion(appServer) { /** * + * @param {*} file * @param {*} dumpPath * @param {*} resultPath + * @param {*} ua + * @param {*} protocolV */ -function simulateConnection(dumpPath, resultPath, ua, protocolV) { - this.disconnected = false; +function simulateConnection(file, resultFile, ua, protocolV) { + const filePath = dumpPath + file; + const resultPath = jestResultsPath + resultFile; + this.disconnected = false; const resultString = fs.readFileSync(resultPath); const resultList = JSON.parse(resultString); @@ -316,9 +279,9 @@ function simulateConnection(dumpPath, resultPath, ua, protocolV) { }; const rtcstatsWsOptions = { - id: dumpPath, + id: file, serverUrl: `ws://localhost:3000/?statsSessionId=${statsSessionId}`, - dumpPath, + filePath, readDelay: 1, wsOptions, protocolV, @@ -327,26 +290,16 @@ function simulateConnection(dumpPath, resultPath, ua, protocolV) { const connection = new RtcstatsConnection(rtcstatsWsOptions); - const identityData = connection.getIdentityData(); - testCheckRouter.attachTest({ statsSessionId, checkDoneResponse: body => { const parsedBody = JSON.parse(JSON.stringify(body)); resultList.shift(); - resultTemplate.dumpInfo.clientId = statsSessionId; - resultTemplate.dumpInfo.userId = identityData.displayName; - resultTemplate.dumpInfo.app = identityData.applicationName; - resultTemplate.dumpInfo.sessionId = identityData.meetingUniqueId; - resultTemplate.dumpInfo.ampDeviceId = identityData.deviceId; - resultTemplate.dumpInfo.ampSessionId = identityData.sessionId; - resultTemplate.dumpInfo.conferenceUrl = identityData.confID; - - resultTemplate.dumpInfo.startDate = body.dumpInfo.startDate; - resultTemplate.dumpInfo.endDate = body.dumpInfo.endDate; resultTemplate.dumpInfo.dumpPath = body.dumpInfo.dumpPath; + resultTemplate.dumpInfo.endDate = body.dumpInfo.endDate; + resultTemplate.dumpInfo.startDate = body.dumpInfo.startDate; // The size of the dump changes with every iteration as the application will add an additional // 'connectionInfo' entry, thus metrics won't match. @@ -385,53 +338,53 @@ function runTest() { testCheckRouter = new TestCheckRouter(server); simulateConnection( - './src/test/dumps/google-standard-stats-p2p-reconnect', - './src/test/jest/results/google-standard-stats-p2p-result.json', + 'google-standard-stats-p2p-reconnect', + 'google-standard-stats-p2p-result.json', BrowserUASamples.CHROME, ProtocolV.STANDARD ); simulateConnection( - './src/test/dumps/google-standard-stats-p2p', - './src/test/jest/results/google-standard-stats-p2p-result.json', + 'google-standard-stats-p2p', + 'google-standard-stats-p2p-result.json', BrowserUASamples.CHROME, ProtocolV.STANDARD ); simulateConnection( - './src/test/dumps/google-standard-stats-sfu', - './src/test/jest/results/google-standard-stats-sfu-result.json', + 'google-standard-stats-sfu', + 'google-standard-stats-sfu-result.json', BrowserUASamples.CHROME, ProtocolV.STANDARD ); simulateConnection( - './src/test/dumps/firefox-standard-stats-sfu', - './src/test/jest/results/firefox-standard-stats-sfu-result.json', + 'firefox-standard-stats-sfu', + 'firefox-standard-stats-sfu-result.json', BrowserUASamples.FIREFOX, ProtocolV.STANDARD ); - simulateConnection( - './src/test/dumps/firefox97-standard-stats-sfu', - './src/test/jest/results/firefox97-standard-stats-sfu-result.json', - BrowserUASamples.FIREFOX, - ProtocolV.STANDARD - ); - - simulateConnection( - './src/test/dumps/safari-standard-stats', - './src/test/jest/results/safari-standard-stats-result.json', - BrowserUASamples.SAFARI, - ProtocolV.STANDARD - ); - - simulateConnection( - './src/test/dumps/chrome96-standard-stats-p2p-add-transceiver', - './src/test/jest/results/chrome96-standard-stats-p2p-add-transceiver-result.json', - BrowserUASamples.CHROME, - ProtocolV.STANDARD - ); + // simulateConnection( + // 'firefox97-standard-stats-sfu', + // 'firefox97-standard-stats-sfu-result.json', + // BrowserUASamples.FIREFOX, + // ProtocolV.STANDARD + // ); + + // simulateConnection( + // 'safari-standard-stats', + // 'safari-standard-stats-result.json', + // BrowserUASamples.SAFARI, + // ProtocolV.STANDARD + // ); + + // simulateConnection( + // 'chrome96-standard-stats-p2p-add-transceiver', + // 'chrome96-standard-stats-p2p-add-transceiver-result.json', + // BrowserUASamples.CHROME, + // ProtocolV.STANDARD + // ); } setTimeout(runTest, 6000); diff --git a/src/test/jest/extract.test.js b/src/test/jest/extract.test.js index f4371fb8..bd6865b4 100644 --- a/src/test/jest/extract.test.js +++ b/src/test/jest/extract.test.js @@ -34,7 +34,7 @@ async function simulateConnection(dumpPath, expectedResultPath, statsFormat) { }); } - assert.deepStrictEqual(actualFeatures, expectedResultList[0].features); + assert.deepStrictEqual(actualFeatures, expectedResultList[0]); } describe('Feature extraction tests', () => { diff --git a/src/test/jest/results/59c86272-03ea-42e9-a62d-1c8a272e8ab0.json b/src/test/jest/results/59c86272-03ea-42e9-a62d-1c8a272e8ab0.json index 27e7303c..5d86faa0 100644 --- a/src/test/jest/results/59c86272-03ea-42e9-a62d-1c8a272e8ab0.json +++ b/src/test/jest/results/59c86272-03ea-42e9-a62d-1c8a272e8ab0.json @@ -1,5 +1,21 @@ [ { + "dumpInfo": { + "ampDeviceId": "nrOILs0J1QkO0DoYUNhcnc", + "ampSessionId": 1651144262838, + "ampUserId": null, + "app": "Jitsi Meet", + "conferenceId": "ThrilledFirmsTellImmensely", + "conferenceUrl": "george.jitsi.net/thrilledfirmstellimmensely", + "endpointId": "78a1c829", + "sessionId": "9402252c-132d-4c9d-8f87-dcd8ae4def9d", + "statsFormat": "chrome_standard", + "userId": "Kelton-nfn", + "isJaaSTenant": false, + "jaasClientId": "", + "jaasMeetingFqn": "", + "tenant": "" + }, "features": { "aggregates": { "PC_0": { diff --git a/src/test/jest/results/9c93a447-c9f8-489d-87ca-21263dec0642.json b/src/test/jest/results/9c93a447-c9f8-489d-87ca-21263dec0642.json index b90de112..15b49281 100644 --- a/src/test/jest/results/9c93a447-c9f8-489d-87ca-21263dec0642.json +++ b/src/test/jest/results/9c93a447-c9f8-489d-87ca-21263dec0642.json @@ -1,5 +1,21 @@ [ { + "dumpInfo": { + "ampDeviceId": "8c884a6b-275a-4199-bb0f-8371abf939baR", + "ampSessionId": 1652352424131, + "ampUserId": null, + "app": "Jitsi Meet", + "conferenceId": "hello", + "conferenceUrl": "george.jitsi.net/hello", + "endpointId": "8c954a5e", + "sessionId": "0f1ba6a2-edbf-40e9-a677-f66b27775b21", + "statsFormat": "chrome_standard", + "userId": "Kevin-H4P", + "isJaaSTenant": false, + "jaasClientId": "", + "jaasMeetingFqn": "", + "tenant": "" + }, "features": { "aggregates": { "PC_0": { diff --git a/src/test/jest/results/chrome-standard-multiple-p2p.json b/src/test/jest/results/chrome-standard-multiple-p2p.json index 4485f97a..1fdc5d79 100644 --- a/src/test/jest/results/chrome-standard-multiple-p2p.json +++ b/src/test/jest/results/chrome-standard-multiple-p2p.json @@ -1,5 +1,21 @@ [ { + "dumpInfo": { + "ampDeviceId": "QK8hI_xnqqxOLZAJE0UHqK", + "ampSessionId": 1647251175641, + "ampUserId": null, + "app": "Jitsi Meet", + "conferenceId": "BottomBacteriasPinStraight", + "conferenceUrl": "0.0.0.0:8080/bottombacteriaspinstraight", + "endpointId": "372c0a27", + "sessionId": "ac0aaa8a-efa8-42ed-8a01-9c486105f6b0", + "statsFormat": "chrome_standard", + "userId": "Lesly-U1W", + "isJaaSTenant": false, + "jaasClientId": "", + "jaasMeetingFqn": "", + "tenant": "" + }, "features": { "aggregates": { "PC_0": { diff --git a/src/test/jest/results/chrome-standard-pc-failed.json b/src/test/jest/results/chrome-standard-pc-failed.json index 51546dc4..8827afbe 100644 --- a/src/test/jest/results/chrome-standard-pc-failed.json +++ b/src/test/jest/results/chrome-standard-pc-failed.json @@ -1,5 +1,21 @@ [ { + "dumpInfo": { + "ampDeviceId": "QK8hI_xnqqxOLZAJE0UHqK", + "ampSessionId": 1647265163968, + "ampUserId": null, + "app": "Jitsi Meet", + "conferenceId": "ProblematicLandmarksAssociateAbout", + "conferenceUrl": "192.168.245.128:8080/problematiclandmarksassociateabout", + "endpointId": "bf715c66", + "sessionId": "f90acd63-a86e-4351-b2fe-c584fa14893e", + "statsFormat": "chrome_standard", + "userId": "Lesly-U1W", + "isJaaSTenant": false, + "jaasClientId": "", + "jaasMeetingFqn": "", + "tenant": "" + }, "features": { "aggregates": { "PC_0": { diff --git a/src/test/jest/results/chrome-standard-pc-reconnect.json b/src/test/jest/results/chrome-standard-pc-reconnect.json index 2e9ce367..803c2680 100644 --- a/src/test/jest/results/chrome-standard-pc-reconnect.json +++ b/src/test/jest/results/chrome-standard-pc-reconnect.json @@ -1,5 +1,21 @@ [ { + "dumpInfo": { + "ampDeviceId": "QK8hI_xnqqxOLZAJE0UHqK", + "ampSessionId": 1647265163968, + "ampUserId": null, + "app": "Jitsi Meet", + "conferenceId": "ProblematicLandmarksAssociateAbout", + "conferenceUrl": "192.168.245.128:8080/problematiclandmarksassociateabout", + "endpointId": "69cebf74", + "sessionId": "f90acd63-a86e-4351-b2fe-c584fa14893e", + "statsFormat": "chrome_standard", + "userId": "Lesly-U1W", + "isJaaSTenant": false, + "jaasClientId": "", + "jaasMeetingFqn": "", + "tenant": "" + }, "features": { "aggregates": { "PC_0": { diff --git a/src/test/jest/results/chrome96-standard-stats-p2p-add-transceiver-result.json b/src/test/jest/results/chrome96-standard-stats-p2p-add-transceiver-result.json index 5189833a..f7947357 100644 --- a/src/test/jest/results/chrome96-standard-stats-p2p-add-transceiver-result.json +++ b/src/test/jest/results/chrome96-standard-stats-p2p-add-transceiver-result.json @@ -1,21 +1,20 @@ [ { "dumpInfo": { - "ampDeviceId": "8520fd54-ab35-4a4c-9454-45e17605914e", - "ampSessionId": 1641601089490, - "app": "Integration Test", - "clientId": "bac9ca22-8c8f-45a4-92a2-a3411cfe398a", - "conferenceUrl": "192.168.1.1/conf-bac9ca22-8c8f-45a4-92a2-a3411cfe398a", - "dumpPath": "/Users/nohlmeier/src/rtcstats-server/temp/bac9ca22-8c8f-45a4-92a2-a3411cfe398a", - "endDate": 1641601089568, + "ampDeviceId": "YP76a4HPQG5ORpCottXP7a", + "ampSessionId": 1640046540939, + "ampUserId": null, + "app": "Jitsi Meet", + "conferenceId": "ElderlyNetworksAcquireWeekly", + "conferenceUrl": "drno.jitsi.net/elderlynetworksacquireweekly", + "endpointId":"d58e53af", + "sessionId": "68282950-1f48-404a-a12e-9ed92f955a54", + "statsFormat": "chrome_standard", + "userId": "Nichole-ryS", "isJaaSTenant": false, "jaasClientId": "", "jaasMeetingFqn": "", - "sessionId": "b2ff55e1-c57e-4fc0-a003-54418278fa92", - "startDate": 1641601089525, - "statsFormat": "chrome_standard", - "tenant": "", - "userId": "test-bac9ca22-8c8f-45a4-92a2-a3411cfe398a" + "tenant": "" }, "features": { "aggregates": { diff --git a/src/test/jest/results/firefox-standard-stats-sfu-result.json b/src/test/jest/results/firefox-standard-stats-sfu-result.json index b17badbb..87241068 100644 --- a/src/test/jest/results/firefox-standard-stats-sfu-result.json +++ b/src/test/jest/results/firefox-standard-stats-sfu-result.json @@ -1,20 +1,13 @@ [ { "dumpInfo": { - "ampDeviceId": "60cba6ea-790a-4ec3-bf1c-b0d4f486c739", - "ampSessionId": 1641600699795, - "app": "Integration Test", - "clientId": "9195e361-2a5b-4749-923d-7f4d5d111c36", - "conferenceUrl": "192.168.1.1/conf-9195e361-2a5b-4749-923d-7f4d5d111c36", - "dumpPath": "/Users/nohlmeier/src/rtcstats-server/temp/9195e361-2a5b-4749-923d-7f4d5d111c36", - "endDate": 1641600699878, - "isJaaSTenant": false, - "jaasClientId": "", - "jaasMeetingFqn": "", - "sessionId": "d4fe59fa-d0ca-4984-9e8d-0ac8fd6780ed", - "startDate": 1641600699825, + "app": "Jitsi Meet", + "conferenceUrl": "192.168.1.234:8080/closeoutfitsusefast", + "userId": "andrei-mac-firefox", + "ampSessionId": 1605197691597, + "ampUserId": null, "statsFormat": "firefox", - "userId": "test-9195e361-2a5b-4749-923d-7f4d5d111c36", + "ampDeviceId": "TdETRFgU45V3rbsihHkA6w", "isJaaSTenant": false, "jaasClientId": "", "jaasMeetingFqn": "", diff --git a/src/test/jest/results/firefox97-standard-stats-sfu-result.json b/src/test/jest/results/firefox97-standard-stats-sfu-result.json index 220c38a0..a993095c 100644 --- a/src/test/jest/results/firefox97-standard-stats-sfu-result.json +++ b/src/test/jest/results/firefox97-standard-stats-sfu-result.json @@ -1,20 +1,16 @@ [ { "dumpInfo": { - "ampDeviceId": "d5f91167-4d2e-445b-a48d-492edcd3b3b9", - "ampSessionId": 1641864713012, - "app": "Integration Test", - "clientId": "9eb2f1a0-af02-443f-b97c-e415ecc857e7", - "conferenceUrl": "192.168.1.1/conf-9eb2f1a0-af02-443f-b97c-e415ecc857e7", - "dumpPath": "/Users/nohlmeier/src/rtcstats-server/temp/9eb2f1a0-af02-443f-b97c-e415ecc857e7", - "endDate": 1641864713064, - "isJaaSTenant": false, - "jaasClientId": "", - "jaasMeetingFqn": "", - "sessionId": "1e501074-10e3-48ec-99bd-9c402d53513c", - "startDate": 1641864713041, + "app": "Jitsi Meet", + "conferenceUrl": "drno.jitsi.net/obviousgroupsanticipatecertainly", + "userId": "Easter-BIy", + "ampSessionId": 1641860930491, + "ampUserId": null, + "ampDeviceId": "TuvMOKxV_wnsQoA3EBBoPF", "statsFormat": "firefox", - "userId": "test-9eb2f1a0-af02-443f-b97c-e415ecc857e7", + "conferenceId": "ObviousGroupsAnticipateCertainly", + "endpointId": "59d7f6f7", + "sessionId": "eb568c58-b21d-4e7b-b566-665a90d1a009", "isJaaSTenant": false, "jaasClientId": "", "jaasMeetingFqn": "", diff --git a/src/test/jest/results/google-standard-stats-p2p-result.json b/src/test/jest/results/google-standard-stats-p2p-result.json index 704c420d..37908edd 100644 --- a/src/test/jest/results/google-standard-stats-p2p-result.json +++ b/src/test/jest/results/google-standard-stats-p2p-result.json @@ -1,20 +1,13 @@ [ { "dumpInfo": { - "ampDeviceId": "38e672be-5e96-4d19-905e-1692a81eb09c", - "ampSessionId": 1641600326907, - "app": "Integration Test", - "clientId": "83072254-e24b-4f8d-8162-23e94958ccb3", - "conferenceUrl": "192.168.1.1/conf-83072254-e24b-4f8d-8162-23e94958ccb3", - "dumpPath": "/Users/nohlmeier/src/rtcstats-server/temp/83072254-e24b-4f8d-8162-23e94958ccb3", - "endDate": 1641600327015, - "isJaaSTenant": false, - "jaasClientId": "", - "jaasMeetingFqn": "", - "sessionId": "bd918844-47a7-4985-a01d-22042108742a", - "startDate": 1641600326943, + "ampSessionId": 1605197553463, + "ampDeviceId": "Z4pw0CT9udBLc9rSQ4ytH5", + "app": "Jitsi Meet", + "conferenceUrl": "192.168.1.234:8080/fullmechanismslastimpolitely", + "userId": "andrei-win-1", "statsFormat": "chrome_standard", - "userId": "test-83072254-e24b-4f8d-8162-23e94958ccb3", + "ampUserId": null, "isJaaSTenant": false, "jaasClientId": "", "jaasMeetingFqn": "", diff --git a/src/test/jest/results/google-standard-stats-sfu-result.json b/src/test/jest/results/google-standard-stats-sfu-result.json index 7de4afa3..a9b5308a 100644 --- a/src/test/jest/results/google-standard-stats-sfu-result.json +++ b/src/test/jest/results/google-standard-stats-sfu-result.json @@ -1,24 +1,17 @@ [ { "dumpInfo": { - "ampDeviceId": "4982d7c4-01ae-4570-8599-09283b42766a", - "ampSessionId": 1641600611831, - "app": "Integration Test", - "clientId": "d0667072-0689-43bd-b34a-89e147cbf9ce", - "conferenceUrl": "192.168.1.1/conf-d0667072-0689-43bd-b34a-89e147cbf9ce", - "dumpPath": "/Users/nohlmeier/src/rtcstats-server/temp/d0667072-0689-43bd-b34a-89e147cbf9ce", - "endDate": 1641600611905, - "isJaaSTenant": false, - "jaasClientId": "", - "jaasMeetingFqn": "", - "sessionId": "4755c766-a069-4316-b1f1-54829dbc7a69", - "startDate": 1641600611868, + "ampSessionId": 1605197553463, + "ampDeviceId": "Z4pw0CT9udBLc9rSQ4ytH5", + "app": "Jitsi Meet", + "conferenceUrl": "192.168.1.234:8080/fullmechanismslastimpolitely", + "userId": "andrei-win-1", "statsFormat": "chrome_standard", - "userId": "test-d0667072-0689-43bd-b34a-89e147cbf9ce", - "isJaaSTenant": false, - "jaasClientId": "", - "jaasMeetingFqn": "", - "tenant": "" + "ampUserId": null, + "isJaaSTenant": false, + "jaasClientId": "", + "jaasMeetingFqn": "", + "tenant": "" }, "features": { "aggregates": { diff --git a/src/test/jest/results/safari-standard-stats-result.json b/src/test/jest/results/safari-standard-stats-result.json index 738c0d13..9fdf9a6e 100644 --- a/src/test/jest/results/safari-standard-stats-result.json +++ b/src/test/jest/results/safari-standard-stats-result.json @@ -1,20 +1,13 @@ [ { "dumpInfo": { - "ampDeviceId": "f0892dc7-0f9c-4e39-9e9b-0924ec51fa27", - "ampSessionId": 1641941576018, - "app": "Integration Test", - "clientId": "9f2af46d-0dc9-4040-b1fa-f4bb55f8ab19", - "conferenceUrl": "192.168.1.1/conf-9f2af46d-0dc9-4040-b1fa-f4bb55f8ab19", - "dumpPath": "/Users/nohlmeier/src/rtcstats-server/temp/9f2af46d-0dc9-4040-b1fa-f4bb55f8ab19", - "endDate": 1641941576116, - "isJaaSTenant": false, - "jaasClientId": "", - "jaasMeetingFqn": "", - "sessionId": "4567a1ea-9b53-4249-812b-e9986eb12423", - "startDate": 1641941576052, + "ampDeviceId": "KkGl_2yDswWBdDXC0fFMLk", + "ampSessionId": 1605197674060, + "ampUserId": null, + "app": "Jitsi Meet", + "conferenceUrl": "192.168.1.234:8080/closeoutfitsusefast", "statsFormat": "safari", - "userId": "test-9f2af46d-0dc9-4040-b1fa-f4bb55f8ab19", + "userId": "andreig-safari", "isJaaSTenant": false, "jaasClientId": "", "jaasMeetingFqn": "", diff --git a/src/test/jest/results/undefined-ice-candidate-result.json b/src/test/jest/results/undefined-ice-candidate-result.json index e103bae5..50447fe1 100644 --- a/src/test/jest/results/undefined-ice-candidate-result.json +++ b/src/test/jest/results/undefined-ice-candidate-result.json @@ -5,17 +5,16 @@ "ampSessionId": 1646895708035, "ampUserId": null, "app": "Jitsi Meet", - "clientId": "050bf1c4-8d52-43dd-ba94-8b58089f0020", "conferenceId": "xxxxxxxxxxzu2pFGyp7mBrP7RdvzNcsEPXj7pmGDcNGw", "conferenceUrl": "meet.jit.si/xxxxxxxxxxzu2pfgyp7mbrp7rdvzncsepxj7pmgdcngw", - "dumpPath": "/rtcstats-server/temp/050bf1c4-8d52-43dd-ba94-8b58089f0020", - "endDate": 1646901926175, "endpointId": "cced643e", "sessionId": "41c8f2f2-eab3-49c7-b568-6d7d4e51fb81", - "startDate": 1646901906018, "statsFormat": "chrome_standard", - "tenant": "", - "userId": "Lyda-hGl" + "userId": "XXXX-XXX", + "isJaaSTenant": false, + "jaasClientId": "", + "jaasMeetingFqn": "", + "tenant": "" }, "features": { "aggregates": { diff --git a/src/worker-pool/ExtractWorker.js b/src/worker-pool/ExtractWorker.js index bfc81500..9ffb8688 100644 --- a/src/worker-pool/ExtractWorker.js +++ b/src/worker-pool/ExtractWorker.js @@ -34,11 +34,14 @@ parentPort.on('message', request => { async function processRequest(request) { try { const featureExtractor = new FeatureExtractor(request.body); - const features = await featureExtractor.extract(); + const { features, dumpInfo } = await featureExtractor.extract(); parentPort.postMessage({ type: ResponseType.DONE, - body: { dumpInfo: request.body, - features } }); + body: { dumpInfo: { + ...dumpInfo, + ...request.body + }, + features } }); } catch (error) { parentPort.postMessage({ type: ResponseType.ERROR,