Skip to content

Commit

Permalink
[backend/frontend] Improve latency on endpoint teams
Browse files Browse the repository at this point in the history
Co-authored-by: Damien Goujard <damien.goujard@filigran.io>
  • Loading branch information
RomuDeuxfois and damgouj authored Oct 3, 2024
1 parent c936004 commit 8eaadc9
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public class ImapService {
private FileService fileService;
private final PlatformSettingsService platformSettingsService;

public ImapService(Environment env, @Autowired PlatformSettingsService platformSettingsService) throws Exception {
public ImapService(Environment env, @Autowired PlatformSettingsService platformSettingsService) {
this.platformSettingsService = platformSettingsService;
try {
initStore(env);
Expand Down Expand Up @@ -296,17 +296,20 @@ private void synchronizeBox(Folder inbox, Boolean isSent) throws Exception {
settingRepository.save(currentState);
}

private void tryToSynchronizeFolderFromBox(String folderName, Boolean isSent) throws Exception {
try(Folder folderBox = imapStore.getFolder(folderName)) {
folderBox.open(Folder.READ_ONLY);
synchronizeBox(folderBox, isSent);
}
}

private void syncFolders() throws Exception {
try {
// Sync sent
Folder sentBox = imapStore.getFolder(sentFolder);
sentBox.open(Folder.READ_ONLY);
synchronizeBox(sentBox, true);
tryToSynchronizeFolderFromBox(sentFolder, true);
// Sync received
for (String listeningFolder : inboxFolders) {
Folder inbox = imapStore.getFolder(listeningFolder);
inbox.open(Folder.READ_ONLY);
synchronizeBox(inbox, false);
tryToSynchronizeFolderFromBox(listeningFolder, false);
}
} catch (MessagingException e) {
log.warning("Connection failure: " + e.getMessage());
Expand All @@ -323,6 +326,9 @@ private void retrySyncFolders() throws Exception {
} catch (MessagingException e) {
log.warning("Retrying connection..." + e.getMessage());
Thread.sleep(2000);
if(i == 2 && imapStore != null && imapStore.isConnected()) {
imapStore.close();
}
}
}
}
Expand All @@ -346,11 +352,11 @@ public void connectionListener() throws Exception {

public void storeSentMessage(MimeMessage message) throws Exception {
if (enabled) {
Folder folder = imapStore.getFolder(sentFolder);
folder.open(Folder.READ_WRITE);
message.setFlag(Flags.Flag.SEEN, true);
folder.appendMessages(new Message[]{message});
folder.close();
try (Folder folder = imapStore.getFolder(sentFolder)) {
folder.open(Folder.READ_WRITE);
message.setFlag(Flags.Flag.SEEN, true);
folder.appendMessages(new Message[]{message});
}
}
}
}
3 changes: 2 additions & 1 deletion openbas-front/src/admin/components/common/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import type {
import type { UserStore } from '../teams/players/Player';
import type { InjectOutputType, InjectStore } from '../../../actions/injects/Inject';
import { Page } from '../../../components/common/queryable/Page';
import type { TeamStore } from '../../../actions/teams/Team';

export type PermissionsContextType = {
permissions: { readOnly: boolean, canWrite: boolean, isRunning: boolean }
Expand Down Expand Up @@ -75,7 +76,7 @@ export type TeamContextType = {
onAddTeam?: (teamId: Team['team_id']) => Promise<void>,
onCreateTeam?: (team: TeamCreateInput) => Promise<{ result: string }>,
onRemoveTeam?: (teamId: Team['team_id']) => void,
onReplaceTeam?: (teamIds: Team['team_id'][]) => Promise<{ result: string[] }>,
onReplaceTeam?: (teamIds: Team['team_id'][]) => Promise<{ result: string[], entities: { teams: Record<string, TeamStore> } }>,
onToggleUser?: (teamId: Team['team_id'], userId: UserStore['user_id'], userEnabled: boolean) => void,
checkUserEnabled?: (teamId: Team['team_id'], userId: UserStore['user_id']) => boolean,
computeTeamUsersEnabled?: (teamId: Team['team_id']) => number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@ import { useSearchParams } from 'react-router-dom';
import ItemTags from '../../../../components/ItemTags';
import TeamPopover from './TeamPopover';
import useSearchAnFilter from '../../../../utils/SortingFiltering';
import { useHelper } from '../../../../store';
import type { TagHelper } from '../../../../actions/helper';
import type { TeamStore } from '../../../../actions/teams/Team';
import type { Team } from '../../../../utils/api-types';
import useDataLoader from '../../../../utils/hooks/useDataLoader';
import { fetchTeams } from '../../../../actions/teams/team-actions';
import { useAppDispatch } from '../../../../utils/hooks';
import type { TeamsHelper } from '../../../../actions/teams/team-helper';
import TeamPlayers from './TeamPlayers';
import { PermissionsContext, TeamContext } from '../../common/Context';

Expand Down Expand Up @@ -125,28 +118,20 @@ const inlineStylesContextual: Record<string, CSSProperties> = {
};

interface Props {
teamIds: Team['team_id'][];
teams: TeamStore[];
}

interface TeamStoreExtended extends TeamStore {
team_users_enabled_number: number;
}

const ContextualTeams: React.FC<Props> = ({ teamIds }) => {
const ContextualTeams: React.FC<Props> = ({ teams }) => {
// Standard hooks
const dispatch = useAppDispatch();
const classes = useStyles();
const [selectedTeam, setSelectedTeam] = useState<string | null>(null);
const { teams }: { teams: TeamStore[] } = useHelper((helper: TagHelper & TeamsHelper) => ({
teams: helper.getTeams(),
}));
const { computeTeamUsersEnabled } = useContext(TeamContext);
const { permissions } = useContext(PermissionsContext);

useDataLoader(() => {
dispatch(fetchTeams());
});

// Query param
const [searchParams] = useSearchParams();
const [search] = searchParams.getAll('search');
Expand All @@ -162,7 +147,7 @@ const ContextualTeams: React.FC<Props> = ({ teamIds }) => {
],
{ defaultKeyword: search },
);
const sortedTeams = filtering.filterAndSort(teams.filter((team) => teamIds.includes(team.team_id)).map((team) => {
const sortedTeams = filtering.filterAndSort(teams.map((team) => {
if (computeTeamUsersEnabled) {
return ({
team_users_enabled_number: computeTeamUsersEnabled(team.team_id),
Expand Down
34 changes: 21 additions & 13 deletions openbas-front/src/admin/components/components/teams/UpdateTeams.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ const useStyles = makeStyles(() => ({

interface Props {
addedTeamIds: Team['team_id'][];
setTeamIds: (ids: string[]) => void;
setTeams: (teams: TeamStore[]) => void;
}

const UpdateTeams: React.FC<Props> = ({
addedTeamIds,
setTeamIds,
setTeams,
}) => {
// Standard hooks
const { t } = useFormatter();
Expand All @@ -46,29 +46,37 @@ const UpdateTeams: React.FC<Props> = ({
dispatch(fetchTags());
});

const [teams, setTeams] = useState<TeamOutput[]>([]);
const [teamValues, setTeamValues] = useState<TeamOutput[]>([]);
const [selectedTeamValues, setSelectedTeamValues] = useState<TeamOutput[]>([]);

// Dialog
const [open, setOpen] = useState(false);

const handleClose = () => {
setOpen(false);
setTeamValues([]);
setSelectedTeamValues([]);
};

const handleSubmit = async () => {
setOpen(false);
onReplaceTeam?.(teamValues.map((v) => v.team_id)).then((result) => setTeamIds(result.result));
onReplaceTeam?.(selectedTeamValues.map((v) => v.team_id)).then((result) => {
if (result.result.length === 0) {
setTeams([]);
} else {
setTeams(Object.values(result.entities.teams));
}
});
};

useEffect(() => {
findTeams(addedTeamIds).then((result) => setTeamValues(result.data));
}, [addedTeamIds]);
if (open) {
findTeams(addedTeamIds).then((result) => setSelectedTeamValues(result.data));
}
}, [open, addedTeamIds]);

// Pagination
const addTeam = (_teamId: string, team: TeamOutput) => setTeamValues([...teamValues, team]);
const removeTeam = (teamId: string) => setTeamValues(teamValues.filter((v) => v.team_id !== teamId));
const addTeam = (_teamId: string, team: TeamOutput) => setSelectedTeamValues([...selectedTeamValues, team]);
const removeTeam = (teamId: string) => setSelectedTeamValues(selectedTeamValues.filter((v) => v.team_id !== teamId));

// Headers
const elements: SelectListElements<EndpointStore> = useMemo(() => ({
Expand Down Expand Up @@ -97,7 +105,7 @@ const UpdateTeams: React.FC<Props> = ({
const paginationComponent = <PaginationComponentV2
fetch={(input) => searchTeams(input)}
searchPaginationInput={searchPaginationInput}
setContent={setTeams}
setContent={setTeamValues}
entityPrefix="team"
availableFilterNames={availableFilterNames}
queryableHelpers={queryableHelpers}
Expand Down Expand Up @@ -132,16 +140,16 @@ const UpdateTeams: React.FC<Props> = ({
<DialogContent>
<Box sx={{ marginTop: 2 }}>
<SelectList
values={teams}
selectedValues={teamValues}
values={teamValues}
selectedValues={selectedTeamValues}
elements={elements}
prefix="team"
onSelect={addTeam}
onDelete={removeTeam}
paginationComponent={paginationComponent}
buttonComponent={<CreateTeam
inline
onCreate={(team) => setTeamValues([...teamValues, team])}
onCreate={(team) => setSelectedTeamValues([...selectedTeamValues, team])}
/>}
/>
</Box>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useParams } from 'react-router-dom';
import React, { useContext, useEffect, useState } from 'react';
import { Paper, Typography } from '@mui/material';
import { makeStyles } from '@mui/styles';
import { useHelper } from '../../../../../store';
import useDataLoader from '../../../../../utils/hooks/useDataLoader';
import { useAppDispatch } from '../../../../../utils/hooks';
Expand All @@ -25,18 +24,6 @@ import ContextualTeams from '../../../components/teams/ContextualTeams';
import { addScenarioTeams, removeScenarioTeams, replaceScenarioTeams, searchScenarioTeams } from '../../../../../actions/scenarios/scenario-teams-action';
import type { Page } from '../../../../../components/common/queryable/Page';

// Deprecated - https://mui.com/system/styles/basics/
// Do not use it for new code.
const useStyles = makeStyles(() => ({
paper: {
height: '100%',
minHeight: '100%',
margin: '-4px 0 0 0',
padding: 15,
borderRadius: 4,
},
}));

interface Props {
scenarioTeamsUsers: ScenarioStore['scenario_teams_users'],
}
Expand Down Expand Up @@ -68,7 +55,7 @@ export const teamContextForScenario = (scenarioId: ScenarioStore['scenario_id'],
onRemoveTeam(teamId: Team['team_id']): void {
dispatch(removeScenarioTeams(scenarioId, { scenario_teams: [teamId] }));
},
onReplaceTeam(teamIds: Team['team_id'][]): Promise<{ result: string[] }> {
onReplaceTeam(teamIds: Team['team_id'][]): Promise<{ result: string[], entities: { teams: Record<string, TeamStore> } }> {
return dispatch(replaceScenarioTeams(scenarioId, { scenario_teams: teamIds }));
},
onToggleUser(teamId: Team['team_id'], userId: UserStore['user_id'], userEnabled: boolean): void {
Expand All @@ -87,30 +74,37 @@ export const teamContextForScenario = (scenarioId: ScenarioStore['scenario_id'],
const ScenarioTeams: React.FC<Props> = ({ scenarioTeamsUsers }) => {
// Standard hooks
const { t } = useFormatter();
const classes = useStyles();
const dispatch = useAppDispatch();
const { permissions } = useContext(PermissionsContext);

// Fetching data
const { scenarioId } = useParams() as { scenarioId: ScenarioStore['scenario_id'] };
const { teams }: { scenario: ScenarioStore, teams: TeamStore[] } = useHelper((helper: ScenariosHelper) => ({
teams: helper.getScenarioTeams(scenarioId),
const { teamsStore }: { teamsStore: TeamStore[] } = useHelper((helper: ScenariosHelper) => ({
teamsStore: helper.getScenarioTeams(scenarioId),
}));
const { permissions } = useContext(PermissionsContext);
useDataLoader(() => {
dispatch(fetchScenarioTeams(scenarioId));
});
const [teamIds, setTeamsId] = useState<string[]>([]);

const [teams, setTeams] = useState<TeamStore[]>([]);
useEffect(() => {
setTeamsId(teams.map((team) => team.team_id));
}, [teams]);
setTeams(teamsStore);
}, [teamsStore]);

return (
<TeamContext.Provider value={teamContextForScenario(scenarioId, scenarioTeamsUsers)}>
<Typography variant="h4" gutterBottom style={{ float: 'left' }}>
{t('Teams')}
</Typography>
{permissions.canWrite && <UpdateTeams addedTeamIds={teamIds} setTeamIds={(ids: string[]) => setTeamsId(ids)}/>}
{permissions.canWrite
&& <UpdateTeams
addedTeamIds={teams.map((team: TeamStore) => team.team_id)}
setTeams={(ts: TeamStore[]) => setTeams(ts)}
/>
}
<div className="clearfix" />
<Paper classes={{ root: classes.paper }} variant="outlined">
<ContextualTeams teamIds={teamIds} />
<Paper sx={{ minHeight: '100%', padding: 2 }} variant="outlined">
<ContextualTeams teams={teams} />
</Paper>
</TeamContext.Provider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useContext } from 'react';
import { useParams } from 'react-router-dom';
import { Paper, Typography } from '@mui/material';
import { makeStyles } from '@mui/styles';
import Variables from '../../../components/variables/Variables';
import { useAppDispatch } from '../../../../../utils/hooks';
import { useHelper } from '../../../../../store';
Expand All @@ -14,22 +13,9 @@ import type { Variable, VariableInput } from '../../../../../utils/api-types';
import { useFormatter } from '../../../../../components/i18n';
import CreateVariable from '../../../components/variables/CreateVariable';

// Deprecated - https://mui.com/system/styles/basics/
// Do not use it for new code.
const useStyles = makeStyles(() => ({
paper: {
height: '100%',
minHeight: '100%',
margin: '-4px 0 0 0',
padding: 15,
borderRadius: 4,
},
}));

const ScenarioVariables = () => {
// Standard hooks
const { t } = useFormatter();
const classes = useStyles();
const dispatch = useAppDispatch();
// Fetching data
const { scenarioId } = useParams() as { scenarioId: ScenarioStore['scenario_id'] };
Expand All @@ -52,7 +38,7 @@ const ScenarioVariables = () => {
</Typography>
{permissions.canWrite && (<CreateVariable />)}
<div className="clearfix" />
<Paper classes={{ root: classes.paper }} variant="outlined">
<Paper sx={{ minHeight: '100%', padding: 2 }} variant="outlined">
<Variables variables={variables} />
</Paper>
</VariableContext.Provider>
Expand Down
Loading

0 comments on commit 8eaadc9

Please sign in to comment.