* Network metrics * update network-client ref * fix unit tests * missing catch error parsing * Replace API's to fetch all teams and channels for a user Update groupLabel to use a type definition Include effective Latency and Average Speed in the metrics Include parallel and sequential request counts * update network library and fix tests * feat(MM-61865): send network request telemetry data to the server (#8436) * feat(MM-61865): send network info telemetry data * unit testing * fix latency vs effectiveLatency * cleanup test * fix failing tests * fix spelling error * fix failing test * more cleanup * fix: improve parallel requests calculation (#8439) * fix: improve parallel requests calculation * fix test issue * multiple parallelGroups testing * calculateAverageSpeedWithCategories test * categorizedRequests in it's own describe * clean up duplicate tests * check for when groupLabel is non-existent * a case when groupLabel is non-existent * more testing with effective latency. * resolveAndFlattenModels with a capital F * add try..catch within resolveAndFlattenModels * update groupLabel to fix failing lint * fix linting issue due to unknown group label * forgot to push changes * fix the indentation problem again * add env var option for COLLECT_NETWORK_METRICS --------- Co-authored-by: Rahim Rahman <rahim.rahman@mattermost.com> Co-authored-by: Mattermost Build <build@mattermost.com>
255 lines
9.6 KiB
TypeScript
255 lines
9.6 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {chunk} from 'lodash';
|
|
import {DeviceEventEmitter} from 'react-native';
|
|
|
|
import {handleReconnect} from '@actions/websocket';
|
|
import {Events, General, Preferences} from '@constants';
|
|
import DatabaseManager from '@database/manager';
|
|
import {getPreferenceAsBool} from '@helpers/api/preference';
|
|
import NetworkManager from '@managers/network_manager';
|
|
import {queryAllUnreadDMsAndGMsIds, getChannelById} from '@queries/servers/channel';
|
|
import {truncateCrtRelatedTables} from '@queries/servers/entry';
|
|
import {queryPreferencesByCategoryAndName, querySavedPostsPreferences} from '@queries/servers/preference';
|
|
import {getCurrentUserId} from '@queries/servers/system';
|
|
import EphemeralStore from '@store/ephemeral_store';
|
|
import {isDMorGM} from '@utils/channel';
|
|
import {getFullErrorMessage} from '@utils/errors';
|
|
import {logDebug} from '@utils/log';
|
|
import {getUserIdFromChannelName} from '@utils/user';
|
|
|
|
import {forceLogoutIfNecessary} from './session';
|
|
|
|
import type ChannelModel from '@typings/database/models/servers/channel';
|
|
|
|
export type MyPreferencesRequest = {
|
|
preferences?: PreferenceType[];
|
|
error?: unknown;
|
|
};
|
|
|
|
export const fetchMyPreferences = async (serverUrl: string, fetchOnly = false, groupLabel?: RequestGroupLabel): Promise<MyPreferencesRequest> => {
|
|
try {
|
|
const client = NetworkManager.getClient(serverUrl);
|
|
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
|
|
const preferences = await client.getMyPreferences(groupLabel);
|
|
|
|
if (!fetchOnly) {
|
|
await operator.handlePreferences({
|
|
prepareRecordsOnly: false,
|
|
preferences,
|
|
sync: true,
|
|
});
|
|
}
|
|
|
|
return {preferences};
|
|
} catch (error) {
|
|
logDebug('error on fetchMyPreferences', getFullErrorMessage(error));
|
|
forceLogoutIfNecessary(serverUrl, error);
|
|
return {error};
|
|
}
|
|
};
|
|
|
|
export const saveFavoriteChannel = async (serverUrl: string, channelId: string, isFavorite: boolean) => {
|
|
try {
|
|
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const userId = await getCurrentUserId(database);
|
|
const favPref: PreferenceType = {
|
|
category: Preferences.CATEGORIES.FAVORITE_CHANNEL,
|
|
name: channelId,
|
|
user_id: userId,
|
|
value: String(isFavorite),
|
|
};
|
|
return savePreference(serverUrl, [favPref]);
|
|
} catch (error) {
|
|
return {error};
|
|
}
|
|
};
|
|
|
|
export const savePostPreference = async (serverUrl: string, postId: string) => {
|
|
try {
|
|
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
|
|
const userId = await getCurrentUserId(database);
|
|
const pref: PreferenceType = {
|
|
user_id: userId,
|
|
category: Preferences.CATEGORIES.SAVED_POST,
|
|
name: postId,
|
|
value: 'true',
|
|
};
|
|
return savePreference(serverUrl, [pref]);
|
|
} catch (error) {
|
|
return {error};
|
|
}
|
|
};
|
|
|
|
export const savePreference = async (serverUrl: string, preferences: PreferenceType[], prepareRecordsOnly = false, groupLabel?: RequestGroupLabel) => {
|
|
try {
|
|
if (!preferences.length) {
|
|
return {preferences: []};
|
|
}
|
|
|
|
const client = NetworkManager.getClient(serverUrl);
|
|
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
|
|
const userId = await getCurrentUserId(database);
|
|
const chunkSize = 100;
|
|
const chunks = chunk(preferences, chunkSize);
|
|
chunks.forEach((c: PreferenceType[]) => {
|
|
client.savePreferences(userId, c, groupLabel);
|
|
});
|
|
const preferenceModels = await operator.handlePreferences({
|
|
preferences,
|
|
prepareRecordsOnly,
|
|
});
|
|
|
|
return {preferences: preferenceModels};
|
|
} catch (error) {
|
|
logDebug('error on savePreference', getFullErrorMessage(error));
|
|
forceLogoutIfNecessary(serverUrl, error);
|
|
return {error};
|
|
}
|
|
};
|
|
|
|
export const deleteSavedPost = async (serverUrl: string, postId: string) => {
|
|
try {
|
|
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const client = NetworkManager.getClient(serverUrl);
|
|
const userId = await getCurrentUserId(database);
|
|
const records = await querySavedPostsPreferences(database, postId).fetch();
|
|
const postPreferenceRecord = records.find((r) => postId === r.name);
|
|
const pref = {
|
|
user_id: userId,
|
|
category: Preferences.CATEGORIES.SAVED_POST,
|
|
name: postId,
|
|
value: 'true',
|
|
};
|
|
|
|
if (postPreferenceRecord) {
|
|
client.deletePreferences(userId, [pref]);
|
|
await postPreferenceRecord.destroyPermanently();
|
|
}
|
|
|
|
return {
|
|
preference: pref,
|
|
};
|
|
} catch (error) {
|
|
logDebug('error on deleteSavedPost', getFullErrorMessage(error));
|
|
forceLogoutIfNecessary(serverUrl, error);
|
|
return {error};
|
|
}
|
|
};
|
|
|
|
export const openChannelIfNeeded = async (serverUrl: string, channelId: string, groupLabel?: RequestGroupLabel) => {
|
|
try {
|
|
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const channel = await getChannelById(database, channelId);
|
|
if (!channel || !isDMorGM(channel)) {
|
|
return {};
|
|
}
|
|
const res = await openChannels(serverUrl, [channel], groupLabel);
|
|
return res;
|
|
} catch (error) {
|
|
forceLogoutIfNecessary(serverUrl, error);
|
|
return {error};
|
|
}
|
|
};
|
|
|
|
export const openAllUnreadChannels = async (serverUrl: string, groupLabel?: RequestGroupLabel) => {
|
|
try {
|
|
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const channels = await queryAllUnreadDMsAndGMsIds(database).fetch();
|
|
const res = await openChannels(serverUrl, channels, groupLabel);
|
|
return res;
|
|
} catch (error) {
|
|
forceLogoutIfNecessary(serverUrl, error);
|
|
return {error};
|
|
}
|
|
};
|
|
|
|
const openChannels = async (serverUrl: string, channels: ChannelModel[], groupLabel?: RequestGroupLabel) => {
|
|
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const userId = await getCurrentUserId(database);
|
|
|
|
const {DIRECT_CHANNEL_SHOW, GROUP_CHANNEL_SHOW} = Preferences.CATEGORIES;
|
|
const directChannelShowPreferences = await queryPreferencesByCategoryAndName(database, DIRECT_CHANNEL_SHOW).fetch();
|
|
const groupChannelShowPreferences = await queryPreferencesByCategoryAndName(database, GROUP_CHANNEL_SHOW).fetch();
|
|
const showPreferences = directChannelShowPreferences.concat(groupChannelShowPreferences);
|
|
|
|
const prefs: PreferenceType[] = [];
|
|
for (const channel of channels) {
|
|
const category = channel.type === General.DM_CHANNEL ? DIRECT_CHANNEL_SHOW : GROUP_CHANNEL_SHOW;
|
|
const name = channel.type === General.DM_CHANNEL ? getUserIdFromChannelName(userId, channel.name) : channel.id;
|
|
const visible = getPreferenceAsBool(showPreferences, category, name, false);
|
|
if (visible) {
|
|
continue;
|
|
}
|
|
|
|
prefs.push(
|
|
{
|
|
user_id: userId,
|
|
category,
|
|
name,
|
|
value: 'true',
|
|
},
|
|
{
|
|
user_id: userId,
|
|
category: Preferences.CATEGORIES.CHANNEL_OPEN_TIME,
|
|
name: channel.id,
|
|
value: Date.now().toString(),
|
|
},
|
|
);
|
|
}
|
|
|
|
return savePreference(serverUrl, prefs, false, groupLabel);
|
|
};
|
|
|
|
export const setDirectChannelVisible = async (serverUrl: string, channelId: string, visible = true) => {
|
|
try {
|
|
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const channel = await getChannelById(database, channelId);
|
|
if (channel?.type === General.DM_CHANNEL || channel?.type === General.GM_CHANNEL) {
|
|
const userId = await getCurrentUserId(database);
|
|
const {DIRECT_CHANNEL_SHOW, GROUP_CHANNEL_SHOW} = Preferences.CATEGORIES;
|
|
const category = channel.type === General.DM_CHANNEL ? DIRECT_CHANNEL_SHOW : GROUP_CHANNEL_SHOW;
|
|
const name = channel.type === General.DM_CHANNEL ? getUserIdFromChannelName(userId, channel.name) : channelId;
|
|
const pref: PreferenceType = {
|
|
user_id: userId,
|
|
category,
|
|
name,
|
|
value: visible.toString(),
|
|
};
|
|
return savePreference(serverUrl, [pref]);
|
|
}
|
|
|
|
return {};
|
|
} catch (error) {
|
|
forceLogoutIfNecessary(serverUrl, error);
|
|
return {error};
|
|
}
|
|
};
|
|
|
|
export const savePreferredSkinTone = async (serverUrl: string, skinCode: string) => {
|
|
try {
|
|
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const userId = await getCurrentUserId(database);
|
|
const pref: PreferenceType = {
|
|
user_id: userId,
|
|
category: Preferences.CATEGORIES.EMOJI,
|
|
name: Preferences.EMOJI_SKINTONE,
|
|
value: skinCode,
|
|
};
|
|
return savePreference(serverUrl, [pref]);
|
|
} catch (error) {
|
|
return {error};
|
|
}
|
|
};
|
|
|
|
export const handleCRTToggled = async (serverUrl: string) => {
|
|
const currentServerUrl = await DatabaseManager.getActiveServerUrl();
|
|
await truncateCrtRelatedTables(serverUrl);
|
|
await handleReconnect(serverUrl);
|
|
EphemeralStore.setEnablingCRT(false);
|
|
DeviceEventEmitter.emit(Events.CRT_TOGGLED, serverUrl === currentServerUrl);
|
|
};
|