mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Runs `yarn format` across lib/, spec/, script/, build/, default_app/, and npm/ to bring the codebase in line with the .oxfmtrc.json settings added in the previous commit. This is a pure formatting pass: import statements are sorted into the groups defined by the config, method chains longer than printWidth are broken, single-quoted strings containing apostrophes are switched to double quotes, and a handful of single-statement `if` bodies are re-wrapped and get braces added by `oxlint --fix` to satisfy the `curly: multi-line` rule. No behavior changes.
182 lines
6.7 KiB
TypeScript
182 lines
6.7 KiB
TypeScript
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
|
import { MessagePortMain } from '@electron/internal/browser/message-port-main';
|
|
|
|
import type { ServiceWorkerMain } from 'electron/main';
|
|
import { ipcMain } from 'electron/main';
|
|
|
|
const v8Util = process._linkedBinding('electron_common_v8_util');
|
|
const webFrameMainBinding = process._linkedBinding('electron_browser_web_frame_main');
|
|
|
|
const addReplyToEvent = (event: Electron.IpcMainEvent) => {
|
|
const { processId, frameId } = event;
|
|
event.reply = (channel: string, ...args: any[]) => {
|
|
event.sender.sendToFrame([processId, frameId], channel, ...args);
|
|
};
|
|
};
|
|
|
|
const addReturnValueToEvent = (event: Electron.IpcMainEvent | Electron.IpcMainServiceWorkerEvent) => {
|
|
Object.defineProperty(event, 'returnValue', {
|
|
set: (value) => event._replyChannel.sendReply(value),
|
|
get: () => {}
|
|
});
|
|
};
|
|
|
|
const getServiceWorkerFromEvent = (
|
|
event: Electron.IpcMainServiceWorkerEvent | Electron.IpcMainServiceWorkerInvokeEvent
|
|
): ServiceWorkerMain | undefined => {
|
|
return event.session.serviceWorkers._getWorkerFromVersionIDIfExists(event.versionId);
|
|
};
|
|
const addServiceWorkerPropertyToEvent = (
|
|
event: Electron.IpcMainServiceWorkerEvent | Electron.IpcMainServiceWorkerInvokeEvent
|
|
) => {
|
|
Object.defineProperty(event, 'serviceWorker', {
|
|
get: () => event.session.serviceWorkers.getWorkerFromVersionID(event.versionId)
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Cached IPC emitters sorted by dispatch priority.
|
|
* Caching is used to avoid frequent array allocations.
|
|
*/
|
|
const cachedIpcEmitters: (ElectronInternal.IpcMainInternal | undefined)[] = [
|
|
undefined, // WebFrameMain ipc
|
|
undefined, // WebContents ipc
|
|
ipcMain
|
|
];
|
|
|
|
// Get list of relevant IPC emitters for dispatch.
|
|
const getIpcEmittersForFrameEvent = (
|
|
event: Electron.IpcMainEvent | Electron.IpcMainInvokeEvent
|
|
): (ElectronInternal.IpcMainInternal | undefined)[] => {
|
|
// Lookup by FrameTreeNode ID to ensure IPCs received after a frame swap are
|
|
// always received. This occurs when a RenderFrame sends an IPC while it's
|
|
// unloading and its internal state is pending deletion.
|
|
const { frameTreeNodeId } = event;
|
|
const webFrameByFtn = frameTreeNodeId ? webFrameMainBinding._fromFtnIdIfExists(frameTreeNodeId) : undefined;
|
|
cachedIpcEmitters[0] = webFrameByFtn?.ipc;
|
|
cachedIpcEmitters[1] = event.sender.ipc;
|
|
return cachedIpcEmitters;
|
|
};
|
|
|
|
/**
|
|
* Listens for IPC dispatch events on `api`.
|
|
*/
|
|
export function addIpcDispatchListeners(api: NodeJS.EventEmitter) {
|
|
api.on(
|
|
'-ipc-message' as any,
|
|
function (event: Electron.IpcMainEvent | Electron.IpcMainServiceWorkerEvent, channel: string, args: any[]) {
|
|
const internal = v8Util.getHiddenValue<boolean>(event, 'internal');
|
|
|
|
if (internal) {
|
|
ipcMainInternal.emit(channel, event, ...args);
|
|
} else if (event.type === 'frame') {
|
|
addReplyToEvent(event);
|
|
event.sender.emit('ipc-message', event, channel, ...args);
|
|
for (const ipcEmitter of getIpcEmittersForFrameEvent(event)) {
|
|
ipcEmitter?.emit(channel, event, ...args);
|
|
}
|
|
} else if (event.type === 'service-worker') {
|
|
addServiceWorkerPropertyToEvent(event);
|
|
getServiceWorkerFromEvent(event)?.ipc.emit(channel, event, ...args);
|
|
}
|
|
} as any
|
|
);
|
|
|
|
api.on(
|
|
'-ipc-invoke' as any,
|
|
async function (
|
|
event: Electron.IpcMainInvokeEvent | Electron.IpcMainServiceWorkerInvokeEvent,
|
|
channel: string,
|
|
args: any[]
|
|
) {
|
|
const internal = v8Util.getHiddenValue<boolean>(event, 'internal');
|
|
|
|
const replyWithResult = (result: any) => event._replyChannel.sendReply({ result });
|
|
const replyWithError = (error: Error) => {
|
|
console.error(`Error occurred in handler for '${channel}':`, error);
|
|
event._replyChannel.sendReply({ error: error.toString() });
|
|
};
|
|
|
|
const targets: (Electron.IpcMainServiceWorker | ElectronInternal.IpcMainInternal | undefined)[] = [];
|
|
|
|
if (internal) {
|
|
targets.push(ipcMainInternal);
|
|
} else if (event.type === 'frame') {
|
|
targets.push(...getIpcEmittersForFrameEvent(event));
|
|
} else if (event.type === 'service-worker') {
|
|
addServiceWorkerPropertyToEvent(event);
|
|
const workerIpc = getServiceWorkerFromEvent(event)?.ipc;
|
|
targets.push(workerIpc);
|
|
}
|
|
|
|
const target = targets.find((target) => (target as any)?._invokeHandlers.has(channel));
|
|
if (target) {
|
|
const handler = (target as any)._invokeHandlers.get(channel);
|
|
try {
|
|
replyWithResult(await Promise.resolve(handler(event, ...args)));
|
|
} catch (err) {
|
|
replyWithError(err as Error);
|
|
}
|
|
} else {
|
|
replyWithError(new Error(`No handler registered for '${channel}'`));
|
|
}
|
|
} as any
|
|
);
|
|
|
|
api.on(
|
|
'-ipc-message-sync' as any,
|
|
function (event: Electron.IpcMainEvent | Electron.IpcMainServiceWorkerEvent, channel: string, args: any[]) {
|
|
const internal = v8Util.getHiddenValue<boolean>(event, 'internal');
|
|
addReturnValueToEvent(event);
|
|
if (internal) {
|
|
ipcMainInternal.emit(channel, event, ...args);
|
|
} else if (event.type === 'frame') {
|
|
addReplyToEvent(event);
|
|
const webContents = event.sender;
|
|
const ipcEmitters = getIpcEmittersForFrameEvent(event);
|
|
if (
|
|
webContents.listenerCount('ipc-message-sync') === 0 &&
|
|
ipcEmitters.every((emitter) => !emitter || emitter.listenerCount(channel) === 0)
|
|
) {
|
|
console.warn(
|
|
`WebContents #${webContents.id} called ipcRenderer.sendSync() with '${channel}' channel without listeners.`
|
|
);
|
|
}
|
|
webContents.emit('ipc-message-sync', event, channel, ...args);
|
|
for (const ipcEmitter of ipcEmitters) {
|
|
ipcEmitter?.emit(channel, event, ...args);
|
|
}
|
|
} else if (event.type === 'service-worker') {
|
|
addServiceWorkerPropertyToEvent(event);
|
|
getServiceWorkerFromEvent(event)?.ipc.emit(channel, event, ...args);
|
|
}
|
|
} as any
|
|
);
|
|
|
|
api.on('-ipc-message-host', function (event: Electron.IpcMainEvent, channel: string, args: any[]) {
|
|
event.sender.emit('-ipc-message-host', event, channel, args);
|
|
});
|
|
|
|
api.on(
|
|
'-ipc-ports' as any,
|
|
function (
|
|
event: Electron.IpcMainEvent | Electron.IpcMainServiceWorkerEvent,
|
|
channel: string,
|
|
message: any,
|
|
ports: any[]
|
|
) {
|
|
event.ports = ports.map((p) => new MessagePortMain(p));
|
|
if (event.type === 'frame') {
|
|
const ipcEmitters = getIpcEmittersForFrameEvent(event);
|
|
for (const ipcEmitter of ipcEmitters) {
|
|
ipcEmitter?.emit(channel, event, message);
|
|
}
|
|
}
|
|
if (event.type === 'service-worker') {
|
|
addServiceWorkerPropertyToEvent(event);
|
|
getServiceWorkerFromEvent(event)?.ipc.emit(channel, event, message);
|
|
}
|
|
} as any
|
|
);
|
|
}
|