Security News
Input Validation Vulnerabilities Dominate MITRE's 2024 CWE Top 25 List
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
@electron-tools/ipc
Advanced tools
Inspired by VSCode IPC implement. A more simple and more powerful way to use Electron IPC. Support service Invoke/Acknowledgement mode and event Subscribe/Publish mode between main process and renderer process.
# npm
npm install @electron-tools/ipc
# yarn
yarn add @electron-tools/ipc
# pnpm
pnpm add @electron-tools/ipc
Before using @electron-tools/ipc,we have to use event.sender.send
to response to renderer and use try catch to notice client current invoke operation has error, it is not clear.
// main process
import { ipcMain } from 'electron';
ipcMain.on('getUserById', async (event, id) => {
try {
const userInfo = await userService.getUserById(id);
event.sender.send('getUserById:response', userInfo);
} catch (e) {
event.sender.send('getUserById:error', e.message);
}
});
// renderer process
import { ipcRenderer } from 'electron';
function getUserById(id) {
return new Promise((resolve, reject) => {
ipcRenderer.on('getUserById:response', (event, userInfo) => {
resolve(userInfo);
});
ipcRenderer.on('getUserById:error', (event, errorMessage) => {
resolve(new Error(errorMessage));
});
ipcRenderer.send('getUserById', id);
});
}
After using @electron-tools/ipc
// main process
import { ElectronIPCMain } from '@electron-tools/ipc';
const electronIPCMain = new ElectronIPCMain();
// register user ServerChannel to handle client request.
electronIPCMain.registerChannel('user', {
invoke(ctx, command, ...args) {
switch (command) {
case 'getUserById':
// the only thing you need to do is invoke the service method.
// if userService#getUserById throw a error,
// error message will auto response to client.
return userService.getUserById(args[0]);
}
},
});
// renderer process
import { ElectronIPCRenderer } from '@electron-tools/ipc';
const ipcRenderer = new ElectronIPCRenderer('main_window');
function getUserById(id) {
// get user channel and invoke with command getUserById.
// invoke returns type will be Promise<UserInfo>.
// if server throw a error in execution,
// invoke will reject with a error.
return ipcRenderer.getChannel('user').invoke('getUserById', id);
}
Since Electron@7, we can use ipcMain.handle
with ipcRenderer.invoke
to do something like above show. Actually, @electron-tools/ipc
use ipcRender.send
and ipcMain.on
under the hood. in this example, we make a invoke request from main process to renderer process, but we can use the same way to make a invoke request from renderer process to main process, let's do it.
// main process
import { ElectronIPCMain } from '@electron-tools/ipc';
const electronIPCMain = new ElectronIPCMain();
async function getUserById(id) {
// we should set the target client by the first argument of getChannel which mean the client ctx.
// because the renderer process with ctx 'main_window' may be more than one,
// invoke returns with type Promise<Array<UserInfo>>
const [user] = await electronIPCMain.getChannel('main_window', 'user').invoke('getUserById', id);
return user;
}
// renderer process
import { ElectronIPCRenderer } from '@electron-tools/ipc';
const ipcRenderer = new ElectronIPCRenderer('main_window');
ipcRenderer.registerChannel('user', {
invoke(ctx, command, ...args) {
switch (command) {
case 'getUserById':
return userService.getUserById(args[0]);
}
},
});
Sometimes a server execution will take a long time, we may want to cancel the execution because it is outdated. Channel#invoke
method returns type will have a cancel
properties. which can cannel the invoke manually. for example:
// renderer process
import { ElectronIPCRenderer } from '@electron-tools/ipc';
const ipcRenderer = new ElectronIPCRenderer('main_window');
function getUserById(id) {
return ipcRenderer.getChannel('user').invoke('getUserById', id);
}
const userPromise = getUserById('xxx');
userPromise.cancel();
Publish/Subscribe design pattern is widely used in daily development. @electron-tools/ipc
also support it. Renderer process can subscribe main process event which will be published later and vice versa.
// main process
import { ElectronIPCMain } from '@electron-tools/ipc';
import { EventEmitter } from 'events';
const eventBus = new EventEmitter();
setInterval(() => {
eventBus.emit('userStatusChange', 'user login');
}, 1000);
const electronIPCMain = new ElectronIPCMain();
electronIPCMain.registerChannel('user', {
event(ctx, event) {
switch (event) {
case 'userStatusChange':
return {
subscribe(cb) {
eventBus.on('userStatusChange', cb);
return () => eventBus.off('userStatusChange', cb);
},
};
}
},
});
// renderer process
import { ElectronIPCRenderer } from '@electron-tools/ipc';
const ipcClient = new ElectronIPCRenderer('main_window');
// subscription has a unscribe method to stop listen userStatusChange event.
const subscription = ipcClient
.getChannel('user')
.event('userStatusChange')
.subscribe((latestStatus) => {
console.log(latestStatus);
});
setTimeout(() => {
// after subscribe, main process will auto remove userStatusChange listener.
// and will never send and ipc message except userStatusChange event been subscripted again.
subscription.unsubscribe();
}, 5000);
// user login
// user login
// user login
// user login
@electron-tools/ipc
use rxjs
subscribe/publish pattern under the hood. so it really simple when working with rxjs
.
// main process
import { ElectronIPCMain } from '@electron-tools/ipc';
import { Subject } from 'rxjs';
const userStatusSubject = new Subject();
setInterval(() => {
userStatusSubject.next('user login');
}, 1000);
const electronIPCMain = new ElectronIPCMain();
electronIPCMain.registerChannel('user', {
event(ctx, event) {
switch (event) {
case 'userStatusChange':
return userStatusSubject;
}
},
});
Represent connection between main process(ElectronIPCMain
) and renderer process(ElectronIPCRenderer
). ElectronIPCMain
maintains a group of connection. ElectronIPCRenderer
maintains only one connection with ElectronIPCMain
.
ServerChannel
has two method, invoke
and event
, connect with ClientChannel
by connection. Represent a group of service and subscribable, service can be invoked and subscribable can be subscribe through ClientChannel
.
ClientChannel
is a proxy channel of ServiceChannel
, also contains invoke
and event
method.
interface Subscription {
unsubscribe(): void;
}
interface Subscribable<TData = any> {
subscribe(receiver: (data: TData) => void): Subscription | void;
}
interface ClientSubscribable<TData = any> {
subscribe(receiver: (data: TData) => void): Subscription;
}
interface ServerChannel<TContext = string> {
invoke?(ctx: TContext, command: string, ...args: any[]): any;
event?(ctx: TContext, event: string): Subscribable<any>;
}
interface Cancellable {
cancel(reason?: string): void;
}
type CancellablePromise<T = any> = Promise<T> & Cancellable;
interface ClientChannel {
invoke<TArgs extends any[] = any[], TReturn = any>(command: string, ...args: TArgs): CancellablePromise<TReturn>;
event<TData = any>(event: string): ClientSubscribable<TData>;
}
interface ElectronIPCMain<TContext = string> {
registerChannel(channel: string, serverChannel: ServerChannel): void;
getChannel(ctx: TContext, channel: string): ClientChannel;
// destroy will disconect all connections.
destroy(): void;
}
interface ElectronIPCRenderer {
registerChannel(channel: string, serverChannel: ServerChannel): void;
getChannel(ctx: TContext, channel: string): ClientChannel;
// destroy will disconect current connection.
destroy(): void;
}
ElectronIPCMain
and ElectronIPCRenderer
should be initialized only once, or says it should be a singleton instance. You can initialize in one place and exports the instance, all other source want to use should import the instance.FAQs
electron ipc toolkit
The npm package @electron-tools/ipc receives a total of 0 weekly downloads. As such, @electron-tools/ipc popularity was classified as not popular.
We found that @electron-tools/ipc demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.