local M = {} -- Coroutine-based async/await helpers function M.await(callback_fn) local co = coroutine.running() if not co then error 'await must be called inside async' end local result, err local done = false callback_fn(function(res, e) result = res err = e done = true if coroutine.status(co) == 'suspended' then coroutine.resume(co) end end) if not done then coroutine.yield() end if err then error(err) end return result end function M.awaitAll(callback_fns) local co = coroutine.running() if not co then error 'awaitAll must be called inside async' end local results = {} local pending = #callback_fns local err = nil for i, fn in ipairs(callback_fns) do fn(function(res, e) if e then err = e end results[i] = res pending = pending - 1 if pending == 0 and coroutine.status(co) == 'suspended' then coroutine.resume(co) end end) end if pending > 0 then coroutine.yield() end if err then error(err) end return results end function M.async(fn) return function(...) local args = { ... } local co = coroutine.create(function() fn(table.unpack(args)) end) local ok, err = coroutine.resume(co) if not ok then print('Async error: ' .. tostring(err)) end end end -- Execute a shell command, returns a callback function for use with await function M.exec(cmd) return function(resolve) sbar.exec(cmd, function(result, exit_code) if exit_code ~= 0 then resolve(nil, string.format('Exit Code: %s Message: %s', tostring(exit_code), M.dump(result))) else resolve(result, nil) end end) end end return M