mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-15 21:28:40 -09:00
typed ipc invoke and handle
This commit is contained in:
parent
2b644e1fbb
commit
b90d37bd9c
5 changed files with 49 additions and 12 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint-disable eslint-comments/disable-enable-pair */
|
/* eslint-disable eslint-comments/disable-enable-pair */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
import {app, dialog, BrowserWindow, App, ipcMain} from 'electron';
|
import {app, dialog, BrowserWindow, App, ipcMain as _ipcMain} from 'electron';
|
||||||
import {resolve, basename} from 'path';
|
import {resolve, basename} from 'path';
|
||||||
import {writeFileSync} from 'fs';
|
import {writeFileSync} from 'fs';
|
||||||
import Config from 'electron-store';
|
import Config from 'electron-store';
|
||||||
|
|
@ -17,6 +17,7 @@ import mapKeys from './utils/map-keys';
|
||||||
import {configOptions} from '../lib/config';
|
import {configOptions} from '../lib/config';
|
||||||
import {promisify} from 'util';
|
import {promisify} from 'util';
|
||||||
import {exec, execFile} from 'child_process';
|
import {exec, execFile} from 'child_process';
|
||||||
|
import {IpcMainWithCommands} from '../common';
|
||||||
|
|
||||||
// local storage
|
// local storage
|
||||||
const cache = new Config();
|
const cache = new Config();
|
||||||
|
|
@ -456,12 +457,12 @@ export const decorateSessionClass = <T>(Session: T): T => {
|
||||||
|
|
||||||
export {toDependencies as _toDependencies};
|
export {toDependencies as _toDependencies};
|
||||||
|
|
||||||
ipcMain.handle('child_process.exec', (event, args) => {
|
const ipcMain = _ipcMain as IpcMainWithCommands;
|
||||||
const {command, options} = args;
|
|
||||||
|
ipcMain.handle('child_process.exec', (event, command, options) => {
|
||||||
return promisify(exec)(command, options);
|
return promisify(exec)(command, options);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('child_process.execFile', (event, _args) => {
|
ipcMain.handle('child_process.execFile', (event, file, args, options) => {
|
||||||
const {file, args, options} = _args;
|
|
||||||
return promisify(execFile)(file, args, options);
|
return promisify(execFile)(file, args, options);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import {EventEmitter} from 'events';
|
import {EventEmitter} from 'events';
|
||||||
import {ipcMain, BrowserWindow} from 'electron';
|
import {ipcMain, BrowserWindow, IpcMainEvent} from 'electron';
|
||||||
import {v4 as uuidv4} from 'uuid';
|
import {v4 as uuidv4} from 'uuid';
|
||||||
import {TypedEmitter, MainEvents, RendererEvents, FilterNever} from '../common';
|
import {TypedEmitter, MainEvents, RendererEvents, FilterNever} from '../common';
|
||||||
|
|
||||||
|
|
@ -35,7 +35,8 @@ export class Server {
|
||||||
return this.win.webContents;
|
return this.win.webContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcListener = (event: any, {ev, data}: {ev: keyof MainEvents; data: any}) => this.emitter.emit(ev, data);
|
ipcListener = <U extends keyof MainEvents>(event: IpcMainEvent, {ev, data}: {ev: U; data: MainEvents[U]}) =>
|
||||||
|
this.emitter.emit(ev, data);
|
||||||
|
|
||||||
on = <U extends keyof MainEvents>(ev: U, fn: (arg0: MainEvents[U]) => void) => {
|
on = <U extends keyof MainEvents>(ev: U, fn: (arg0: MainEvents[U]) => void) => {
|
||||||
this.emitter.on(ev, fn);
|
this.emitter.on(ev, fn);
|
||||||
|
|
|
||||||
33
common.d.ts
vendored
33
common.d.ts
vendored
|
|
@ -1,4 +1,6 @@
|
||||||
import type parseUrl from 'parse-url';
|
import type parseUrl from 'parse-url';
|
||||||
|
import type {IpcMain, IpcRenderer} from 'electron';
|
||||||
|
import type {ExecFileOptions, ExecOptions} from 'child_process';
|
||||||
|
|
||||||
export type Session = {
|
export type Session = {
|
||||||
uid: string;
|
uid: string;
|
||||||
|
|
@ -94,3 +96,34 @@ export interface TypedEmitter<Events> {
|
||||||
removeListener<E extends keyof Events>(event: E, listener: (args: Events[E]) => void): this;
|
removeListener<E extends keyof Events>(event: E, listener: (args: Events[E]) => void): this;
|
||||||
removeAllListeners<E extends keyof Events>(event?: E): this;
|
removeAllListeners<E extends keyof Events>(event?: E): this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OptionalPromise<T> = T | Promise<T>;
|
||||||
|
|
||||||
|
export type IpcCommands = {
|
||||||
|
'child_process.exec': (command: string, options: ExecOptions) => {stdout: string; stderr: string};
|
||||||
|
'child_process.execFile': (
|
||||||
|
file: string,
|
||||||
|
args: string[],
|
||||||
|
options: ExecFileOptions
|
||||||
|
) => {
|
||||||
|
stdout: string;
|
||||||
|
stderr: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface IpcMainWithCommands extends IpcMain {
|
||||||
|
handle<E extends keyof IpcCommands>(
|
||||||
|
channel: E,
|
||||||
|
listener: (
|
||||||
|
event: Electron.IpcMainInvokeEvent,
|
||||||
|
...args: Parameters<IpcCommands[E]>
|
||||||
|
) => OptionalPromise<ReturnType<IpcCommands[E]>>
|
||||||
|
): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IpcRendererWithCommands extends IpcRenderer {
|
||||||
|
invoke<E extends keyof IpcCommands>(
|
||||||
|
channel: E,
|
||||||
|
...args: Parameters<IpcCommands[E]>
|
||||||
|
): Promise<ReturnType<IpcCommands[E]>>;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import {ipcRenderer} from 'electron';
|
import electron from 'electron';
|
||||||
|
import type {IpcRendererWithCommands} from '../../common';
|
||||||
|
const ipcRenderer = electron.ipcRenderer as IpcRendererWithCommands;
|
||||||
|
|
||||||
export function exec(command: string, options?: any, callback?: (..._args: any) => void) {
|
export function exec(command: string, options?: any, callback?: (..._args: any) => void) {
|
||||||
if (typeof options === 'function') {
|
if (typeof options === 'function') {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
ipcRenderer.invoke('child_process.exec', {command, options}).then(
|
ipcRenderer.invoke('child_process.exec', command, options).then(
|
||||||
({stdout, stderr}) => callback?.(null, stdout, stderr),
|
({stdout, stderr}) => callback?.(null, stdout, stderr),
|
||||||
(error) => callback?.(error, '', '')
|
(error) => callback?.(error, '', '')
|
||||||
);
|
);
|
||||||
|
|
@ -25,7 +27,7 @@ export function execFile(file: string, args?: any, options?: any, callback?: (..
|
||||||
args = null;
|
args = null;
|
||||||
options = null;
|
options = null;
|
||||||
}
|
}
|
||||||
ipcRenderer.invoke('child_process.execFile', {file, args, options}).then(
|
ipcRenderer.invoke('child_process.execFile', file, args, options).then(
|
||||||
({stdout, stderr}) => callback?.(null, stdout, stderr),
|
({stdout, stderr}) => callback?.(null, stdout, stderr),
|
||||||
(error) => callback?.(error, '', '')
|
(error) => callback?.(error, '', '')
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,8 @@ export default class Client {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
emit<U extends Exclude<keyof MainEvents, FilterNever<MainEvents>>>(ch: U): boolean;
|
emit<U extends Exclude<keyof MainEvents, FilterNever<MainEvents>>>(ev: U): boolean;
|
||||||
emit<U extends FilterNever<MainEvents>>(ch: U, data: MainEvents[U]): boolean;
|
emit<U extends FilterNever<MainEvents>>(ev: U, data: MainEvents[U]): boolean;
|
||||||
emit<U extends keyof MainEvents>(ev: U, data?: MainEvents[U]) {
|
emit<U extends keyof MainEvents>(ev: U, data?: MainEvents[U]) {
|
||||||
if (!this.id) {
|
if (!this.id) {
|
||||||
throw new Error('Not ready');
|
throw new Error('Not ready');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue