diff --git a/bin/web/src/lib/analysis.ts b/bin/web/src/lib/analysis.ts index fcb2d72..1625e40 100644 --- a/bin/web/src/lib/analysis.ts +++ b/bin/web/src/lib/analysis.ts @@ -1,13 +1,7 @@ import { parse_ndjson, type NewlineDeliminatedJson } from "./ndjson"; import { req } from "./utils"; -export type AnalysisReport = - | LoadingReport - | FinishedReport; - -export type LoadingReport = {}; - -export type FinishedReport = { +export type AnalysisReport = { metadata: ReportMetadata; rows: AnalysisRow[]; }; @@ -54,7 +48,7 @@ export type InformationalEvent = { message: string; }; -export function parse_finished_report(report_json: NewlineDeliminatedJson): FinishedReport { +export function parse_finished_report(report_json: NewlineDeliminatedJson): AnalysisReport { const metadata: ReportMetadata = report_json[0]; // this can be cast directly const rows: AnalysisRow[] = report_json.slice(1).map((row_json: any) => { const analysis: PacketAnalysis[] = row_json.analysis.map((analysis_json: any) => { @@ -93,7 +87,7 @@ export function parse_finished_report(report_json: NewlineDeliminatedJson): Fini }; } -export async function get_report(name: string): Promise { +export async function get_report(name: string): Promise { const report_json = parse_ndjson(await req('GET', `/api/analysis-report/${name}`)); return parse_finished_report(report_json); } diff --git a/bin/web/src/lib/analysisManager.ts b/bin/web/src/lib/analysisManager.ts index 40ead16..9f5cdf0 100644 --- a/bin/web/src/lib/analysisManager.ts +++ b/bin/web/src/lib/analysisManager.ts @@ -1,9 +1,14 @@ +import { get_report, type AnalysisReport } from "./analysis"; import type { Manifest, ManifestEntry } from "./manifest"; import { req } from "./utils"; export enum AnalysisStatus { + // rayhunter is currently analyzing this entry (note that this is distinct + // from the currently-recording entry) Running, + // this entry is queued to be analyzed Queued, + // analysis is finished, and the new report can be accessed Finished, } @@ -19,27 +24,40 @@ export type AnalysisResult = { }; export class AnalysisManager { - public analysis_status: Map = new Map(); + public status: Map = new Map(); + public reports: Map = new Map(); public async run_analysis(name: string) { await req('POST', `/api/analysis/${name}`); - this.analysis_status.set(name, AnalysisStatus.Queued); + this.status.set(name, AnalysisStatus.Queued); + this.reports.delete(name); } public async update() { - this.analysis_status.clear(); - const status: AnalysisStatusJson = JSON.parse(await req('GET', '/api/analysis')); if (status.running) { - this.analysis_status.set(status.running, AnalysisStatus.Running); + this.status.set(status.running, AnalysisStatus.Running); } for (const entry of status.queued) { - this.analysis_status.set(entry, AnalysisStatus.Queued); + this.status.set(entry, AnalysisStatus.Queued); } for (const entry of status.finished) { - this.analysis_status.set(entry, AnalysisStatus.Finished); + // if entry was already finished, nothing to do + if (this.status.get(entry) === AnalysisStatus.Finished) { + continue; + } + + this.status.set(entry, AnalysisStatus.Finished); + + // fetch the analysis report + this.reports.delete(entry); + get_report(entry).then(report => { + this.reports.set(entry, report); + }).catch(err => { + this.reports.set(entry, `Failed to get analysis: ${err}`); + }); } } } diff --git a/bin/web/src/lib/components/AnalysisStatus.svelte b/bin/web/src/lib/components/AnalysisStatus.svelte new file mode 100644 index 0000000..22e720f --- /dev/null +++ b/bin/web/src/lib/components/AnalysisStatus.svelte @@ -0,0 +1,40 @@ + + +

+ {summary} +

+ + diff --git a/bin/web/src/lib/components/ManifestTableRow.svelte b/bin/web/src/lib/components/ManifestTableRow.svelte index deb6bf5..2ffbbd0 100644 --- a/bin/web/src/lib/components/ManifestTableRow.svelte +++ b/bin/web/src/lib/components/ManifestTableRow.svelte @@ -1,6 +1,7 @@