diff --git a/apps/remixdesktop/src/plugins/xtermPlugin.ts b/apps/remixdesktop/src/plugins/xtermPlugin.ts index b1eff777b8..1c0569ddd3 100644 --- a/apps/remixdesktop/src/plugins/xtermPlugin.ts +++ b/apps/remixdesktop/src/plugins/xtermPlugin.ts @@ -13,6 +13,8 @@ import { findExecutable } from '../utils/findExecutable' import { spawnSync } from 'child_process' import { stripAnsi } from '../lib' import { DataBatcher } from '../lib/databatcher' +import { Worker } from 'worker_threads' +import { utilityProcess } from 'electron' export const detectDefaultShell = () => { const { env } = process @@ -64,6 +66,12 @@ const parseEnv = (env: any) => { return returnValue } + + + + + + export default defaultShell const profile: Profile = { @@ -103,9 +111,10 @@ const clientProfile: Profile = { } class XtermPluginClient extends ElectronBasePluginClient { - terminals: pty.IPty[] = [] + terminals: Electron.UtilityProcess[] = [] dataBatchers: DataBatcher[] = [] workingDir: string = '' + parsedEnv: any = null constructor(webContentsId: number, profile: Profile) { super(webContentsId, profile) this.onload(async () => { @@ -116,10 +125,18 @@ class XtermPluginClient extends ElectronBasePluginClient { this.workingDir = await this.call('fs' as any, 'getWorkingDir') console.log('workingDir', this.workingDir) }) + if (!(process.platform === 'win32')) { + const { stdout } = spawnSync(defaultShell, getShellEnvArgs, { + encoding: 'utf8', + }) + this.parsedEnv = parseEnv(stdout) + } + } async keystroke(key: string, pid: number): Promise { - this.terminals[pid].write(key) + //this.terminals[pid].write(key) + this.terminals[pid].postMessage({ type: 'write', data: key }) } async getShells(): Promise { @@ -140,49 +157,57 @@ class XtermPluginClient extends ElectronBasePluginClient { async createTerminal(path?: string, shell?: string): Promise { const start_time = Date.now() - console.log('createTerminal', path, shell || defaultShell) - let parsedEnv: any = null - if (!(process.platform === 'win32')) { - const { stdout } = spawnSync(defaultShell, getShellEnvArgs, { - encoding: 'utf8', + return new Promise((resolve, reject) => { + let mypy: Electron.UtilityProcess = utilityProcess.fork(__dirname + '/xtermWorker.js') + const end_time_fork = Date.now() + console.log(`fork took ${end_time_fork - start_time} ms`) + + const env = this.parsedEnv || process.env + + mypy.on('message', (message: any) => { + //console.log('message', message) + if (message.type === 'spawned') { + const end_time_spawn = Date.now() + console.log(`spawn message took ${end_time_spawn - end_time_fork} ms`) + const pid = message.pid + const dataBatcher = new DataBatcher(pid) + this.dataBatchers[pid] = dataBatcher + dataBatcher.on('flush', (data: string, uid: number) => { + this.sendData(data, uid) + }) + this.terminals[pid] = mypy + const end_time = Date.now() + console.log('spawned', pid, end_time - start_time) + resolve(pid) + } + if (message.type === 'data') { + this.dataBatchers[message.pid].write(Buffer.from(message.data)) + } + if (message.type === 'exit') { + this.closeTerminal(message.pid) + } }) - parsedEnv = parseEnv(stdout) - } - const env = parsedEnv || process.env - - const ptyProcess = pty.spawn(shell || defaultShell, [], { - name: 'xterm-color', - cols: 80, - rows: 20, - cwd: path || process.cwd(), - env: env, - encoding: 'utf8', - }); - const dataBatcher = new DataBatcher(ptyProcess.pid) - this.dataBatchers[ptyProcess.pid] = dataBatcher - ptyProcess.onData((data: string) => { - //console.log('data', data) - dataBatcher.write(Buffer.from(data)) - }) - ptyProcess.onExit(() => { - const pid = ptyProcess.pid - this.closeTerminal(pid) - }) - dataBatcher.on('flush', (data: string, uid: number) => { - this.sendData(data, uid) + mypy.postMessage({ + type: 'spawn', shell, args: [], options: + { + name: 'xterm-color', + cols: 40, + rows: 10, + cwd: path || process.cwd(), + env: env, + encoding: 'utf8', + } + }) }) - this.terminals[ptyProcess.pid] = ptyProcess - const end_time = Date.now() - console.log('createTerminal', end_time - start_time) - return ptyProcess.pid } async closeTerminal(pid: number): Promise { if (this.terminals) { if (this.terminals[pid]) { try { - this.terminals[pid].kill() + this.terminals[pid].postMessage({ type: 'close' }) + //this.terminals[pid].kill() } catch (err) { // ignore } @@ -197,7 +222,7 @@ class XtermPluginClient extends ElectronBasePluginClient { async resize({ cols, rows }: { cols: number; rows: number }, pid: number) { if (this.terminals[pid]) { try { - this.terminals[pid].resize(cols, rows) + //this.terminals[pid].postMessage({ type: 'resize', cols, rows }) } catch (_err) { const err = _err as { stack: any } console.error(err.stack) @@ -209,7 +234,7 @@ class XtermPluginClient extends ElectronBasePluginClient { async closeAll(): Promise { for (const pid in this.terminals) { - this.terminals[pid].kill() + this.terminals[pid].postMessage({ type: 'close' }) delete this.terminals[pid] this.emit('close', pid) }