Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
createSelector,
/**
* Returns list of messages that are visible to the user.
* Filtered messages by types and text are factored in.
*/
const getDisplayedMessages = createSelector(
state => state.messages,
({
messages,
messageFilterType,
showControlFrames,
messageFilterText,
currentChannelId,
}) => {
if (!currentChannelId || !messages.get(currentChannelId)) {
return [];
}
const messagesArray = messages.get(currentChannelId);
if (messageFilterType === "all" && messageFilterText.length === 0) {
return messagesArray.filter(message =>
typeFilter(message, messageFilterType, showControlFrames)
);
}
const filter = searchFilter(messageFilterText);
// If message payload is > 10,000 characters long, we check the LongStringActor payload string
return messagesArray.filter(
message =>
(message.payload.initial
? filter(message.payload.initial)
: filter(message.payload)) &&
typeFilter(message, messageFilterType, showControlFrames)
);
}
);
function typeFilter(message, messageFilterType, showControlFrames) {
const controlFrames = [0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf];
const isControlFrame = controlFrames.includes(message.opCode);
if (messageFilterType === "all" || messageFilterType === message.type) {
return showControlFrames || !isControlFrame;
}
return false;
}
function searchFilter(messageFilterText) {
let regex;
if (looksLikeRegex(messageFilterText)) {
try {
regex = regexFromText(messageFilterText);
} catch (e) {}
}
return regex
? payload => regex.test(payload)
: payload => payload.includes(messageFilterText);
}
function looksLikeRegex(text) {
return text.startsWith("/") && text.endsWith("/") && text.length > 2;
}
function regexFromText(text) {
return new RegExp(text.slice(1, -1), "im");
}
/**
* Checks if the selected message is visible.
* If the selected message is not visible, the SplitBox component
* should not show the MessagePayload component.
*/
const isSelectedMessageVisible = createSelector(
state => state.messages,
getDisplayedMessages,
({ selectedMessage }, displayedMessages) =>
displayedMessages.some(message => message === selectedMessage)
);
/**
* Returns the current selected message.
*/
const getSelectedMessage = createSelector(
state => state.messages,
({ selectedMessage }) => (selectedMessage ? selectedMessage : undefined)
);
/**
* Returns summary data of the list of messages that are visible to the user.
* Filtered messages by types and text are factored in.
*/
const getDisplayedMessagesSummary = createSelector(
getDisplayedMessages,
displayedMessages => {
let firstStartedMs = +Infinity;
let lastEndedMs = -Infinity;
let sentSize = 0;
let receivedSize = 0;
let totalSize = 0;
displayedMessages.forEach(message => {
if (message.type == "received") {
receivedSize += message.payload.length;
} else if (message.type == "sent") {
sentSize += message.payload.length;
}
totalSize += message.payload.length;
if (message.timeStamp < firstStartedMs) {
firstStartedMs = message.timeStamp;
}
if (message.timeStamp > lastEndedMs) {
lastEndedMs = message.timeStamp;
}
});
return {
count: displayedMessages.length,
totalMs: (lastEndedMs - firstStartedMs) / 1000,
sentSize,
receivedSize,
totalSize,
};
}
);
/**
* Returns if the currentChannelId is closed
*/
const isCurrentChannelClosed = createSelector(
state => state.messages,
({ closedConnections, currentChannelId }) =>
closedConnections.has(currentChannelId)
);
/**
* Returns the closed connection details of the currentChannelId
* Null, if the connection is still open
*/
const getClosedConnectionDetails = createSelector(
state => state.messages,
({ closedConnections, currentChannelId }) =>
closedConnections.get(currentChannelId)
);
module.exports = {
getSelectedMessage,
isSelectedMessageVisible,
getDisplayedMessages,
getDisplayedMessagesSummary,
isCurrentChannelClosed,
getClosedConnectionDetails,
};