diff --git a/src/services/native/index.ts b/src/services/native/index.ts index 51afcb9a..7a105929 100644 --- a/src/services/native/index.ts +++ b/src/services/native/index.ts @@ -1,7 +1,8 @@ /* eslint-disable @typescript-eslint/require-await */ import { app, dialog, shell, MessageBoxOptions } from 'electron'; import { injectable, inject } from 'inversify'; -import { spawn, Worker } from 'threads'; +import { ModuleThread, spawn, Worker } from 'threads'; +import { Observable, of } from 'rxjs'; import type { IWindowService } from '@services/windows/interface'; import { WindowNames } from '@services/windows/WindowProperties'; @@ -15,35 +16,45 @@ import type { ZxWorker } from './zxWorker'; @injectable() export class NativeService implements INativeService { - constructor(@inject(serviceIdentifier.Window) private readonly windowService: IWindowService) {} + zxWorker: ModuleThread | undefined; + constructor(@inject(serviceIdentifier.Window) private readonly windowService: IWindowService) { + void this.initialize(); + } - public async executeZxScript(zxWorkerArguments: { fileContent: string; fileName: string }): Promise { + private async initialize(): Promise { const worker = await spawn(new Worker(workerURL)); - const observable = worker.executeZxScript(zxWorkerArguments); - return await new Promise((resolve, reject) => { + this.zxWorker = worker; + } + + public executeZxScript(zxWorkerArguments: { fileContent: string; fileName: string }): Observable { + if (this.zxWorker === undefined) { + return of('this.zxWorker not initialized'); + } + const observable = this.zxWorker.executeZxScript(zxWorkerArguments); + return new Observable((observer) => { observable.subscribe((message) => { if (message.type === 'control') { switch (message.actions) { case ZxWorkerControlActions.start: { if (message.message !== undefined) { - console.log(message.message); + observer.next(message.message); } break; } case ZxWorkerControlActions.error: { const errorMessage = message.message ?? 'get ZxWorkerControlActions.error without message'; console.error(errorMessage, { message }); - reject(new Error(errorMessage)); + observer.next(errorMessage); break; } case ZxWorkerControlActions.ended: { const endedMessage = message.message ?? 'get ZxWorkerControlActions.ended without message'; - resolve(endedMessage); + observer.next(endedMessage); break; } } } else if (message.type === 'stderr' || message.type === 'stdout') { - console.log(message.message); + observer.next(message.message); } }); }); diff --git a/src/services/native/interface.ts b/src/services/native/interface.ts index 8cc6c64d..43b4570f 100644 --- a/src/services/native/interface.ts +++ b/src/services/native/interface.ts @@ -1,4 +1,5 @@ import { MessageBoxOptions } from 'electron'; +import { Observable } from 'rxjs'; import { ProxyPropertyType } from '@/helpers/electron-ipc-proxy/common'; import { NativeChannel } from '@/constants/channels'; @@ -8,7 +9,7 @@ import { WindowNames } from '@services/windows/WindowProperties'; * Wrap call to electron api, so we won't need remote module in renderer process */ export interface INativeService { - executeZxScript(zxWorkerArguments: { fileContent: string; fileName: string }): Promise; + executeZxScript$(zxWorkerArguments: { fileContent: string; fileName: string }): Observable; open(uri: string, isDirectory?: boolean): Promise; pickDirectory(defaultPath?: string): Promise; pickFile(filters?: Electron.OpenDialogOptions['filters']): Promise; @@ -18,7 +19,7 @@ export interface INativeService { export const NativeServiceIPCDescriptor = { channel: NativeChannel.name, properties: { - executeZxScript: ProxyPropertyType.Function, + executeZxScript$: ProxyPropertyType.Function$, open: ProxyPropertyType.Function, pickDirectory: ProxyPropertyType.Function, pickFile: ProxyPropertyType.Function, diff --git a/src/services/native/zxWorker.ts b/src/services/native/zxWorker.ts index 92e01a74..70461a4f 100644 --- a/src/services/native/zxWorker.ts +++ b/src/services/native/zxWorker.ts @@ -30,9 +30,8 @@ function executeZxScript({ fileContent, fileName }: { fileContent: string; fileN execution.on('close', function (code) { observer.next({ type: 'control', actions: ZxWorkerControlActions.ended, message: `child process exited with code ${String(code)}` }); }); - execution.stdout?.on('data', (stdout: string) => { - console.log(stdout); - observer.next({ type: 'stdout', message: `child process stdout ${stdout}` }); + execution.stdout?.on('data', (stdout: Buffer) => { + observer.next({ type: 'stdout', message: String(stdout) }); }); } catch (error) { const message = `Tiddlywiki booted failed with error ${(error as Error).message} ${(error as Error).stack ?? ''}`;