Skip to content

Commit

Permalink
Gracefully fail when globals (e.g. window, document, ipcMain) don't e…
Browse files Browse the repository at this point in the history
…xist (#7)

* return ErrorObservable when no document is available

* added similar checks to renderer observable tools

* added more error checks to main

* added error catch to common

* upped version

* added more error catching on nonexistant DOM globals

Co-authored-by: Brandon Horton <[email protected]>
  • Loading branch information
KeijiBranshi and Brandon Horton authored Jul 14, 2020
1 parent 9921cc3 commit 14cf32e
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 16 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ipc-monitor",
"version": "1.0.2",
"version": "1.0.3",
"description": "Observable-based IPC Monitoring Tool",
"main": "index.js",
"scripts": {
Expand Down
6 changes: 6 additions & 0 deletions src/common/create-monitor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Observable } from "rxjs/Observable";
import { _throw as throwError } from "rxjs/observable/throw";
import { Observer } from "rxjs/Observer";
import { Subscription } from "rxjs/Subscription";
import { IpcMark } from "./types";
Expand All @@ -13,5 +14,10 @@ type MonitorOptions = {
export default function createMonitor({
wrap,
}: MonitorOptions): Observable<IpcMark> {
if (!wrap) {
return throwError(
new Error("No IPC wrapper provided to Observable constructor")
);
}
return Observable.create(wrap).share();
}
1 change: 1 addition & 0 deletions src/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { merge } from "rxjs/observable/merge";
import "rxjs/add/operator/share";
import "rxjs/add/operator/mergeMap";

import { IpcMonitor } from "../common/types";
import createIpcMainMonitor from "./monitor-ipc-main";
Expand Down
5 changes: 5 additions & 0 deletions src/main/on-all-webcontents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import { concat } from "rxjs/observable/concat";
import { defer } from "rxjs/observable/defer";
import { from } from "rxjs/observable/from";
import { fromEvent } from "rxjs/observable/fromEvent";
import { _throw as throwError } from "rxjs/observable/throw";

function onAllWebContents(): Observable<WebContents> {
if (!(webContents || app)) {
return throwError("Unable to detect webContents in this process");
}

const newWebContents = fromEvent(
app,
"web-contents-created",
Expand Down
42 changes: 29 additions & 13 deletions src/renderer/dom-observables.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { WebviewTag } from "electron";
import { Observable } from "rxjs/Observable";
import { from } from "rxjs/observable/from";
import { _throw as throwError } from "rxjs/observable/throw";
import { Observer } from "rxjs/Observer";

import "rxjs/add/operator/filter";
import "rxjs/add/operator/startWith";
import "rxjs/add/operator/mergeMap";
import "rxjs/add/operator/switchMap";

export function onDomMutations(
target: Node = document.documentElement,
target: Node = document?.documentElement,
config: MutationObserverInit = { subtree: true, childList: true }
): Observable<MutationRecord> {
if (!target) {
return throwError(
new Error("DOM Mutations Observable: Node DOM Target Provided")
);
}

return Observable.create((observer: Observer<MutationRecord>) => {
const mutation = new MutationObserver((mutationRecords) =>
mutationRecords.map((m) => observer.next(m))
Expand All @@ -21,17 +30,23 @@ export function onDomMutations(
});
}

const windowReady = new Promise((resolve) => {
const loadedHandler = () => {
resolve();
window.removeEventListener("load", loadedHandler);
};
if (document.readyState === "complete") {
resolve();
} else {
window.addEventListener("load", loadedHandler);
}
});
const whenDomReady: Observable<unknown> = from(
new Promise((resolve, reject) => {
if (!(window || document)) {
reject(new Error("Global Window/DOM not present"));
}

if (document?.readyState === "complete") {
resolve();
} else {
const loadedHandler = () => {
resolve();
window.removeEventListener("load", loadedHandler);
};
window.addEventListener("load", loadedHandler);
}
})
);

function extractWebviewElements(nodes: NodeList): WebviewTag[] {
return [...nodes.values()]
Expand All @@ -40,11 +55,12 @@ function extractWebviewElements(nodes: NodeList): WebviewTag[] {
}

export default function onWebviews(): Observable<WebviewTag> {
return from(windowReady).switchMap(() => {
return whenDomReady.switchMap(() => {
const preExistingWebviews = extractWebviewElements(
document.querySelectorAll("webview")
);
return onDomMutations()
.filter((mutation) => mutation?.addedNodes !== undefined)
.mergeMap((mutation) => extractWebviewElements(mutation.addedNodes))
.startWith(...preExistingWebviews);
});
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/monitor-ipc-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { IpcMark, ObservableConstructor } from "../common/types";

function createIpcWrapper(ipc: IpcRenderer): ObservableConstructor<IpcMark> {
return (observer: Observer<IpcMark>) => {
if (!observer) {
throw new Error("No Observer provided to Observable constructor Fn");
}

/** Helper Functions */
const mark = createMarker({ sink: observer, module: "ipcRenderer" });
const [wrapEventSender, wrapEventReceiver] = createFunctionWrappers({
Expand Down
21 changes: 19 additions & 2 deletions src/renderer/monitor-webviews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ function createWebviewWrapper(
webview: WebviewTag
): ObservableConstructor<IpcMark> {
return (observer: Observer<IpcMark>) => {
if (!observer) {
throw new Error("No Observer provided to Observable constructor Fn");
}

/** Helper Functions */
const mark = createMarker({ sink: observer, module: "webviewTag" });
const [wrapEventSender] = createFunctionWrappers({
Expand Down Expand Up @@ -43,10 +47,23 @@ function createWebviewWrapper(
};
}

function isWebviewTag(webview: WebviewTag): webview is WebviewTag {
return (
webview &&
webview instanceof HTMLElement &&
typeof webview.send === "function"
);
}

export default function createWebviewMonitor(webview: WebviewTag): IpcMonitor {
const isRendererProcess = process?.type === "renderer";
const isRendererProcess =
process?.type === "renderer" && isWebviewTag(webview);
if (!isRendererProcess) {
return throwError(new Error("Cannot access webContents from this process"));
return throwError(
new Error(
"Provided argument is not compatible with this Renderer process"
)
);
}

// monitor the WebContents object (for outgoing messages)
Expand Down

0 comments on commit 14cf32e

Please sign in to comment.