asyncshell.lua 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. -- Asynchronous io.popen for Awesome WM.
  2. -- How to use...
  3. -- ...asynchronously:
  4. -- asyncshell.request('wscript -Kiev', function(f) wwidget.text = f:read("*l") end)
  5. -- ...synchronously
  6. -- wwidget.text = asyncshell.demand('wscript -Kiev', 5):read("*l") or "Error"
  7. local awful = require('awful')
  8. asyncshell = {}
  9. asyncshell.request_table = {}
  10. asyncshell.id_counter = 0
  11. asyncshell.folder = "/tmp/asyncshell"
  12. asyncshell.file_template = asyncshell.folder .. '/req'
  13. -- Create a directory for asynchell response files
  14. os.execute("mkdir -p " .. asyncshell.folder)
  15. -- Returns next tag - unique identifier of the request
  16. local function next_id()
  17. asyncshell.id_counter = (asyncshell.id_counter + 1) % 100000
  18. return asyncshell.id_counter
  19. end
  20. -- Sends an asynchronous request for an output of the shell command.
  21. -- @param command Command to be executed and taken output from
  22. -- @param callback Function to be called when the command finishes
  23. -- @return Request ID
  24. function asyncshell.request(command, callback)
  25. local id = next_id()
  26. local tmpfname = asyncshell.file_template .. id
  27. asyncshell.request_table[id] = {callback = callback}
  28. local req =
  29. string.format("bash -c '%s > %s; " ..
  30. 'echo "asyncshell.deliver(%s)" | ' ..
  31. "awesome-client' 2> /dev/null",
  32. string.gsub(command, "'", "'\\''"), tmpfname, id, tmpfname)
  33. awful.util.spawn(req, false)
  34. return id
  35. end
  36. -- Calls the remembered callback function on the output of the shell
  37. -- command.
  38. -- @param id Request ID
  39. -- @param output The output file of the shell command to be delievered
  40. function asyncshell.deliver(id)
  41. if asyncshell.request_table[id] and
  42. asyncshell.request_table[id].callback then
  43. local output = io.open(asyncshell.file_template .. id, 'r')
  44. asyncshell.request_table[id].callback(output)
  45. end
  46. end
  47. -- Sends a synchronous request for an output of the command. Waits for
  48. -- the output, but if the given timeout expires returns nil.
  49. -- @param command Command to be executed and taken output from
  50. -- @param timeout Maximum amount of time to wait for the result
  51. -- @return File handler on success, nil otherwise
  52. function asyncshell.demand(command, timeout)
  53. local id = next_id()
  54. local tmpfname = asyncshell.file_template .. id
  55. local f = io.popen(string.format("(%s > %s; echo asyncshell_done) & " ..
  56. "(sleep %s; echo asynchell_timeout)",
  57. command, tmpfname, timeout))
  58. local result = f:read("*line")
  59. if result == "asyncshell_done" then
  60. return io.open(tmpfname)
  61. end
  62. end
  63. return asyncshell