mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
81 lines
3.2 KiB
TypeScript
81 lines
3.2 KiB
TypeScript
import { IpcRequest } from "shared/models/ipc";
|
|
import { BrowserWindow, IpcMainEvent, WebContents, ipcMain } from "electron";
|
|
import { Observable } from "rxjs";
|
|
import { IpcCompleteChannel, IpcErrorChannel, IpcTearDownChannel } from "shared/models/ipc/ipc-response.interface";
|
|
import { IpcReplier } from "shared/models/ipc/ipc-request.interface";
|
|
import { serializeError } from 'serialize-error';
|
|
import log from "electron-log";
|
|
import { IpcChannels, IpcRequestType, IpcResponseType } from "shared/models/ipc/ipc-routes";
|
|
|
|
export class IpcService {
|
|
private static instance: IpcService;
|
|
|
|
public static getInstance(): IpcService {
|
|
if (!IpcService.instance) {
|
|
IpcService.instance = new IpcService();
|
|
}
|
|
return IpcService.instance;
|
|
}
|
|
|
|
private constructor() {}
|
|
|
|
private getErrorChannel(channel: string): IpcErrorChannel {
|
|
return `${channel}_error`;
|
|
}
|
|
|
|
private getCompleteChannel(channel: string): IpcCompleteChannel {
|
|
return `${channel}_complete`;
|
|
}
|
|
|
|
private getTearDownChannel(channel: string): IpcTearDownChannel {
|
|
return `${channel}_teardown`;
|
|
}
|
|
|
|
private buildProxyListener<C extends IpcChannels>(listener: IpcListenerFromChannel<C>) {
|
|
return (event: IpcMainEvent, req: IpcRequest<IpcRequestType<C>>) => {
|
|
const window = BrowserWindow.fromWebContents(event.sender);
|
|
const replier = (data: Observable<unknown>) => this.connectStream(req.responceChannel, window, data);
|
|
listener(req.args, replier, event.sender);
|
|
};
|
|
}
|
|
|
|
public send<T>(channel: string, window: BrowserWindow, response?: T | Error): void {
|
|
if(window.webContents?.isDestroyed()){ return; }
|
|
window.webContents?.send(channel, response);
|
|
}
|
|
|
|
private connectStream(channel: string, window: BrowserWindow, observable: Observable<unknown>): void {
|
|
|
|
const sub = observable.subscribe({
|
|
next: data => this.send(channel, window, data),
|
|
error: error => {
|
|
log.error(error, error?.code, error?.data);
|
|
this.send(this.getErrorChannel(channel), window, serializeError(error));
|
|
},
|
|
complete: () => this.send(this.getCompleteChannel(channel), window)
|
|
})
|
|
|
|
const unsubscribe = () => sub.unsubscribe();
|
|
|
|
window.webContents.once("destroyed", unsubscribe);
|
|
window.webContents.ipc.once(this.getTearDownChannel(channel), unsubscribe);
|
|
|
|
sub.add(() => {
|
|
window.webContents.ipc.removeAllListeners(this.getTearDownChannel(channel));
|
|
window.webContents.removeListener("destroyed", unsubscribe);
|
|
});
|
|
}
|
|
|
|
public on<C extends IpcChannels>(channel: C, listener: IpcListenerFromChannel<C>, ipc = ipcMain): void {
|
|
ipc.on(channel as string, this.buildProxyListener(listener));
|
|
}
|
|
|
|
public once<C extends IpcChannels>(channel: C, listener: IpcListenerFromChannel<C>, ipc = ipcMain): void {
|
|
ipc.once(channel as string, this.buildProxyListener(listener));
|
|
}
|
|
}
|
|
|
|
|
|
type IpcListener<TRequest = unknown, TResponse = unknown> = (req: TRequest, replier: IpcReplier<TResponse>, webContents: WebContents) => void | Promise<void>;
|
|
type IpcListenerFromChannel<C extends IpcChannels> = IpcListener<IpcRequestType<C>, IpcResponseType<C>>;
|