Files
Toju/toju-app/src/app/infrastructure/diagnostics/diagnostics.bootstrap.ts
Myx bb0ac930ad
All checks were successful
Queue Release Build / prepare (push) Successful in 20s
Deploy Web Apps / deploy (push) Successful in 9m2s
Queue Release Build / build-windows (push) Successful in 28m8s
Queue Release Build / build-linux (push) Successful in 47m26s
Queue Release Build / build-android (push) Successful in 19m52s
Queue Release Build / finalize (push) Successful in 4m42s
Improve attachment memory safety, downloads, and high-memory alert UX.
Stream large receives to disk with chunk acks to cap renderer RAM, evict
off-screen display blobs, and route exports through a disk-aware download
service. Fix the high-memory dialog (backdrop dismiss, copy, log actions),
allow diagnostics paths in the path jail, and restore persisted image
hydration after reload.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 00:25:22 +02:00

136 lines
3.4 KiB
TypeScript

import {
EnvironmentInjector,
inject,
runInInjectionContext
} from '@angular/core';
import type { ElectronApi } from '../../core/platform/electron/electron-api.models';
import { PerfDiagnosticsCollector, publishRendererDiagnosticsSample } from './diagnostics.collector';
import type { PerfDiagEntry, PerfDiagReporter } from './diagnostics.models';
declare global {
// Registered for synchronous main-process sampling at high-memory threshold.
var __collectPerfDiagSample: (() => PerfDiagEntry[]) | undefined;
}
const SAMPLE_INTERVAL_MS = 10_000;
let started = false;
let sampleTimer: ReturnType<typeof setInterval> | null = null;
let immediateCollectorRegistered = false;
export function registerImmediatePerfDiagCollector(injector: EnvironmentInjector): void {
if (immediateCollectorRegistered) {
return;
}
let immediateSampleCollector: PerfDiagnosticsCollector | null = null;
runInInjectionContext(injector, () => {
immediateSampleCollector = inject(PerfDiagnosticsCollector);
});
globalThis.__collectPerfDiagSample = () => {
if (!immediateSampleCollector) {
return [];
}
const sample = immediateSampleCollector.collectSample();
return sample ? immediateSampleCollector.buildEntries(sample) : [];
};
immediateCollectorRegistered = true;
}
export async function bootstrapPerfDiagnostics(
api: ElectronApi,
injector: EnvironmentInjector
): Promise<void> {
registerImmediatePerfDiagCollector(injector);
const reportSample = api.reportPerfDiagSample;
if (started || !api.isPerfDiagEnabled || !reportSample) {
return;
}
let enabled = false;
try {
enabled = await api.isPerfDiagEnabled();
} catch {
return;
}
if (!enabled) {
return;
}
started = true;
const reporter: PerfDiagReporter = {
report: (entry: PerfDiagEntry) => reportSample(entry)
};
const runSample = (): void => {
void runInInjectionContext(injector, async () => {
try {
const collector = inject(PerfDiagnosticsCollector);
await publishRendererDiagnosticsSample(reporter, collector);
} catch {
stopPerfDiagnosticsSampling();
}
});
};
scheduleSample(runSample);
sampleTimer = setInterval(() => scheduleSample(runSample), SAMPLE_INTERVAL_MS);
window.addEventListener('error', () => {
void reporter.report({
collectedAt: Date.now(),
source: 'renderer',
type: 'crash',
payload: { scope: 'window-error' }
});
});
window.addEventListener('unhandledrejection', () => {
void reporter.report({
collectedAt: Date.now(),
source: 'renderer',
type: 'crash',
payload: { scope: 'unhandled-rejection' }
});
});
}
function scheduleSample(runSample: () => void): void {
const idle = (globalThis as {
requestIdleCallback?: (handler: () => void, options?: { timeout: number }) => number;
}).requestIdleCallback;
if (idle) {
idle(() => runSample(), { timeout: SAMPLE_INTERVAL_MS });
return;
}
setTimeout(runSample, 0);
}
function stopPerfDiagnosticsSampling(): void {
if (sampleTimer) {
clearInterval(sampleTimer);
sampleTimer = null;
}
started = false;
}
/** @internal Resets module state between unit tests. */
export function resetDiagnosticsBootstrapStateForTests(): void {
stopPerfDiagnosticsSampling();
immediateCollectorRegistered = false;
delete globalThis.__collectPerfDiagSample;
}