Skip to content

Instantly share code, notes, and snippets.

@danguilherme
Created August 5, 2019 14:48
Show Gist options
  • Save danguilherme/5515ad3160f3b112387eb53a1ca94c33 to your computer and use it in GitHub Desktop.
Save danguilherme/5515ad3160f3b112387eb53a1ca94c33 to your computer and use it in GitHub Desktop.
Send messages from Electron Renderer to Main processes, with an RxJS observable to communicate progress and completion
// In Renderer
export function makeHttpRequest(url: string; method: string) {
return createIpcSender<{ url: string; method: string }, void>(
'http-request',
{ url, method },
);
}
// ... in browser window code ...
makeHttpRequest('https://httpbin.org', 'GET').subscribe({
next: value => console.log('Response from server', value),
error: err => console.error(err),
complete: () => console.log('End'),
});
// In Main
createIpcReceiver(
'http-request',
({ url, method }: { url: string; method: string }) =>
http.request$(url, method),
);
// http.request$ => fictional method that makes an HTTP request and returns an Observable.
export function buildChannelNames(channel: string) {
return {
source: channel,
next: `${channel}/next`,
error: `${channel}/error`,
complete: `${channel}/complete`,
};
}
import { Event, ipcMain } from 'electron';
import { Observable } from 'rxjs';
import { buildChannelNames } from './ipc';
export function createIpcReceiver<A, R>(channel: string, invoke: (args: A) => Observable<R>) {
ipcMain.on(channel, async (event: Event, args: A) => {
console.log(channel, args);
const channels = buildChannelNames(channel);
invoke(args).subscribe({
next(value) {
console.log(channels.next, value);
event.sender.send(channels.next, {
args,
value,
});
},
error(error) {
let serializedError = error;
if (error instanceof Error) {
serializedError = {
name: error.name,
message: error.message,
stack: error.stack,
};
}
console.log(channels.error, serializedError);
event.sender.send(channels.error, {
args,
error: serializedError,
});
},
complete() {
console.log(channels.complete);
event.sender.send(channels.complete, {
args,
});
},
});
});
}
import { ipcRenderer } from 'electron';
import { defer, Observable } from 'rxjs';
import { buildChannelNames } from './ipc';
export function createIpcSender<A, R>(channel: string, payload: A) {
return defer(() => {
ipcRenderer.send(channel, payload);
const message$: Observable<R> = new Observable((observer: any) => {
const channels = buildChannelNames(channel);
const onNext = ({ }: Event, args: { args: any; value: any }) => {
observer.next(args.value);
};
const onError = ({ }: Event, args: { args: any; error: any }) => {
removeListeners();
observer.error(args.error);
};
const onComplete = ({ }: Event) => {
removeListeners();
observer.complete();
};
const removeListeners = () => {
ipcRenderer.removeListener(channels.next, onNext);
ipcRenderer.removeListener(channels.error, onError);
ipcRenderer.removeListener(channels.complete, onComplete);
};
ipcRenderer.on(channels.next, onNext);
ipcRenderer.once(channels.error, onError);
ipcRenderer.once(channels.complete, onComplete);
return removeListeners;
});
return message$;
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment