diff --git a/docs-site/docs/creatingplugins.md b/docs-site/docs/creatingplugins.md index 8dd2ce8..8150787 100644 --- a/docs-site/docs/creatingplugins.md +++ b/docs-site/docs/creatingplugins.md @@ -162,3 +162,24 @@ export default class App { ``` **Keep in mind that the config could possibly be `undefined`.** + +## Caller +Plugins get access to the caller of the method using the context object that gets passed as the second argument of the constructor. E.g.: + +```typescript +import { PluginContext } from '@capacitor/electron'; + +export default class App { + private context: PluginContext; + + constructor(_?: Record, context: PluginContext) { + this.context = context; + } + + getId(): number { + const { sender } = this.context.caller.get(); + + return sender.id; + } +} +``` diff --git a/src/electron-platform/definitions.ts b/src/electron-platform/definitions.ts index 012b8be..da69330 100644 --- a/src/electron-platform/definitions.ts +++ b/src/electron-platform/definitions.ts @@ -1,4 +1,5 @@ import type { CapacitorConfig } from '@capacitor/cli'; +import type { WebContents, WebFrameMain, IpcMainInvokeEvent } from 'electron'; export interface SplashOptions { imageFilePath?: string; @@ -27,3 +28,20 @@ export interface ElectronConfig { export type CapacitorElectronConfig = CapacitorConfig & { electron?: ElectronConfig; }; + +export type PluginContext = { + caller: { readonly get: () => CallContext }; +}; + +export type CallContext = { + /** The internal ID of the renderer process that sent this message */ + processId: number; + /** The ID of the renderer frame that sent this message */ + frameId: number; + /** Returns the `webContents` that sent the message */ + sender: WebContents; + /** The frame that sent this message */ + senderFrame: WebFrameMain; + /** The raw `IpcMainInvokeEvent` */ + event: IpcMainInvokeEvent; +}; diff --git a/src/electron-platform/util.ts b/src/electron-platform/util.ts index c4f1728..04a5c7b 100644 --- a/src/electron-platform/util.ts +++ b/src/electron-platform/util.ts @@ -1,12 +1,13 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/prefer-for-of */ +import { AsyncLocalStorage } from 'async_hooks'; import { app, ipcMain } from 'electron'; import EventEmitter from 'events'; import { existsSync, readFileSync } from 'fs'; import mimeTypes from 'mime-types'; import { join } from 'path'; -import type { CapacitorElectronConfig } from './definitions'; +import type { CallContext, CapacitorElectronConfig } from './definitions'; class CapElectronEmitter extends EventEmitter {} let config: CapacitorElectronConfig = {}; @@ -87,6 +88,14 @@ export function deepClone(object: Record): Record { const pluginInstanceRegistry: { [pluginClassName: string]: { [functionName: string]: any } } = {}; export function setupCapacitorElectronPlugins(): void { + const callerStorage = new AsyncLocalStorage(); + const caller = Object.defineProperties( + {}, + { + get: { value: () => callerStorage.getStore(), writable: false, configurable: false, enumerable: true }, + } + ); + console.log('in setupCapacitorElectronPlugins'); const rtPluginsPath = join(app.getAppPath(), 'build', 'src', 'rt', 'electron-plugins.js'); // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -101,7 +110,9 @@ export function setupCapacitorElectronPlugins(): void { console.log(`-> ${classKey}`); if (!pluginInstanceRegistry[classKey]) { - pluginInstanceRegistry[classKey] = new plugins[pluginKey][classKey](deepClone(config as Record)); + pluginInstanceRegistry[classKey] = new plugins[pluginKey][classKey](deepClone(config as Record), { + caller, + }); } const functionList = Object.getOwnPropertyNames(plugins[pluginKey][classKey].prototype).filter( @@ -111,11 +122,18 @@ export function setupCapacitorElectronPlugins(): void { for (const functionName of functionList) { console.log(`--> ${functionName}`); - ipcMain.handle(`${classKey}-${functionName}`, (_event, ...args) => { + ipcMain.handle(`${classKey}-${functionName}`, (event, ...args) => { console.log(`called ipcMain.handle: ${classKey}-${functionName}`); const pluginRef = pluginInstanceRegistry[classKey]; - - return pluginRef[functionName](...args); + const callContext: CallContext = { + senderFrame: event.senderFrame, + processId: event.processId, + frameId: event.frameId, + sender: event.sender, + event, + }; + + return callerStorage.run(callContext, () => pluginRef[functionName](...args)); }); }