electron-bridge: Move mutable state out of electron_bridge.

Only the initial value of a mutable field is exposed via
exposeInMainWorld, which is why we have a bunch of setter and getter
functions.  It’s better to avoid the possibility for this confusion.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2020-12-01 17:45:17 -08:00
parent 82450a91a9
commit 1ca15d44a0
2 changed files with 49 additions and 57 deletions

View File

@@ -1,68 +1,62 @@
import {ipcRenderer} from 'electron'; import {ipcRenderer} from 'electron';
import {EventEmitter} from 'events'; import {EventEmitter} from 'events';
import isDev from 'electron-is-dev';
import {ClipboardDecrypterImpl} from './clipboard-decrypter'; import {ClipboardDecrypterImpl} from './clipboard-decrypter';
import {NotificationData, newNotification} from './notification'; import {NotificationData, newNotification} from './notification';
type ListenerType = ((...args: any[]) => void); type ListenerType = ((...args: any[]) => void);
class ElectronBridgeImpl extends EventEmitter implements ElectronBridge { let notificationReplySupported = false;
send_notification_reply_message_supported: boolean; // Indicates if the user is idle or not
idle_on_system: boolean; let idle = false;
last_active_on_system: number; // Indicates the time at which user was last active
let lastActive = Date.now();
constructor() { export const bridgeEvents = new EventEmitter();
super();
this.send_notification_reply_message_supported = false;
// Indicates if the user is idle or not
this.idle_on_system = false;
// Indicates the time at which user was last active const electron_bridge: ElectronBridge = {
this.last_active_on_system = Date.now(); send_event: (eventName: string | symbol, ...args: unknown[]): void => {
} bridgeEvents.emit(eventName, ...args);
},
send_event = (eventName: string | symbol, ...args: unknown[]): void => { on_event: (eventName: string, listener: ListenerType): void => {
this.emit(eventName, ...args); bridgeEvents.on(eventName, listener);
}; },
on_event = (eventName: string, listener: ListenerType): void => { new_notification: (
this.on(eventName, listener);
};
new_notification = (
title: string, title: string,
options: NotificationOptions | undefined, options: NotificationOptions | undefined,
dispatch: (type: string, eventInit: EventInit) => boolean dispatch: (type: string, eventInit: EventInit) => boolean
): NotificationData => ): NotificationData =>
newNotification(title, options, dispatch); newNotification(title, options, dispatch),
get_idle_on_system = (): boolean => this.idle_on_system; get_idle_on_system: (): boolean => idle,
get_last_active_on_system = (): number => this.last_active_on_system; get_last_active_on_system: (): number => lastActive,
get_send_notification_reply_message_supported = (): boolean => get_send_notification_reply_message_supported: (): boolean =>
this.send_notification_reply_message_supported; notificationReplySupported,
set_send_notification_reply_message_supported = (value: boolean): void => { set_send_notification_reply_message_supported: (value: boolean): void => {
this.send_notification_reply_message_supported = value; notificationReplySupported = value;
}; },
decrypt_clipboard = (version: number): ClipboardDecrypterImpl => decrypt_clipboard: (version: number): ClipboardDecrypterImpl =>
new ClipboardDecrypterImpl(version); new ClipboardDecrypterImpl(version)
} };
const electron_bridge = new ElectronBridgeImpl(); bridgeEvents.on('total_unread_count', (...args) => {
electron_bridge.on('total_unread_count', (...args) => {
ipcRenderer.send('unread-count', ...args); ipcRenderer.send('unread-count', ...args);
}); });
electron_bridge.on('realm_name', realmName => { bridgeEvents.on('realm_name', realmName => {
const serverURL = location.origin; const serverURL = location.origin;
ipcRenderer.send('realm-name-changed', serverURL, realmName); ipcRenderer.send('realm-name-changed', serverURL, realmName);
}); });
electron_bridge.on('realm_icon_url', (iconURL: unknown) => { bridgeEvents.on('realm_icon_url', (iconURL: unknown) => {
if (typeof iconURL !== 'string') { if (typeof iconURL !== 'string') {
throw new TypeError('Expected string for iconURL'); throw new TypeError('Expected string for iconURL');
} }
@@ -72,6 +66,25 @@ electron_bridge.on('realm_icon_url', (iconURL: unknown) => {
ipcRenderer.send('realm-icon-changed', serverURL, iconURL); ipcRenderer.send('realm-icon-changed', serverURL, iconURL);
}); });
// Set user as active and update the time of last activity
ipcRenderer.on('set-active', () => {
if (isDev) {
console.log('active');
}
idle = false;
lastActive = Date.now();
});
// Set user as idle and time of last activity is left unchanged
ipcRenderer.on('set-idle', () => {
if (isDev) {
console.log('idle');
}
idle = true;
});
// This follows node's idiomatic implementation of event // This follows node's idiomatic implementation of event
// emitters to make event handling more simpler instead of using // emitters to make event handling more simpler instead of using
// functions zulip side will emit event using ElectronBrigde.send_event // functions zulip side will emit event using ElectronBrigde.send_event

View File

@@ -1,8 +1,6 @@
import {contextBridge, ipcRenderer, webFrame} from 'electron'; import {contextBridge, ipcRenderer, webFrame} from 'electron';
import fs from 'fs'; import fs from 'fs';
import isDev from 'electron-is-dev';
import electron_bridge from './electron-bridge'; import electron_bridge from './electron-bridge';
import * as NetworkError from './pages/network'; import * as NetworkError from './pages/network';
@@ -72,25 +70,6 @@ document.addEventListener('keydown', event => {
} }
}); });
// Set user as active and update the time of last activity
ipcRenderer.on('set-active', () => {
if (isDev) {
console.log('active');
}
electron_bridge.idle_on_system = false;
electron_bridge.last_active_on_system = Date.now();
});
// Set user as idle and time of last activity is left unchanged
ipcRenderer.on('set-idle', () => {
if (isDev) {
console.log('idle');
}
electron_bridge.idle_on_system = true;
});
(async () => webFrame.executeJavaScript( (async () => webFrame.executeJavaScript(
fs.readFileSync(require.resolve('./injected'), 'utf8') fs.readFileSync(require.resolve('./injected'), 'utf8')
))(); ))();