diff --git a/extensions/cpp/explorer/src/extension.cpp b/extensions/cpp/explorer/src/extension.cpp index 080dd74..6609ca7 100644 --- a/extensions/cpp/explorer/src/extension.cpp +++ b/extensions/cpp/explorer/src/extension.cpp @@ -91,7 +91,7 @@ tryFetchGame(const std::filesystem::directory_entry &entry) { auto data = sfo::load(paramSfoPath.string()); if (data.errc != sfo::error::ok) { - elog("%s: error %d", entry.path().c_str(), data.errc); + elog("%s: error %d", entry.path().c_str(), static_cast(data.errc)); return {}; } diff --git a/rpcsx-ui/src/app/server/initialization.ts b/rpcsx-ui/src/app/server/initialization.ts index dabd2ff..0f63648 100644 --- a/rpcsx-ui/src/app/server/initialization.ts +++ b/rpcsx-ui/src/app/server/initialization.ts @@ -10,7 +10,7 @@ const mainWindow: Window = { }; export function initialize() { - explorer.pushExplorerView(mainWindow, { + return explorer.pushExplorerView(mainWindow, { filter: { type: 'game' } diff --git a/rpcsx-ui/src/app/server/initialization.web.ts b/rpcsx-ui/src/app/server/initialization.web.ts index 56f3882..5bdbc1b 100644 --- a/rpcsx-ui/src/app/server/initialization.web.ts +++ b/rpcsx-ui/src/app/server/initialization.web.ts @@ -117,8 +117,7 @@ async function activateMainWindow() { setupElectron(); -export function initialize() { - console.log('web initialization'); +export async function initialize() { ipcMain.on('window/create', (_event, options) => { const win = new BrowserWindow({ webPreferences: { @@ -130,11 +129,6 @@ export function initialize() { win.loadURL(`app://-/${options.url}`); }); - // console.log(await github.githubReleases({ - // owner: "RPCSX", - // repository: "rpcsx" - // })); - const createWindow = async () => { await activateMainWindow(); @@ -152,28 +146,31 @@ export function initialize() { uiInitializedFuture.dispose(); console.log('initialization complete'); - explorer.pushExplorerView(toWindow(MainWindow), { + return explorer.pushExplorerView(toWindow(MainWindow), { filter: { type: 'game' } }); }; - app.whenReady().then(() => { - createWindow(); - - app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); - } - }); + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow(); + } }); app.on('window-all-closed', async () => { - await core.shutdown(undefined); + try { + await core.shutdown(undefined); + } catch (e) { + console.error("shutdown throws exception", e); + } if (process.platform !== 'darwin') { app.quit(); } }); + + await app.whenReady(); + return createWindow(); } diff --git a/rpcsx-ui/src/core/lib/Component.ts b/rpcsx-ui/src/core/lib/Component.ts index dfae5d7..d7635d1 100644 --- a/rpcsx-ui/src/core/lib/Component.ts +++ b/rpcsx-ui/src/core/lib/Component.ts @@ -19,6 +19,6 @@ export type ComponentId = string; export type Component = { getId(): ComponentId; - onClose(listener: () => void): IDisposable; + onClose(listener: () => void | Promise): IDisposable; sendEvent(event: string, params?: any): void; }; diff --git a/rpcsx-ui/src/core/server/ComponentActivation.web.ts b/rpcsx-ui/src/core/server/ComponentActivation.web.ts index f2d47bf..8aeada4 100644 --- a/rpcsx-ui/src/core/server/ComponentActivation.web.ts +++ b/rpcsx-ui/src/core/server/ComponentActivation.web.ts @@ -12,8 +12,16 @@ export function onComponentActivation(component: ComponentInstance) { const rendererComponent: Component = { getId: () => ":renderer", onClose: (listener) => { - webContents.on("destroyed", listener); - return Disposable.Create(() => { webContents.off("destroyed", listener); }); + const wrapped = async () => { + try { + await listener(); + } catch (e) { + console.error("onClose listener throws exception", e); + } + }; + + webContents.on("destroyed", wrapped); + return Disposable.Create(() => { webContents.off("destroyed", wrapped); }); }, sendEvent: (event, params) => { webContents.send(`${component.getName()}/${event}`, params); diff --git a/rpcsx-ui/src/core/server/ComponentInstance.ts b/rpcsx-ui/src/core/server/ComponentInstance.ts index 583b7e1..f2fc538 100644 --- a/rpcsx-ui/src/core/server/ComponentInstance.ts +++ b/rpcsx-ui/src/core/server/ComponentInstance.ts @@ -207,10 +207,7 @@ export class ComponentInstance implements ComponentContext { const externalDisposable = externalEmitter.event(listener); const emitterDisposable = emitter.event(listener); - const disposable = Disposable.Create(() => { - externalDisposable.dispose(); - emitterDisposable.dispose(); - + const disposable = Disposable.Create(async () => { if (!externalEmitter.hasListeners()) { delete caller.externalEventEmitter[externalEvent]; } @@ -219,6 +216,17 @@ export class ComponentInstance implements ComponentContext { delete this.eventEmitter[event]; } + try { + await externalDisposable.dispose(); + } catch (e) { + console.error('externalDisposable throws error', e); + } + + try { + await emitterDisposable.dispose(); + } catch (e) { + console.error('emitterDisposable throws error', e); + } }); caller.manage(disposable); diff --git a/rpcsx-ui/src/core/server/main.ts b/rpcsx-ui/src/core/server/main.ts index bc1afd7..19ea047 100644 --- a/rpcsx-ui/src/core/server/main.ts +++ b/rpcsx-ui/src/core/server/main.ts @@ -20,6 +20,10 @@ export async function activate() { await Promise.all(Object.values(components).map(component => initializeComponent(component.getManifest()))); for (const component of Object.values(components)) { + if (component.getName() == "core") { + continue; + } + try { await instance.activateComponent(component.getManifest()); } catch (e) { @@ -34,6 +38,9 @@ export async function deactivate() { const components = getComponentList(); for (const component of Object.values(components)) { + if (component.getName() == "core") { + continue; + } try { await instance.unregisterComponent(component.getId()); } catch (e) { @@ -189,5 +196,5 @@ export async function handleSettingsGet(caller: Component, request: SettingsGetR export async function shutdown(caller: Component, _request: ShutdownRequest): Promise { console.warn(`shutdown invoked by ${caller.getId()}`); - instance.uninitializeComponent(self.thisComponent().getManifest()); + await instance.uninitializeComponent(self.thisComponent().getManifest()); } diff --git a/rpcsx-ui/src/explorer/server/Component.ts b/rpcsx-ui/src/explorer/server/Component.ts index 5657059..a507d39 100644 --- a/rpcsx-ui/src/explorer/server/Component.ts +++ b/rpcsx-ui/src/explorer/server/Component.ts @@ -139,22 +139,24 @@ export class ExplorerComponent implements IDisposable { title: "Explorer progress" })).channel; + const closeDisposable = caller.onClose(async () => { + delete this.subscriptions[progressChannel]; + + await progress.progressUpdate({ + channel: progressChannel, + status: ProgressStatus.Canceled + }); + }); + progress.onProgressUpdate(({ value }) => { if (value.status == ProgressStatus.Canceled) { + closeDisposable.dispose(); delete this.subscriptions[progressChannel]; } }); this.subscriptions[progressChannel] = caller; - caller.onClose(() => { - progress.progressUpdate({ - channel: progressChannel, - status: ProgressStatus.Canceled - }); - - delete this.subscriptions[progressChannel]; - }); self.sendExplorerItemsEvent(caller, { channel: progressChannel, diff --git a/rpcsx-ui/src/progress/server/main.ts b/rpcsx-ui/src/progress/server/main.ts index 6091e41..f6a888a 100644 --- a/rpcsx-ui/src/progress/server/main.ts +++ b/rpcsx-ui/src/progress/server/main.ts @@ -60,14 +60,14 @@ export function progressCreate(source: Component, params: ProgressCreateRequest) return { channel }; } -export function progressUpdate(caller: Component, params: ProgressUpdateRequest) { +export async function progressUpdate(caller: Component, params: ProgressUpdateRequest) { const info = channels[params.channel]; if (!info) { throw { code: ErrorCode.InvalidParams }; } - if (info.creator != caller) { + if (info.creator.getId() != caller.getId()) { throw { code: ErrorCode.InvalidRequest }; } @@ -101,7 +101,7 @@ export function progressUpdate(caller: Component, params: ProgressUpdateRequest) params.status == ProgressStatus.Complete || params.status == ProgressStatus.Error) { if (info.disposable) { - info.disposable.dispose(); + await info.disposable.dispose(); } delete channels[params.channel];