Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve latency on endpoint teams #1584

Merged
merged 6 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
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 @@
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);

Check warning on line 302 in openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java#L300-L302

Added lines #L300 - L302 were not covered by tests
}
}

Check warning on line 304 in openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java#L304

Added line #L304 was not covered by tests

private void syncFolders() throws Exception {
try {
// Sync sent
Folder sentBox = imapStore.getFolder(sentFolder);
sentBox.open(Folder.READ_ONLY);
synchronizeBox(sentBox, true);
tryToSynchronizeFolderFromBox(sentFolder, true);

Check warning on line 309 in openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java#L309

Added line #L309 was not covered by tests
// Sync received
for (String listeningFolder : inboxFolders) {
Folder inbox = imapStore.getFolder(listeningFolder);
inbox.open(Folder.READ_ONLY);
synchronizeBox(inbox, false);
tryToSynchronizeFolderFromBox(listeningFolder, false);

Check warning on line 312 in openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java#L312

Added line #L312 was not covered by tests
}
} catch (MessagingException e) {
log.warning("Connection failure: " + e.getMessage());
Expand All @@ -323,6 +326,9 @@
} catch (MessagingException e) {
log.warning("Retrying connection..." + e.getMessage());
Thread.sleep(2000);
if(i == 2 && imapStore != null && imapStore.isConnected()) {
imapStore.close();

Check warning on line 330 in openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java#L330

Added line #L330 was not covered by tests
}
}
}
}
Expand All @@ -346,11 +352,11 @@

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});

Check warning on line 358 in openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java#L355-L358

Added lines #L355 - L358 were not covered by tests
}
}
}
}
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