fix: load maxmind data once on mount of status dialog

pull/2969/head
Audric Ackermann 2 months ago
parent 5f9d3209c8
commit 96809bf5b4

@ -91,7 +91,6 @@
"emoji-mart": "^5.5.2",
"filesize": "3.6.1",
"firstline": "1.2.1",
"fs": "^0.0.1-security",
"fs-extra": "9.0.0",
"glob": "7.1.2",
"image-type": "^4.1.0",
@ -100,7 +99,7 @@
"linkify-it": "^4.0.1",
"lodash": "^4.17.21",
"long": "^4.0.0",
"maxmind": "^4.3.6",
"maxmind": "^4.3.18",
"mic-recorder-to-mp3": "^2.2.2",
"moment": "^2.29.4",
"node-fetch": "^2.6.7",

@ -1,9 +1,7 @@
import { shell } from 'electron';
import { readFileSync } from 'fs';
import path from 'path';
import React from 'react';
import { ipcRenderer, shell } from 'electron';
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
import useHover from 'react-use/lib/useHover';
import styled from 'styled-components';
@ -11,16 +9,18 @@ import { CityResponse, Reader } from 'maxmind';
import { Snode } from '../../data/data';
import { onionPathModal } from '../../state/ducks/modalDialog';
import {
getFirstOnionPath,
getFirstOnionPathLength,
getIsOnline,
getOnionPathsCount,
useFirstOnionPath,
useFirstOnionPathLength,
useIsOnline,
useOnionPathsCount,
} from '../../state/selectors/onions';
import { Flex } from '../basic/Flex';
import { isEmpty, isTypedArray } from 'lodash';
import { useMount } from 'react-use';
import { SessionWrapperModal } from '../SessionWrapperModal';
import { SessionSpinner } from '../basic/SessionSpinner';
import { SessionIcon, SessionIconButton } from '../icon';
import { SessionWrapperModal } from '../SessionWrapperModal';
export type StatusLightType = {
glowStartDelay: number;
@ -77,11 +77,28 @@ const OnionCountryDisplay = ({ labelText, snodeIp }: { snodeIp?: string; labelTe
return hoverable;
};
let reader: Reader<CityResponse> | null;
const lang = 'en';
const OnionPathModalInner = () => {
const onionPath = useSelector(getFirstOnionPath);
const isOnline = useSelector(getIsOnline);
const onionPath = useFirstOnionPath();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_dataLoaded, setDataLoaded] = useState(false);
const isOnline = useIsOnline();
const glowDuration = onionPath.length + 2;
useMount(() => {
ipcRenderer.once('load-maxmind-data-reply', (_event, content) => {
const asArrayBuffer = content as Uint8Array;
if (asArrayBuffer && isTypedArray(asArrayBuffer) && !isEmpty(asArrayBuffer)) {
reader = new Reader<CityResponse>(Buffer.from(asArrayBuffer.buffer));
setDataLoaded(true); // retrigger a rerender
}
});
ipcRenderer.send('load-maxmind-data');
});
if (!isOnline || !onionPath || onionPath.length === 0) {
return <SessionSpinner loading={true} />;
}
@ -96,13 +113,6 @@ const OnionPathModalInner = () => {
},
];
const binPath = (process.env.NODE_APP_INSTANCE || '').startsWith('devprod')
? path.resolve(`${__dirname}/../../..`)
: path.resolve(`${process.resourcesPath}/..`);
const buffer = readFileSync(`${binPath}/mmdb/GeoLite2-Country.mmdb`);
const reader = new Reader<CityResponse>(buffer);
const lang = 'en';
return (
<>
<StyledOnionDescription>
@ -126,13 +136,13 @@ const OnionPathModalInner = () => {
</StyledLightsContainer>
<Flex container={true} flexDirection="column" alignItems="flex-start">
{nodes.map((snode: Snode | any) => {
const geoLookup = reader.get(snode.ip || '0.0.0.0');
const countryName = geoLookup?.country?.names[lang] || window.i18n('unknownCountry');
const labelText = snode.label || countryName;
const countryName =
reader?.get(snode.ip || '0.0.0.0')?.country?.names[lang] ||
window.i18n('unknownCountry');
return (
<OnionCountryDisplay
labelText={labelText}
labelText={countryName}
snodeIp={snode.ip}
key={`country-${snode.ip}`}
/>
@ -197,9 +207,9 @@ export const ActionPanelOnionStatusLight = (props: {
}) => {
const { isSelected, handleClick, id } = props;
const onionPathsCount = useSelector(getOnionPathsCount);
const firstPathLength = useSelector(getFirstOnionPathLength);
const isOnline = useSelector(getIsOnline);
const onionPathsCount = useOnionPathsCount();
const firstPathLength = useFirstOnionPathLength();
const isOnline = useIsOnline();
// Set icon color based on result
const errorColor = 'var(--button-path-error-color)';

@ -10,6 +10,7 @@ import {
dialog,
protocol as electronProtocol,
ipcMain as ipc,
IpcMainEvent,
Menu,
nativeTheme,
screen,
@ -154,7 +155,7 @@ if (windowFromUserConfig) {
ephemeralConfig.set('window', windowConfig);
}
// import {load as loadLocale} from '../..'
import { readFile } from 'fs-extra';
import { getAppRootPath } from '../node/getRootPath';
import { setLastestRelease } from '../node/latest_desktop_release';
import { load as loadLocale, LocaleMessagesWithNameType } from '../node/locale';
@ -1074,6 +1075,16 @@ ipc.on('close-debug-log', () => {
}
});
ipc.on('save-debug-log', saveDebugLog);
ipc.on('load-maxmind-data', async (event: IpcMainEvent) => {
try {
const appRoot = app.isPackaged ? process.resourcesPath : app.getAppPath();
const fileToRead = path.join(appRoot, 'mmdb', 'GeoLite2-Country.mmdb');
const buffer = await readFile(fileToRead);
event.reply('load-maxmind-data-reply', new Uint8Array(buffer.buffer));
} catch (e) {
event.reply('load-maxmind-data-reply', null);
}
});
// This should be called with an ipc sendSync
ipc.on('get-media-permissions', event => {

@ -1,27 +1,41 @@
import { createSelector } from '@reduxjs/toolkit';
import { StateType } from '../reducer';
import { useSelector } from 'react-redux';
import { OnionState } from '../ducks/onion';
import { SectionType } from '../ducks/section';
import { StateType } from '../reducer';
export const getOnionPaths = (state: StateType): OnionState => state.onionPaths;
const getOnionPaths = (state: StateType): OnionState => state.onionPaths;
export const getOnionPathsCount = createSelector(
const getOnionPathsCount = createSelector(
getOnionPaths,
(state: OnionState): SectionType => state.snodePaths.length
);
export const getFirstOnionPath = createSelector(
const getFirstOnionPath = createSelector(
getOnionPaths,
(state: OnionState): Array<{ ip: string }> => state.snodePaths?.[0] || []
);
export const getFirstOnionPathLength = createSelector(
const getFirstOnionPathLength = createSelector(
getFirstOnionPath,
(state: Array<{ ip: string }>): number => state.length || 0
);
export const getIsOnline = createSelector(
getOnionPaths,
(state: OnionState): boolean => state.isOnline
);
const getIsOnline = createSelector(getOnionPaths, (state: OnionState): boolean => state.isOnline);
export const useOnionPathsCount = () => {
return useSelector(getOnionPathsCount);
};
export const useIsOnline = () => {
return useSelector(getIsOnline);
};
export const useFirstOnionPathLength = () => {
return useSelector(getFirstOnionPathLength);
};
export const useFirstOnionPath = () => {
return useSelector(getFirstOnionPath);
};

@ -3867,11 +3867,6 @@ fs.realpath@^1.0.0:
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
fs@^0.0.1-security:
version "0.0.1-security"
resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4"
integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==
fsevents@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
@ -6882,7 +6877,7 @@ safe-regex-test@^1.0.3:
es-errors "^1.3.0"
is-regex "^1.1.4"
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
"safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==

Loading…
Cancel
Save