import React, { PureComponent } from 'react'; import { FormattedTime, defineMessages, injectIntl } from 'react-intl'; import PropTypes from 'prop-types'; import cx from 'classnames'; import UserAvatar from '/imports/ui/components/user-avatar/component'; import Icon from '/imports/ui/components/connection-status/icon/component'; import Switch from '/imports/ui/components/switch/component'; import Service from '../service'; import Modal from '/imports/ui/components/modal/simple/component'; import { styles } from './styles'; const NETWORK_MONITORING_INTERVAL_MS = 2000; const MIN_TIMEOUT = 3000; const intlMessages = defineMessages({ ariaTitle: { id: 'app.connection-status.ariaTitle', description: 'Connection status aria title', }, title: { id: 'app.connection-status.title', description: 'Connection status title', }, description: { id: 'app.connection-status.description', description: 'Connection status description', }, empty: { id: 'app.connection-status.empty', description: 'Connection status empty', }, more: { id: 'app.connection-status.more', description: 'More about conectivity issues', }, audioLabel: { id: 'app.settings.audioTab.label', description: 'Audio label', }, videoLabel: { id: 'app.settings.videoTab.label', description: 'Video label', }, copy: { id: 'app.connection-status.copy', description: 'Copy network data', }, copied: { id: 'app.connection-status.copied', description: 'Copied network data', }, offline: { id: 'app.connection-status.offline', description: 'Offline user', }, dataSaving: { id: 'app.settings.dataSavingTab.description', description: 'Description of data saving', }, webcam: { id: 'app.settings.dataSavingTab.webcam', description: 'Webcam data saving switch', }, screenshare: { id: 'app.settings.dataSavingTab.screenShare', description: 'Screenshare data saving switch', }, on: { id: 'app.switch.onLabel', description: 'label for toggle switch on state', }, off: { id: 'app.switch.offLabel', description: 'label for toggle switch off state', }, no: { id: 'app.connection-status.no', description: 'No to is using turn', }, yes: { id: 'app.connection-status.yes', description: 'Yes to is using turn', }, usingTurn: { id: 'app.connection-status.usingTurn', description: 'User is using turn server', }, jitter: { id: 'app.connection-status.jitter', description: 'Jitter buffer in ms', }, lostPackets: { id: 'app.connection-status.lostPackets', description: 'Number of lost packets', }, }); const propTypes = { closeModal: PropTypes.func.isRequired, intl: PropTypes.shape({ formatMessage: PropTypes.func.isRequired, }).isRequired, }; const isConnectionStatusEmpty = (connectionStatus) => { // Check if it's defined if (!connectionStatus) return true; // Check if it's an array if (!Array.isArray(connectionStatus)) return true; // Check if is empty if (connectionStatus.length === 0) return true; return false; }; class ConnectionStatusComponent extends PureComponent { constructor(props) { super(props); const { intl } = this.props; this.help = Service.getHelp(); this.state = { dataSaving: props.dataSaving, hasNetworkData: false, networkData: { user: { }, audio: { audioCurrentUploadRate: 0, audioCurrentDownloadRate: 0, jitter: 0, packetsLost: 0, transportStats: {}, }, video: { videoCurrentUploadRate: 0, videoCurrentDownloadRate: 0, }, }, }; this.displaySettingsStatus = this.displaySettingsStatus.bind(this); this.rateInterval = null; this.audioLabel = (intl.formatMessage(intlMessages.audioLabel)).charAt(0); this.videoLabel = (intl.formatMessage(intlMessages.videoLabel)).charAt(0); } async componentDidMount() { this.startMonitoringNetwork(); } componentWillUnmount() { Meteor.clearInterval(this.rateInterval); } handleDataSavingChange(key) { const { dataSaving } = this.state; dataSaving[key] = !dataSaving[key]; this.setState(dataSaving); } /** * Start monitoring the network data. * @return {Promise} A Promise that resolves when process started. */ async startMonitoringNetwork() { let previousData = await Service.getNetworkData(); this.rateInterval = Meteor.setInterval(async () => { const data = await Service.getNetworkData(); const { outbound: audioCurrentUploadRate, inbound: audioCurrentDownloadRate, } = Service.calculateBitsPerSecond(data.audio, previousData.audio); const jitter = data.audio['inbound-rtp'] ? data.audio['inbound-rtp'].jitterBufferAverage : 0; const packetsLost = data.audio['inbound-rtp'] ? data.audio['inbound-rtp'].packetsLost : 0; const audio = { audioCurrentUploadRate, audioCurrentDownloadRate, jitter, packetsLost, transportStats: data.audio.transportStats, }; const { outbound: videoCurrentUploadRate, inbound: videoCurrentDownloadRate, } = Service.calculateBitsPerSecondFromMultipleData(data.video, previousData.video); const video = { videoCurrentUploadRate, videoCurrentDownloadRate, }; const { user } = data; const networkData = { user, audio, video, }; previousData = data; this.setState({ networkData, hasNetworkData: true, }); }, NETWORK_MONITORING_INTERVAL_MS); } renderEmpty() { const { intl } = this.props; return (