Skip to content

Commit 2aac7d1

Browse files
committed
Fix log downloading
1 parent 7385cf1 commit 2aac7d1

File tree

5 files changed

+65
-34
lines changed

5 files changed

+65
-34
lines changed

src/pages/home/AlgorithmDetail.tsx

+16-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Accordion, Button, Group, MantineColor, Text } from '@mantine/core';
2+
import axios from 'axios';
23
import { ReactNode } from 'react';
34
import { useNavigate } from 'react-router-dom';
45
import { ErrorAlert } from '../../components/ErrorAlert';
@@ -7,16 +8,21 @@ import { useActualColorScheme } from '../../hooks/use-actual-color-scheme.ts';
78
import { useAsync } from '../../hooks/use-async.ts';
89
import { AlgorithmSummary } from '../../models.ts';
910
import { useStore } from '../../store.ts';
10-
import { downloadAlgorithmResults, parseAlgorithmLogs } from '../../utils/algorithm.ts';
11-
import { authenticatedAxios } from '../../utils/axios.ts';
11+
import {
12+
downloadAlgorithmLogs,
13+
downloadAlgorithmResults,
14+
getAlgorithmLogsUrl,
15+
parseAlgorithmLogs,
16+
} from '../../utils/algorithm.ts';
1217
import { formatTimestamp } from '../../utils/format.ts';
1318

1419
export interface AlgorithmDetailProps {
1520
position: number;
1621
algorithm: AlgorithmSummary;
22+
proxy: string;
1723
}
1824

