This commit is contained in:
copycat-killer 2015-08-05 12:28:54 +02:00
parent e6f3e74e0c
commit b0209bd820
6 changed files with 55 additions and 70 deletions

View File

@ -2,78 +2,71 @@
--[[ --[[
Licensed under GNU General Public License v2 Licensed under GNU General Public License v2
* (c) 2015, worron
* (c) 2013, Alexander Yakushev * (c) 2013, Alexander Yakushev
--]] --]]
-- Asynchronous io.popen for Awesome WM. -- Asynchronous io.popen for Awesome WM.
-- How to use... -- How to use:
-- ...asynchronously: -- asyncshell.request('wscript -Kiev', function(output) wwidget.text = output end)
-- 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")
local spawn = require('awful.util').spawn -- Grab environment
local awful = require('awful')
asyncshell = {} -- Initialize tables for module
asyncshell.request_table = {} asyncshell = { request_table = {}, id_counter = 0 }
asyncshell.id_counter = 0
asyncshell.folder = "/tmp/asyncshell"
asyncshell.file_template = asyncshell.folder .. '/req'
-- Create a directory for asynchell response files -- Request counter
os.execute("mkdir -p " .. asyncshell.folder)
-- Returns next tag - unique identifier of the request
local function next_id() local function next_id()
asyncshell.id_counter = (asyncshell.id_counter + 1) % 100000 asyncshell.id_counter = (asyncshell.id_counter + 1) % 10000
return asyncshell.id_counter return asyncshell.id_counter
end end
-- Sends an asynchronous request for an output of the shell command. -- 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
-- @param command Command to be executed and taken output from -- @param command Command to be executed and taken output from
-- @param callback Function to be called when the command finishes -- @param callback Function to be called when the command finishes
-- @return Request ID -- @param timeout Maximum amount of time to wait for the result (optional)
function asyncshell.request(command, callback) function asyncshell.request(command, callback, timeout)
local id = next_id() local id = next_id()
local tmpfname = asyncshell.file_template .. id asyncshell.request_table[id] = { callback = callback }
asyncshell.request_table[id] = { callback = callback }
local req = local formatted_command = string.gsub(command, '"','\"')
string.format("sh -c '%s > %s; " ..
'echo "asyncshell.deliver(%s)" | ' .. local req = string.format(
"awesome-client' 2> /dev/null", "echo \"asyncshell.deliver(%s, [[\\\"$(%s)\\\"]])\" | awesome-client &",
string.gsub(command, "'", "'\\''"), tmpfname, id) id, formatted_command
spawn(req, false) )
return id
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 end
-- Calls the remembered callback function on the output of the shell -- Calls the remembered callback function on the output of the shell command
-- command.
-- @param id Request ID -- @param id Request ID
-- @param output The output file of the shell command to be delievered -- @param output Shell command output to be delievered
function asyncshell.deliver(id) function asyncshell.deliver(id, output)
if asyncshell.request_table[id] and local output = string.sub(output, 2, -2)
asyncshell.request_table[id].callback then if asyncshell.request_table[id] then
local output = io.open(asyncshell.file_template .. id, 'r') asyncshell.request_table[id].callback(output)
asyncshell.request_table[id].callback(output) asyncshell.clear(id)
end 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
end end
return asyncshell return asyncshell

View File

@ -27,8 +27,7 @@ local function worker(args)
function abase.update() function abase.update()
async.request(cmd, function(f) async.request(cmd, function(f)
output = f:read("*all") output = f
f:close()
widget = abase.widget widget = abase.widget
settings() settings()
end) end)

View File

@ -59,7 +59,7 @@ local function worker(args)
total = "N/A" 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 for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
if k == "State" then moc_now.state = v if k == "State" then moc_now.state = v
elseif k == "File" then moc_now.file = v elseif k == "File" then moc_now.file = v

View File

@ -64,10 +64,7 @@ local function worker(args)
head_command, server, port, mail, password, request) head_command, server, port, mail, password, request)
async.request(curl, function(f) async.request(curl, function(f)
ws = f:read("*all") _, mailcount = string.gsub(f, "%d+", "")
f:close()
_, mailcount = string.gsub(ws, "%d+", "")
_ = nil _ = nil
widget = imap.widget widget = imap.widget

View File

@ -67,7 +67,7 @@ local function worker(args)
elapsed = "N/A" 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 for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
if k == "state" then mpd_now.state = v if k == "state" then mpd_now.state = v
elseif k == "file" then mpd_now.file = v elseif k == "file" then mpd_now.file = v

View File

@ -78,9 +78,7 @@ local function worker(args)
function weather.forecast_update() function weather.forecast_update()
local cmd = string.format(forecast_call, city_id, units, lang, cnt) local cmd = string.format(forecast_call, city_id, units, lang, cnt)
async.request(cmd, function(f) async.request(cmd, function(f)
j = f:read("*all") weather_now, pos, err = json.decode(f, 1, nil)
f:close()
weather_now, pos, err = json.decode(j, 1, nil)
if not err and weather_now ~= nil and tonumber(weather_now["cod"]) == 200 then if not err and weather_now ~= nil and tonumber(weather_now["cod"]) == 200 then
weather.notification_text = '' weather.notification_text = ''
@ -110,9 +108,7 @@ local function worker(args)
function weather.update() function weather.update()
local cmd = string.format(current_call, city_id, units, lang) local cmd = string.format(current_call, city_id, units, lang)
async.request(cmd, function(f) async.request(cmd, function(f)
j = f:read("*all") weather_now, pos, err = json.decode(f, 1, nil)
f:close()
weather_now, pos, err = json.decode(j, 1, nil)
if not err and weather_now ~= nil and tonumber(weather_now["cod"]) == 200 then 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" weather.icon_path = icons_path .. weather_now["weather"][1]["icon"] .. ".png"