Skip to content

Commit

Permalink
regression: Notifications over context bridge (#1731)
Browse files Browse the repository at this point in the history
* Move injected script

* Inject functions and callbacks only through the context bridge
  • Loading branch information
tassoevan authored Sep 22, 2020
1 parent f8d6987 commit 75f0cdb
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 190 deletions.
24 changes: 24 additions & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,30 @@ export default [
},
],
},
{
input: 'src/injected.ts',
plugins: [
json(),
replace({
'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
}),
typescript({ noEmitOnError: false }),
babel({
babelHelpers: 'bundled',
}),
nodeResolve({
browser: true,
}),
commonjs(),
],
output: [
{
dir: 'app',
format: 'iife',
sourcemap: 'inline',
},
],
},
{
external: [
...builtinModules,
Expand Down
5 changes: 4 additions & 1 deletion src/app/main/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ export const setupRootWindowReload = async (webContents: WebContents): Promise<v

export const setupPreloadReload = async (webContents: WebContents): Promise<void> => {
const chokidar = await import('chokidar');
chokidar.watch(path.join(app.getAppPath(), 'app/preload.js'), {
chokidar.watch([
path.join(app.getAppPath(), 'app/preload.js'),
path.join(app.getAppPath(), 'app/injected.js'),
], {
awaitWriteFinish: true,
}).on('change', () => {
if (webContents.isDestroyed()) {
Expand Down
176 changes: 176 additions & 0 deletions src/injected.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { RocketChatDesktopAPI } from './servers/preload/api';

declare global {
interface Window {
RocketChatDesktop: RocketChatDesktopAPI;
}
}

const start = (): void => {
if (typeof window.require !== 'function') {
return;
}

const { Info: serverInfo = {} } = window.require('/app/utils/rocketchat.info') ?? {};

if (!serverInfo.version) {
return;
}

window.RocketChatDesktop.setServerInfo(serverInfo);

const { Meteor } = window.require('meteor/meteor');
const { Session } = window.require('meteor/session');
const { Tracker } = window.require('meteor/tracker');
const { UserPresence } = window.require('meteor/konecty:user-presence');
const { settings } = window.require('/app/settings');
const { getUserPreference } = window.require('/app/utils');

window.RocketChatDesktop.setUrlResolver(Meteor.absoluteUrl);

Tracker.autorun(() => {
const unread = Session.get('unread');
window.RocketChatDesktop.setBadge(unread);
});

Tracker.autorun(() => {
const { url, defaultUrl } = settings.get('Assets_favicon') || {};
window.RocketChatDesktop.setFavicon(url || defaultUrl);
});

Tracker.autorun(() => {
const { url, defaultUrl } = settings.get('Assets_background') || {};
window.RocketChatDesktop.setBackground(url || defaultUrl);
});

Tracker.autorun(() => {
const siteName = settings.get('Site_Name');
window.RocketChatDesktop.setTitle(siteName);
});

Tracker.autorun(() => {
const uid = Meteor.userId();
const isAutoAwayEnabled = getUserPreference(uid, 'enableAutoAway');
const idleThreshold = getUserPreference(uid, 'idleTimeLimit');

if (isAutoAwayEnabled) {
delete UserPresence.awayTime;
UserPresence.start();
}

window.RocketChatDesktop.setUserPresenceDetection({
isAutoAwayEnabled,
idleThreshold,
setUserOnline: (online) => {
Meteor.call('UserPresence:setDefaultStatus', online ? 'online' : 'away');
},
});
});

const destroyPromiseSymbol = Symbol('destroyPromise');

window.Notification = class RocketChatDesktopNotification extends EventTarget implements Notification {
static readonly permission: NotificationPermission = 'granted';

static readonly maxActions: number = process.platform === 'darwin' ? Number.MAX_SAFE_INTEGER : 0;

static requestPermission(): Promise<NotificationPermission> {
return Promise.resolve(RocketChatDesktopNotification.permission);
}

[destroyPromiseSymbol]: Promise<() => void>

constructor(title: string, options: (NotificationOptions & { canReply?: boolean }) = {}) {
super();

for (const eventType of ['show', 'close', 'click', 'reply', 'action']) {
const propertyName = `on${ eventType }`;
const propertySymbol = Symbol(propertyName);

Object.defineProperty(this, propertyName, {
get: () => this[propertySymbol],
set: (value) => {
if (this[propertySymbol]) {
this.removeEventListener(eventType, this[propertySymbol]);
}

this[propertySymbol] = value;

if (this[propertySymbol]) {
this.addEventListener(eventType, this[propertySymbol]);
}
},
});
}

this[destroyPromiseSymbol] = window.RocketChatDesktop.createNotification({
title,
...options,
onEvent: this.handleEvent,
}).then((id) => () => {
window.RocketChatDesktop.destroyNotification(id);
});

Object.assign(this, { title, ...options });
}

handleEvent = ({ type, detail }: CustomEvent): void => {
const mainWorldEvent = new CustomEvent(type, { detail });
if (type === 'reply') {
(mainWorldEvent as any).response = detail?.reply;
}
this.dispatchEvent(mainWorldEvent);
}

actions: NotificationAction[];

badge: string;

body: string;

data: any;

dir: NotificationDirection;

icon: string;

image: string;

lang: string;

onclick: (this: Notification, ev: Event) => any;

onclose: (this: Notification, ev: Event) => any;

onerror: (this: Notification, ev: Event) => any;

onshow: (this: Notification, ev: Event) => any;

renotify: boolean;

requireInteraction: boolean;

silent: boolean;

tag: string;

timestamp: number;

title: string;

vibrate: readonly number[];

close(): void {
if (!this[destroyPromiseSymbol]) {
return;
}

this[destroyPromiseSymbol].then((destroy) => {
delete this[destroyPromiseSymbol];
destroy();
});
}
};
};

start();
Loading

0 comments on commit 75f0cdb

Please sign in to comment.