From b0209bd820dd5d8c6a2de893444953490f531de0 Mon Sep 17 00:00:00 2001 From: copycat-killer Date: Wed, 5 Aug 2015 12:28:54 +0200 Subject: [PATCH 1/1] #122 merged --- asyncshell.lua | 105 +++++++++++++++++++--------------------- widgets/abase.lua | 3 +- widgets/contrib/moc.lua | 2 +- widgets/imap.lua | 5 +- widgets/mpd.lua | 2 +- widgets/weather.lua | 8 +-- 6 files changed, 55 insertions(+), 70 deletions(-) diff --git a/asyncshell.lua b/asyncshell.lua index 0aafa17..827cf4b 100644 --- a/asyncshell.lua +++ b/asyncshell.lua @@ -2,78 +2,71 @@ --[[ Licensed under GNU General Public License v2 + * (c) 2015, worron * (c) 2013, Alexander Yakushev --]] -- Asynchronous io.popen for Awesome WM. --- How to use... --- ...asynchronously: --- asyncshell.request('wscript -Kiev', function(f) wwidget.text = f:read("*l") end) --- ...synchronously: --- widget:set_text(asyncshell.demand('wscript -Kiev', 5):read("*l") or "Error") +-- How to use: +-- asyncshell.request('wscript -Kiev', function(output) wwidget.text = output end) -local spawn = require('awful.util').spawn +-- Grab environment +local awful = require('awful') -asyncshell = {} -asyncshell.request_table = {} -asyncshell.id_counter = 0 -asyncshell.folder = "/tmp/asyncshell" -asyncshell.file_template = asyncshell.folder .. '/req' +-- Initialize tables for module +asyncshell = { request_table = {}, id_counter = 0 } --- Create a directory for asynchell response files -os.execute("mkdir -p " .. asyncshell.folder) - --- Returns next tag - unique identifier of the request +-- Request counter local function next_id() - asyncshell.id_counter = (asyncshell.id_counter + 1) % 100000 - return asyncshell.id_counter + asyncshell.id_counter = (asyncshell.id_counter + 1) % 10000 + return asyncshell.id_counter +end + +-- Remove given request +function asyncshell.clear(id) + if asyncshell.request_table[id] then + if asyncshell.request_table[id].timer then + asyncshell.request_table[id].timer:stop() + asyncshell.request_table[id].timer = nil + end + asyncshell.request_table[id] = nil + end end --- Sends an asynchronous request for an output of the shell command. +-- Sends an asynchronous request for an output of the shell command -- @param command Command to be executed and taken output from -- @param callback Function to be called when the command finishes --- @return Request ID -function asyncshell.request(command, callback) - local id = next_id() - local tmpfname = asyncshell.file_template .. id - asyncshell.request_table[id] = { callback = callback } - local req = - string.format("sh -c '%s > %s; " .. - 'echo "asyncshell.deliver(%s)" | ' .. - "awesome-client' 2> /dev/null", - string.gsub(command, "'", "'\\''"), tmpfname, id) - spawn(req, false) - return id -end +-- @param timeout Maximum amount of time to wait for the result (optional) +function asyncshell.request(command, callback, timeout) + local id = next_id() + asyncshell.request_table[id] = { callback = callback } --- Calls the remembered callback function on the output of the shell --- command. --- @param id Request ID --- @param output The output file of the shell command to be delievered -function asyncshell.deliver(id) - if asyncshell.request_table[id] and - asyncshell.request_table[id].callback then - local output = io.open(asyncshell.file_template .. id, 'r') - asyncshell.request_table[id].callback(output) - end + local formatted_command = string.gsub(command, '"','\"') + + local req = string.format( + "echo \"asyncshell.deliver(%s, [[\\\"$(%s)\\\"]])\" | awesome-client &", + id, formatted_command + ) + + awful.util.spawn_with_shell(req) + + if timeout then + asyncshell.request_table[id].timer = timer({ timeout = timeout }) + asyncshell.request_table[id].timer:connect_signal("timeout", function() asyncshell.clear(id) end) + asyncshell.request_table[id].timer:start() + end end --- Sends a synchronous request for an output of the command. Waits for --- the output, but if the given timeout expires returns nil. --- @param command Command to be executed and taken output from --- @param timeout Maximum amount of time to wait for the result --- @return File handler on success, nil otherwise -function asyncshell.demand(command, timeout) - local id = next_id() - local tmpfname = asyncshell.file_template .. id - local f = io.popen(string.format("(%s > %s; echo asyncshell_done) & " .. - "(sleep %s; echo asynchell_timeout)", - command, tmpfname, timeout)) - local result = f:read("*line") - if result == "asyncshell_done" then - return io.open(tmpfname) - end +-- Calls the remembered callback function on the output of the shell command +-- @param id Request ID +-- @param output Shell command output to be delievered +function asyncshell.deliver(id, output) + local output = string.sub(output, 2, -2) + if asyncshell.request_table[id] then + asyncshell.request_table[id].callback(output) + asyncshell.clear(id) + end end return asyncshell diff --git a/widgets/abase.lua b/widgets/abase.lua index 1c132cd..98f7818 100644 --- a/widgets/abase.lua +++ b/widgets/abase.lua @@ -27,8 +27,7 @@ local function worker(args) function abase.update() async.request(cmd, function(f) - output = f:read("*all") - f:close() + output = f widget = abase.widget settings() end) diff --git a/widgets/contrib/moc.lua b/widgets/contrib/moc.lua index bd25ffb..b818bb6 100644 --- a/widgets/contrib/moc.lua +++ b/widgets/contrib/moc.lua @@ -59,7 +59,7 @@ local function worker(args) total = "N/A" } - for line in f:lines() do + for line in string.gmatch(f, "[^\n]+") do for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do if k == "State" then moc_now.state = v elseif k == "File" then moc_now.file = v diff --git a/widgets/imap.lua b/widgets/imap.lua index ec7bd1f..62b33d7 100644 --- a/widgets/imap.lua +++ b/widgets/imap.lua @@ -64,10 +64,7 @@ local function worker(args) head_command, server, port, mail, password, request) async.request(curl, function(f) - ws = f:read("*all") - f:close() - - _, mailcount = string.gsub(ws, "%d+", "") + _, mailcount = string.gsub(f, "%d+", "") _ = nil widget = imap.widget diff --git a/widgets/mpd.lua b/widgets/mpd.lua index d5f07a8..5af898b 100644 --- a/widgets/mpd.lua +++ b/widgets/mpd.lua @@ -67,7 +67,7 @@ local function worker(args) elapsed = "N/A" } - for line in f:lines() do + for line in string.gmatch(f, "[^\n]+") do for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do if k == "state" then mpd_now.state = v elseif k == "file" then mpd_now.file = v diff --git a/widgets/weather.lua b/widgets/weather.lua index 741c9dc..fb37a52 100644 --- a/widgets/weather.lua +++ b/widgets/weather.lua @@ -78,9 +78,7 @@ local function worker(args) function weather.forecast_update() local cmd = string.format(forecast_call, city_id, units, lang, cnt) async.request(cmd, function(f) - j = f:read("*all") - f:close() - weather_now, pos, err = json.decode(j, 1, nil) + weather_now, pos, err = json.decode(f, 1, nil) if not err and weather_now ~= nil and tonumber(weather_now["cod"]) == 200 then weather.notification_text = '' @@ -110,9 +108,7 @@ local function worker(args) function weather.update() local cmd = string.format(current_call, city_id, units, lang) async.request(cmd, function(f) - j = f:read("*all") - f:close() - weather_now, pos, err = json.decode(j, 1, nil) + weather_now, pos, err = json.decode(f, 1, nil) if not err and weather_now ~= nil and tonumber(weather_now["cod"]) == 200 then weather.icon_path = icons_path .. weather_now["weather"][1]["icon"] .. ".png" -- 2.39.5