You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
2.9 KiB
113 lines
2.9 KiB
// @flow
|
|
import logger from 'logger'
|
|
import { Observable } from 'rxjs'
|
|
import uuidv4 from 'uuid/v4'
|
|
import { deserializeError } from './errors'
|
|
|
|
export function createCommand<In, A>(id: string, impl: In => Observable<A>): Command<In, A> {
|
|
return new Command(id, impl)
|
|
}
|
|
|
|
export class Command<In, A> {
|
|
id: string
|
|
impl: In => Observable<A>
|
|
|
|
constructor(id: string, impl: In => Observable<A>) {
|
|
this.id = id
|
|
this.impl = impl
|
|
}
|
|
|
|
/**
|
|
* Usage example:
|
|
* sub = cmd.send(data).subscribe({ next: ... })
|
|
* // or
|
|
* const res = await cmd.send(data).toPromise()
|
|
*/
|
|
send(data: In): Observable<A> {
|
|
return ipcRendererSendCommand(this.id, data)
|
|
}
|
|
}
|
|
|
|
type Msg<A> = {
|
|
type: 'cmd.NEXT' | 'cmd.COMPLETE' | 'cmd.ERROR',
|
|
requestId: string,
|
|
data?: A,
|
|
}
|
|
|
|
// Implements command message of (Renderer proc -> Main proc)
|
|
function ipcRendererSendCommand<In, A>(id: string, data: In): Observable<A> {
|
|
const { ipcRenderer } = require('electron')
|
|
return Observable.create(o => {
|
|
const requestId: string = uuidv4()
|
|
const startTime = Date.now()
|
|
|
|
const unsubscribe = () => {
|
|
ipcRenderer.send('command-unsubscribe', { requestId })
|
|
ipcRenderer.removeListener('command-event', handleCommandEvent)
|
|
}
|
|
|
|
function handleCommandEvent(e, msg: Msg<A>) {
|
|
if (requestId !== msg.requestId) return
|
|
logger.onCmd(msg.type, id, Date.now() - startTime, msg.data)
|
|
switch (msg.type) {
|
|
case 'cmd.NEXT':
|
|
if (msg.data) {
|
|
o.next(msg.data)
|
|
}
|
|
break
|
|
|
|
case 'cmd.COMPLETE':
|
|
o.complete()
|
|
ipcRenderer.removeListener('command-event', handleCommandEvent)
|
|
break
|
|
|
|
case 'cmd.ERROR': {
|
|
const error = deserializeError(msg.data)
|
|
o.error(error)
|
|
ipcRenderer.removeListener('command-event', handleCommandEvent)
|
|
break
|
|
}
|
|
|
|
default:
|
|
}
|
|
}
|
|
|
|
ipcRenderer.on('command-event', handleCommandEvent)
|
|
|
|
ipcRenderer.send('command', { id, data, requestId })
|
|
|
|
logger.onCmd('cmd.START', id, 0, data)
|
|
|
|
return unsubscribe
|
|
})
|
|
}
|
|
|
|
// Implements command message of (Main proc -> Renderer proc)
|
|
// (dual of ipcRendererSendCommand)
|
|
export function ipcMainListenReceiveCommands(o: {
|
|
onUnsubscribe: (requestId: string) => void,
|
|
onCommand: (
|
|
command: { id: string, data: *, requestId: string },
|
|
notifyCommandEvent: (Msg<*>) => void,
|
|
) => void,
|
|
}) {
|
|
const { ipcMain } = require('electron')
|
|
|
|
const onCommandUnsubscribe = (event, { requestId }) => {
|
|
o.onUnsubscribe(requestId)
|
|
}
|
|
|
|
const onCommand = (event, command) => {
|
|
o.onCommand(command, payload => {
|
|
event.sender.send('command-event', payload)
|
|
})
|
|
}
|
|
|
|
ipcMain.on('command-unsubscribe', onCommandUnsubscribe)
|
|
ipcMain.on('command', onCommand)
|
|
|
|
return () => {
|
|
ipcMain.removeListener('command-unsubscribe', onCommandUnsubscribe)
|
|
ipcMain.removeListener('command', onCommand)
|
|
}
|
|
}
|
|
|