2019-11-28 05:17:01 -09:00
|
|
|
import {EventEmitter} from 'events';
|
2023-06-26 01:29:50 -08:00
|
|
|
import type {BrowserWindow, IpcMainEvent} from 'electron';
|
|
|
|
|
import {ipcMain} from 'electron';
|
2020-03-02 01:25:27 -09:00
|
|
|
import {v4 as uuidv4} from 'uuid';
|
2023-06-26 01:29:50 -08:00
|
|
|
import type {TypedEmitter, MainEvents, RendererEvents, FilterNever} from '../common';
|
2016-06-30 22:01:04 -08:00
|
|
|
|
2023-06-25 05:26:16 -08:00
|
|
|
export class Server {
|
|
|
|
|
emitter: TypedEmitter<MainEvents>;
|
2019-12-18 07:28:28 -09:00
|
|
|
destroyed = false;
|
|
|
|
|
win: BrowserWindow;
|
|
|
|
|
id!: string;
|
2023-06-25 05:26:16 -08:00
|
|
|
|
2019-12-18 07:28:28 -09:00
|
|
|
constructor(win: BrowserWindow) {
|
2023-06-25 05:26:16 -08:00
|
|
|
this.emitter = new EventEmitter();
|
2016-06-30 22:01:04 -08:00
|
|
|
this.win = win;
|
2023-06-25 05:26:16 -08:00
|
|
|
this.emit = this.emit.bind(this);
|
2016-07-25 10:01:01 -08:00
|
|
|
|
2016-09-21 06:27:11 -08:00
|
|
|
if (this.destroyed) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-07-25 10:01:01 -08:00
|
|
|
|
2020-03-02 01:25:27 -09:00
|
|
|
const uid = uuidv4();
|
2016-07-25 10:01:01 -08:00
|
|
|
this.id = uid;
|
|
|
|
|
|
|
|
|
|
ipcMain.on(uid, this.ipcListener);
|
|
|
|
|
|
|
|
|
|
// we intentionally subscribe to `on` instead of `once`
|
|
|
|
|
// to support reloading the window and re-initializing
|
|
|
|
|
// the channel
|
|
|
|
|
this.wc.on('did-finish-load', () => {
|
|
|
|
|
this.wc.send('init', uid);
|
2016-06-30 22:01:04 -08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-21 06:27:11 -08:00
|
|
|
get wc() {
|
2016-06-30 22:01:04 -08:00
|
|
|
return this.win.webContents;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-26 01:22:59 -08:00
|
|
|
ipcListener = <U extends keyof MainEvents>(event: IpcMainEvent, {ev, data}: {ev: U; data: MainEvents[U]}) =>
|
|
|
|
|
this.emitter.emit(ev, data);
|
2023-06-25 05:26:16 -08:00
|
|
|
|
|
|
|
|
on = <U extends keyof MainEvents>(ev: U, fn: (arg0: MainEvents[U]) => void) => {
|
|
|
|
|
this.emitter.on(ev, fn);
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
once = <U extends keyof MainEvents>(ev: U, fn: (arg0: MainEvents[U]) => void) => {
|
|
|
|
|
this.emitter.once(ev, fn);
|
|
|
|
|
return this;
|
|
|
|
|
};
|
2016-06-30 22:01:04 -08:00
|
|
|
|
2023-06-25 05:26:16 -08:00
|
|
|
emit<U extends Exclude<keyof RendererEvents, FilterNever<RendererEvents>>>(ch: U): boolean;
|
|
|
|
|
emit<U extends FilterNever<RendererEvents>>(ch: U, data: RendererEvents[U]): boolean;
|
|
|
|
|
emit<U extends keyof RendererEvents>(ch: U, data?: RendererEvents[U]) {
|
2018-12-28 14:13:00 -09:00
|
|
|
// This check is needed because data-batching can cause extra data to be
|
|
|
|
|
// emitted after the window has already closed
|
|
|
|
|
if (!this.win.isDestroyed()) {
|
|
|
|
|
this.wc.send(this.id, {ch, data});
|
2023-06-25 05:26:16 -08:00
|
|
|
return true;
|
2018-12-28 14:13:00 -09:00
|
|
|
}
|
2023-06-25 05:26:16 -08:00
|
|
|
return false;
|
2016-06-30 22:01:04 -08:00
|
|
|
}
|
|
|
|
|
|
2016-09-21 06:27:11 -08:00
|
|
|
destroy() {
|
2023-06-25 05:26:16 -08:00
|
|
|
this.emitter.removeAllListeners();
|
2016-06-30 22:01:04 -08:00
|
|
|
this.wc.removeAllListeners();
|
|
|
|
|
if (this.id) {
|
|
|
|
|
ipcMain.removeListener(this.id, this.ipcListener);
|
|
|
|
|
} else {
|
|
|
|
|
// mark for `genUid` in constructor
|
|
|
|
|
this.destroyed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-18 07:28:28 -09:00
|
|
|
export default (win: BrowserWindow) => {
|
2016-06-30 22:01:04 -08:00
|
|
|
return new Server(win);
|
|
|
|
|
};
|