19-
export function AlgorithmDetail({ position, algorithm }: AlgorithmDetailProps): ReactNode {
25+
export function AlgorithmDetail({ position, algorithm, proxy }: AlgorithmDetailProps): ReactNode {
2026
const setAlgorithm = useStore(state => state.setAlgorithm);
2127

2228
const navigate = useNavigate();
@@ -32,14 +38,17 @@ export function AlgorithmDetail({ position, algorithm }: AlgorithmDetailProps):
3238
break;
3339
}
3440

41+
const downloadLogs = useAsync<void>(async () => {
42+
await downloadAlgorithmLogs(algorithm.id);
43+
});
44+
3545
const downloadResults = useAsync<void>(async () => {
3646
await downloadAlgorithmResults(algorithm.id);
3747
});
3848

3949
const openInVisualizer = useAsync<void>(async () => {
40-
const logsResponse = await authenticatedAxios.get(
41-
`https://bz97lt8b1e.execute-api.eu-west-1.amazonaws.com/prod/submission/logs/${algorithm.id}`,
42-
);
50+
const logsUrl = await getAlgorithmLogsUrl(algorithm.id);
51+
const logsResponse = await axios.get(proxy + logsUrl);
4352

4453
setAlgorithm(parseAlgorithmLogs(logsResponse.data, algorithm));
4554
navigate('/visualizer');
@@ -60,14 +69,7 @@ export function AlgorithmDetail({ position, algorithm }: AlgorithmDetailProps):
6069
<Accordion.Panel>
6170
{openInVisualizer.error && <ErrorAlert error={openInVisualizer.error} mb="xs" />}
6271
<Group grow mb="xs">
63-
<Button
64-
variant="outline"
65-
component="a"
66-
href={`https://bz97lt8b1e.execute-api.eu-west-1.amazonaws.com/prod/submission/logs/${algorithm.id}`}
67-
download
68-
target="_blank"
69-
rel="noreferrer"
70-
>
72+
<Button variant="outline" onClick={downloadLogs.call} loading={downloadLogs.loading}>
7173
Download logs
7274
</Button>
7375
<Button variant="outline" onClick={downloadResults.call} loading={downloadResults.loading}>

src/pages/home/AlgorithmList.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@ import { AlgorithmDetail } from './AlgorithmDetail.tsx';
55

66
export interface AlgorithmListProps {
77
algorithms: AlgorithmSummary[];
8+
proxy: string;
89
}
910

10-
export function AlgorithmList({ algorithms }: AlgorithmListProps): ReactNode {
11+
export function AlgorithmList({ algorithms, proxy }: AlgorithmListProps): ReactNode {
1112
if (algorithms.length === 0) {
1213
return <Text mt="md">No algorithms found</Text>;
1314
}
1415

1516
return (
1617
<Accordion variant="contained" defaultValue={algorithms[0].id} mt="md">
1718
{algorithms.map((algorithm, i) => (
18-
<AlgorithmDetail key={i} position={algorithms.length - i} algorithm={algorithm} />
19+
<AlgorithmDetail key={i} position={algorithms.length - i} algorithm={algorithm} proxy={proxy} />
1920
))}
2021
</Accordion>
2122
);

src/pages/home/LoadFromProsperity.tsx

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Button, Code, Kbd, PasswordInput, Select, Text } from '@mantine/core';
1+
import { Anchor, Button, Code, Kbd, PasswordInput, Select, Text, TextInput } from '@mantine/core';
22
import { AxiosResponse } from 'axios';
3-
import { FormEvent, ReactNode, useCallback } from 'react';
3+
import { FormEvent, ReactNode, useCallback, useState } from 'react';
44
import { ErrorAlert } from '../../components/ErrorAlert.tsx';
55
import { useAsync } from '../../hooks/use-async.ts';
66
import { AlgorithmSummary } from '../../models.ts';
@@ -38,6 +38,8 @@ export function LoadFromProsperity(): ReactNode {
3838
const round = useStore(state => state.round);
3939
const setRound = useStore(state => state.setRound);
4040

41+
const [proxy, setProxy] = useState('https://imc-prosperity-2-visualizer-cors-anywhere.jmerle.dev/');
42+
4143
const loadAlgorithms = useAsync<AlgorithmSummary[]>(async (): Promise<AlgorithmSummary[]> => {
4244
let response: AxiosResponse<AlgorithmSummary[]>;
4345
try {
@@ -108,6 +110,12 @@ export function LoadFromProsperity(): ReactNode {
108110
download algorithm logs and results. The visualizer communicates directly with the API used by the Prosperity
109111
website and never sends data to other servers.
110112
</Text>
113+
{/* prettier-ignore */}
114+
<Text>
115+
By default the &quot;Open in visualizer&quot; button routes the HTTP request to download the algorithm&apos;s logs through a <Anchor href="https://github.com/Rob--W/cors-anywhere" target="_blank" rel="noreferrer">CORS Anywhere</Anchor> instance hosted by the creator of this visualizer.
116+
This is necessary because the logs need to be downloaded from an AWS S3 endpoint without <Anchor href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin" target="_blank" rel="noreferrer">Access-Control-Allow-Origin</Anchor> headers that allow downloads from this visualizer.
117+
While I promise no log data is persisted server-side, you are free to change the proxy to one hosted by yourself.
118+
</Text>
111119

112120
{loadAlgorithms.error && <ErrorAlert error={loadAlgorithms.error} />}
113121

@@ -128,12 +136,20 @@ export function LoadFromProsperity(): ReactNode {
128136
mt="xs"
129137
/>
130138

139+
<TextInput
140+
label='"Open in visualizer" CORS Anywhere proxy'
141+
placeholder="Proxy"
142+
value={proxy}
143+
onInput={e => setProxy((e.target as HTMLInputElement).value)}
144+
mt="xs"
145+
/>
146+
131147
<Button fullWidth type="submit" loading={loadAlgorithms.loading} mt="sm">
132148
<div>Load algorithms</div>
133149
</Button>
134150
</form>
135151

136-
{loadAlgorithms.success && <AlgorithmList algorithms={loadAlgorithms.result!} />}
152+
{loadAlgorithms.success && <AlgorithmList algorithms={loadAlgorithms.result!} proxy={proxy} />}
137153
</HomeCard>
138154
);
139155
}

src/pages/visualizer/AlgorithmSummaryCard.tsx

+6-9
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ import { ReactNode } from 'react';
33
import { ScrollableCodeHighlight } from '../../components/ScrollableCodeHighlight.tsx';
44
import { useAsync } from '../../hooks/use-async.ts';
55
import { useStore } from '../../store.ts';
6-
import { downloadAlgorithmResults } from '../../utils/algorithm.ts';
6+
import { downloadAlgorithmLogs, downloadAlgorithmResults } from '../../utils/algorithm.ts';
77
import { formatTimestamp } from '../../utils/format.ts';
88
import { VisualizerCard } from './VisualizerCard.tsx';
99

1010
export function AlgorithmSummaryCard(): ReactNode {
1111
const algorithm = useStore(state => state.algorithm)!;
1212
const summary = algorithm.summary!;
1313

14+
const downloadLogs = useAsync<void>(async () => {
15+
await downloadAlgorithmLogs(summary.id);
16+
});
17+
1418
const downloadResults = useAsync<void>(async () => {
1519
await downloadAlgorithmResults(summary.id);
1620
});
@@ -58,14 +62,7 @@ export function AlgorithmSummaryCard(): ReactNode {
5862
</Grid.Col>
5963
<Grid.Col span={2}>
6064
<Group grow>
61-
<Button
62-
variant="outline"
63-
component="a"
64-
href={`https://bz97lt8b1e.execute-api.eu-west-1.amazonaws.com/prod/submission/logs/${summary.id}`}
65-
download
66-
target="_blank"
67-
rel="noreferrer"
68-
>
65+
<Button variant="outline" onClick={downloadLogs.call} loading={downloadLogs.loading}>
6966
Download logs
7067
</Button>
7168
<Button variant="outline" onClick={downloadResults.call} loading={downloadResults.loading}>

src/utils/algorithm.ts

+21-6
Original file line numberDiff line numberDiff line change
@@ -243,20 +243,35 @@ export function parseAlgorithmLogs(logs: string, summary?: AlgorithmSummary): Al
243243
};
244244
}
245245

246-
export async function downloadAlgorithmResults(algorithmId: string): Promise<void> {
247-
const detailsResponse = await authenticatedAxios.get(
248-
`https://bz97lt8b1e.execute-api.eu-west-1.amazonaws.com/prod/results/tutorial/${algorithmId}`,
246+
export async function getAlgorithmLogsUrl(algorithmId: string): Promise<string> {
247+
const urlResponse = await authenticatedAxios.get(
248+
`https://bz97lt8b1e.execute-api.eu-west-1.amazonaws.com/prod/submission/logs/${algorithmId}`,
249249
);
250250

251-
const resultsUrl = detailsResponse.data.algo.summary.activitiesLog;
251+
return urlResponse.data;
252+
}
252253

254+
function downloadFile(url: string): void {
253255
const link = document.createElement('a');
254-
link.href = resultsUrl;
255-
link.download = 'results.csv';
256+
link.href = url;
257+
link.download = new URL(url).pathname.split('/').pop()!;
256258
link.target = '_blank';
257259
link.rel = 'noreferrer';
258260

259261
document.body.appendChild(link);
260262
link.click();
261263
link.remove();
262264
}
265+
266+
export async function downloadAlgorithmLogs(algorithmId: string): Promise<void> {
267+
const logsUrl = await getAlgorithmLogsUrl(algorithmId);
268+
downloadFile(logsUrl);
269+
}
270+
271+
export async function downloadAlgorithmResults(algorithmId: string): Promise<void> {
272+
const detailsResponse = await authenticatedAxios.get(
273+
`https://bz97lt8b1e.execute-api.eu-west-1.amazonaws.com/prod/results/tutorial/${algorithmId}`,
274+
);
275+
276+
downloadFile(detailsResponse.data.algo.summary.activitiesLog);
277+
}

0 commit comments

Comments
 (0)