feat: async Process.exec

the exec_async function was not truly async but a signal based one
This commit is contained in:
Aylur
2024-08-22 02:14:36 +02:00
parent 6dd5200fa3
commit 24af00f6a7
4 changed files with 68 additions and 52 deletions
+22 -7
View File
@@ -1,4 +1,4 @@
import { Astal, GLib } from "./imports.js"
import { Astal } from "./imports.js"
type Args<Out = void, Err = void> = {
cmd: string | string[]
@@ -24,7 +24,7 @@ export function subprocess(
export function subprocess(
argsOrCmd: Args | string | string[],
onOut: (stdout: string) => void = print,
onErr: (stderr: string) => void = console.log,
onErr: (stderr: string) => void = printerr,
) {
const { cmd, err, out } = args(argsOrCmd, onOut, onErr)
const proc = Array.isArray(cmd)
@@ -44,11 +44,26 @@ export function exec(cmd: string | string[]) {
}
export function execAsync(cmd: string | string[]): Promise<string> {
const proc = Array.isArray(cmd)
? Astal.Process.exec_asyncv(cmd)
: Astal.Process.exec_async(cmd)
return new Promise((resolve, reject) => {
proc.connect("stdout", (_, out: string) => resolve(out))
proc.connect("stderr", (_, err: string) => reject(err))
if (Array.isArray(cmd)) {
Astal.Process.exec_asyncv(cmd, (_, res) => {
try {
resolve(Astal.Process.exec_asyncv_finish(res))
}
catch (error) {
reject(error)
}
})
}
else {
Astal.Process.exec_async(cmd, (_, res) => {
try {
resolve(Astal.Process.exec_finish(res))
}
catch (error) {
reject(error)
}
})
}
})
}
+16 -15
View File
@@ -68,26 +68,27 @@ end
---@param commandline string | string[]
---@param on_stdout? fun(out: string): nil
---@param on_stderr? fun(err: string): nil
---@return { kill: function } | nil proc
function M.exec_async(commandline, on_stdout, on_stderr)
local out, err = defualt_proc_args(on_stdout, on_stderr)
local proc, fail
if type(commandline) == "table" then
proc, fail = Astal.Process.exec_asyncv(commandline)
Astal.Process.exec_asyncv(commandline, function(_, res)
local stdout, fail = Astal.exec_asyncv_finish(res)
if fail ~= nil then
err(fail)
else
out(stdout)
end
end)
else
proc, fail = Astal.Process.exec_async(commandline)
Astal.Process.exec_async(commandline, function(_, res)
local stdout, fail = Astal.exec_finish(res)
if fail ~= nil then
err(fail)
else
out(stdout)
end
end)
end
if fail ~= nil then
err(fail)
return nil
end
proc.on_stdout = function(_, str)
out(str)
end
proc.on_stderr = function(_, str)
err(str)
end
return proc
end
return M
+13 -19
View File
@@ -94,32 +94,26 @@ public class Astal.Process : Object {
return Process.execv(argv);
}
public Process.exec_asyncv(string[] cmd) throws Error {
Object(argv: cmd);
process = new Subprocess.newv(cmd,
public static async string exec_asyncv(string[] cmd) throws Error {
var process = new Subprocess.newv(
cmd,
SubprocessFlags.STDERR_PIPE |
SubprocessFlags.STDOUT_PIPE
);
process.communicate_utf8_async.begin(null, null, (_, res) => {
string err_str, out_str;
try {
process.communicate_utf8_async.end(res, out out_str, out err_str);
if (process.get_successful())
stdout(out_str.strip());
else
stderr(err_str.strip());
} catch (Error err) {
printerr("%s\n", err.message);
} finally {
dispose();
}
});
string err_str, out_str;
yield process.communicate_utf8_async(null, null, out out_str, out err_str);
var success = process.get_successful();
process.dispose();
if (success)
return out_str.strip();
else
throw new IOError.FAILED(err_str.strip());
}
public static Process exec_async(string cmd) throws Error {
public static async string exec_async(string cmd) throws Error {
string[] argv;
Shell.parse_argv(cmd, out argv);
return new Process.exec_asyncv(argv);
return yield exec_asyncv(argv);
}
}
+17 -11
View File
@@ -141,20 +141,26 @@ public class Variable : VariableBase {
}, Priority.DEFAULT);
}
if (poll_exec != null) {
var proc = new Process.exec_asyncv(poll_exec);
proc.stdout.connect((str) => set_closure(str, poll_transform));
proc.stderr.connect((str) => this.error(str));
poll_id = Timeout.add(poll_interval, () => {
Process.exec_asyncv.begin(poll_exec, (_, res) => {
try {
proc = new Process.exec_asyncv(poll_exec);
proc.stdout.connect((str) => set_closure(str, poll_transform));
proc.stderr.connect((str) => this.error(str));
return Source.CONTINUE;
var str = Process.exec_asyncv.end(res);
set_closure(str, poll_transform);
} catch (Error err) {
printerr("%s\n", err.message);
poll_id = 0;
return Source.REMOVE;
this.error(err.message);
}
});
poll_id = Timeout.add(poll_interval, () => {
Process.exec_asyncv.begin(poll_exec, (_, res) => {
try {
var str = Process.exec_asyncv.end(res);
set_closure(str, poll_transform);
} catch (Error err) {
this.error(err.message);
Source.remove(poll_id);
poll_id = 0;
}
});
return Source.CONTINUE;
}, Priority.DEFAULT);
}
}