import { createEnsureYomitanExtensionLoadedHandler, createLoadYomitanExtensionHandler, } from './yomitan-extension-loader'; import type { Extension } from 'electron'; import { createBuildEnsureYomitanExtensionLoadedMainDepsHandler, createBuildLoadYomitanExtensionMainDepsHandler, } from './yomitan-extension-loader-main-deps'; type LoadYomitanExtensionMainDeps = Parameters< typeof createBuildLoadYomitanExtensionMainDepsHandler >[0]; type EnsureYomitanExtensionLoadedMainDeps = Omit< Parameters[0], 'loadYomitanExtension' >; export type YomitanExtensionRuntimeDeps = LoadYomitanExtensionMainDeps & EnsureYomitanExtensionLoadedMainDeps & { onYomitanExtensionLoaded?: (extension: Extension) => void | Promise; }; export function createYomitanExtensionRuntime(deps: YomitanExtensionRuntimeDeps) { const buildLoadYomitanExtensionMainDepsHandler = createBuildLoadYomitanExtensionMainDepsHandler({ loadYomitanExtensionCore: deps.loadYomitanExtensionCore, userDataPath: deps.userDataPath, externalProfilePath: deps.externalProfilePath, getYomitanParserWindow: deps.getYomitanParserWindow, setYomitanParserWindow: deps.setYomitanParserWindow, setYomitanParserReadyPromise: deps.setYomitanParserReadyPromise, setYomitanParserInitPromise: deps.setYomitanParserInitPromise, setYomitanExtension: deps.setYomitanExtension, setYomitanSession: deps.setYomitanSession, }); const loadYomitanExtensionHandler = createLoadYomitanExtensionHandler( buildLoadYomitanExtensionMainDepsHandler(), ); const buildEnsureYomitanExtensionLoadedMainDepsHandler = createBuildEnsureYomitanExtensionLoadedMainDepsHandler({ getYomitanExtension: deps.getYomitanExtension, getLoadInFlight: deps.getLoadInFlight, setLoadInFlight: deps.setLoadInFlight, loadYomitanExtension: () => loadYomitanExtensionHandler(), }); const ensureYomitanExtensionLoadedHandler = createEnsureYomitanExtensionLoadedHandler( buildEnsureYomitanExtensionLoadedMainDepsHandler(), ); let lastNotifiedExtension: Extension | null = null; let notifyingExtension: Extension | null = null; let notificationPromise: Promise | null = null; async function notifyYomitanExtensionLoaded(extension: Extension | null): Promise { if (!extension || extension === lastNotifiedExtension) { return; } if (extension === notifyingExtension && notificationPromise) { await notificationPromise; return; } notifyingExtension = extension; notificationPromise = (async () => { await deps.onYomitanExtensionLoaded?.(extension); lastNotifiedExtension = extension; })(); try { await notificationPromise; } finally { if (notifyingExtension === extension) { notifyingExtension = null; notificationPromise = null; } } } return { loadYomitanExtension: async (): Promise> => { const extension = await loadYomitanExtensionHandler(); await notifyYomitanExtensionLoaded(extension); return extension; }, ensureYomitanExtensionLoaded: async (): Promise< ReturnType > => { const extension = await ensureYomitanExtensionLoadedHandler(); await notifyYomitanExtensionLoaded(extension); return extension; }, }; }