Node.js Gjs Async

今回は Node.js でシェルコマンドを使う方法を探してみる。

Node.jsからシェルコマンドを実行する – BppLOG

あらこんな簡単に、Gjs と違って日本語で見つかるのは羨ましい。
exec で非同期になるのかフムフム。

…って非同期通信だよね、mainloop いらないの?
関数を抜けた後でも callback handler を保持しなきゃいけないよね??
本当は非同期ではないのかも、実験だ!

#!/usr/bin/env node

const exec = require('child_process').exec;

exec('eog', (err, stdout, stderr) => {
    if (err) { console.log(err); }
    console.log('callback');
});

console.log('__done__');

GUI のほうが動作が解りやすいので eog を立ち上げてみる、Linux の長所だね。
macOS では Kivy とか PyObjC を使えばいいと思う。
結果は見事に __done__ のほうが先に表示、eog 終了時に callback 表示となった。
見事に関数を抜けているね、本当に非同期で動いていことを確認できた。
どうやっているの?

っっって。
よく見たら child_process というモジュール名じゃないか。
つまり Subprocess で動かしているだけってことかも。
Gjs で同様に動く処理を考えてみる、えぇと…

2017.08.27 以下おもいっきり間違えていたので書き換え

#!/usr/bin/gjs

const Gio = imports.gi.Gio;
const ByteArray = imports.byteArray;

let subprocess = Gio.Subprocess.new(["eog"], Gio.SubprocessFlags.STDIN_PIPE);
let barray = new ByteArray.ByteArray();
subprocess.communicate_async(barray, null, function(source_object, res) {
    print('__DONE__');
});
print('__EOL__');

ダメだ。
これじゃ callback を保持できないままプログラムが終わってしまう。

#!/usr/bin/gjs

const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;

let mainloop = GLib.MainLoop.new(null, false);
let subprocess = Gio.Subprocess.new(["pwd"], Gio.SubprocessFlags.STDOUT_PIPE);

subprocess.communicate_utf8_async(null, null, function(self, result) {
    let [ok, stdin_buf, stderr_buf] = self.communicate_utf8_finish(result);
    if (ok) {
        print(stdin_buf.trim()); // remove '\n'
    }
    print('__DONE__');
    mainloop.quit();
});

print('__EOL__');
mainloop.run()

やはり mainloop は必須。

色々試してみたけど GSubprocess では同様に扱うのは無理みたい。
GUI なら Gtk.main がループしてくれるのでこんな処理はいらないのだが。
GLib.Thread なら、って Gjs からは使えないジャン。

一ヶ月も更新が止まっているのはこの件ででドン詰りしていたからだったりして…
日本語情報が皆無ってキビシイなぁ、もう少し調べます。