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
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>
136 lines
3.4 KiB
TypeScript
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;
|
|
}
|