22
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Electron (Node.js)で別プロセスとinteractiveなやりとりをする

Last updated at Posted at 2016-07-05

Electronを使っていて、Rendere, Mainとはさらに別のプロセスとデータのやり取りをすることがあったのでそのメモを兼ねて。
シナリオとしては、GUIからの入力をMain -> ChildとpipeしてそれをGUIに戻すという感じ。
シーケンス図はこんな感じ。

sec.png

要は、Mainからforkしたchildのstdinに何かを書き込んでstdouをpipeしてもらえばいい。

child_process#spawn

Node.jsには子processをforkする手段が2つある。
ひとつがchild_process.fork、もうひとつがchild_process.spawn
この2つの違いは正直良くわからないのだが、forkはnode.jsスクリプトを子プロセスとしてspawnし、spawnはシェルコマンドをspawnするもののようだ。(詳しい話は公式ドキュメントを読んだほうがいいです)とりあえず今回はnode.js以外のコマンドを実行するのでspawnを使うことにした。

Sample

child-server-js

import {
    spawn
} from "child_process";
import EventEmitter from "events";
import {
    dirname,
    basename
} from "path";

class ChildServer {

    constructor() {
        this.event = new EventEmitter;
    }
    
    run(cmdPath, args = []) {
        const cmd = basename(cmdPath);
        const cwd = dirname(cmdPath);
        this.process = spawn(`./${cmd}`, args, {
            cwd: cwd
        });
        this.process.on("data", (rawData) => {
          const data = new Buffer(rawData).toString("utf-8");
          this.event.emit("child:response", data);
        })
    }
    
    write(cmd) {
        return new Promise((resolve) => {
            this.process.stdin.write(cmd + "\n");
            this.event.on("child:response", resolve);
        });
    }

    close() {
      this.process.kill();
    }
}
main.js
const child = new ChildServer();
child.run();

electron.ipcMain.on("ipc:command", (ev, arg) => {
    child.write(arg).then((res) => {
      ev.sender.send("ipc:response", res);
    });
});
renderer.js
$("#button").on("click", () => {
  const cmd = $("#input").value();
  electron.ipcRenderer.send("ipc:command", cmd);
});

electron.ipcRenderer.on("ipc:response", (res) => {
  console.log(res);
});

解説

spawnした子プロセスへの書き込みは、process.stdin.write(cmd+"\n")で行うのがミソ。(ちなみにwritelnではうまく行かなかった謎)
子プロセスからのoutputは、process.on("data")でしかキャプチャできないので、内部でEventEmitterを使ってPromiseしている。ただ、この実装だとcommandとresponseが常に排他制御されている場合にしか使えない。子プロセスがマルチスレッドで入力を受け付けて非同期でstdoutに結果を返すようなものだと、キューイングする仕組みが必要かもしれない。

22
19
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?