читать асинхронный стандартный вывод из gjs

Я пытаюсь запустить команду из gjs и асинхронно прочитать вывод.

вот мой синхронный код

let [res, pid, in_fd, out_fd, err_fd] = GLib.spawn_async_with_pipes(null,
                                                  ['/bin/ls'], null, 0, null);
let out_reader = new Gio.DataInputStream({
  base_stream: new Gio.UnixInputStream({fd: out_fd})
});
var out = out_reader.read_until("", null);
print(out);

это отлично работает, но если я попытаюсь сделать это асинхронно, это не сработает

let [res, pid, in_fd, out_fd, err_fd]  = GLib.spawn_async_with_pipes(null,
                                                   ['/bin/ls'], null, 0, null);
let out_reader = new Gio.DataInputStream({
  base_stream: new Gio.UnixInputStream({fd: out_fd})
});
function _SocketRead(source_object, res, user_data){
  print("hi");
  let length;
  let out = out_reader.read_upto_finish(asyncResult, length);
  print("out" + out);
  print("length" + length);
}
var out = out_reader.read_upto_async("",0, 0, null, _SocketRead, "");
while(true){
   i = 0;
}

обратный вызов вообще не вызывается


person muhammedabuali    schedule 31.10.2015    source источник


Ответы (1)


Прежде всего, спасибо за вопрос, у меня также был тот же основной вопрос, то есть ваша начальная строка. Я пытаюсь запустить команду из gjs и асинхронно прочитать вывод, и в вашем вопросе были детали, необходимые мне для найти решение!

В вашем примере кода основная проблема заключается в этих строках:

while(true){
   i = 0;
}

Вы правильно пытаетесь предотвратить завершение программы до получения вывода, но это решение не работает.

Javascript является однопоточным, а это означает, что, хотя вычисления могут выполняться одновременно в смысле последовательного чередования, не может быть двух параллельных вычислений Javascript. Невозможно явно передать поток, и цикл занятости в вопросе просто продолжает вращаться, а обратный вызов никогда не получает процессорного времени.

Вместо этого вы хотите ввести цикл событий. Если вы разрабатываете расширение Gnome Shell, вы уже используете его, но если вы просто запускаете скрипт с Gjs, вам нужно явно запустить его. Я собираюсь использовать Clutter, но подойдет и другой цикл обработки событий. Следующие сегменты кода представляют собой полное рабочее решение.

Прежде всего, начнем с импорта необходимых библиотек:

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

Затем добавьте дескриптор нереста и файла из вопроса:

const [res, pid, in_fd, out_fd, err_fd] = GLib.spawn_async_with_pipes(null, ['/bin/ls'], null, 0, null);
const out_reader = new Gio.DataInputStream({
  base_stream: new Gio.UnixInputStream({fd: out_fd})
});

Вызовите функцию асинхронного чтения и дайте ей обратный вызов (определено ниже, здесь можно использовать благодаря подъему Javascript):

out_reader.read_upto_async("", 0, 0, null, _SocketRead, "");

И запустите цикл событий:

Clutter.init(null);
Clutter.main();

В вашем обратном вызове было несколько ошибок, поэтому здесь исправленная версия, которая также прерывает цикл событий, когда команда перестает выводить вывод:

function _SocketRead(source_object, res){
  const [out, length] = out_reader.read_upto_finish(res);
  if (length > 0) {
    print("out: " + out);
    print("length: " + length);
    out_reader.read_upto_async("", 0, 0, null, _SocketRead, "");
  } else {
    Clutter.main_quit();
  } 
} 

Для дальнейшего чтения есть документация по собственным привязкам Gjs по адресу https://gjs-docs.gnome.org/.

person Daniel Landau    schedule 29.11.2015