116 lines
3.4 KiB
Lua
116 lines
3.4 KiB
Lua
-- The unixy extension allows proxying api-functions through cli apps.
|
|
-- Why?
|
|
-- Sometimes the host OS already has cli-apps which can make up for missing lua functionality.
|
|
-- The unixy extension is written in such way that it does not block the mainloop too much.
|
|
-- Instead it checks whether the PID still exists at a certain interval-seconds (dtmax)
|
|
--
|
|
-- example of proxying an api-function to a cli app (curl):
|
|
--
|
|
-- api.protocol.http.request = unixy.proxyCLI(
|
|
-- function(url,opts, cb) return string.format( "curl -v -s %s", url ) end,
|
|
-- function( stdout, stderr, retcode, url, opts, cb)
|
|
-- local status = 200
|
|
-- if retcode ~= 0 then status = retcode end
|
|
-- cb( retcode, stdout, {string = stderr}) -- todo: parse string into key/values
|
|
-- end
|
|
-- )
|
|
--
|
|
-- api.protocol.http.request( "https://2wa.isvery.ninja", {}, function(status,data,headers)
|
|
-- print_r(status)
|
|
-- print_r(headers)
|
|
-- print_r(data)
|
|
-- end)
|
|
--
|
|
local api = ...
|
|
local ecs = api.ecs
|
|
|
|
if table.unpack == nil then
|
|
table.unpack = unpack
|
|
end
|
|
|
|
local unixy
|
|
unixy = {
|
|
name = "unixy",
|
|
enabled = true,
|
|
jobs = {},
|
|
dtmax = 1,
|
|
dt = 0,
|
|
|
|
init = function()
|
|
end,
|
|
|
|
proxyCLI = function( cmd, cmdfunc, callback )
|
|
if api.util.cmdExist(cmd) then
|
|
print("[i] attaching ".. cmd .. " cli-cmd to api")
|
|
return function(...)
|
|
return unixy.addjob( cmdfunc, callback, ...)
|
|
end
|
|
else
|
|
print("[!] could not attach ".. cmd .. " cli-cmd to api: not found")
|
|
return function()end
|
|
end
|
|
end,
|
|
|
|
update = function(dt)
|
|
unixy.dt = unixy.dt + dt
|
|
if unixy.dt > unixy.dtmax then
|
|
unixy.dt = 0
|
|
if #unixy.jobs > 0 then
|
|
unixy.check_jobs()
|
|
end
|
|
end
|
|
end,
|
|
|
|
addjob = function( cmdgen, callback, ...)
|
|
local stdout_file = os.tmpname()
|
|
local stderr_file = os.tmpname()
|
|
local pid_file = os.tmpname()
|
|
|
|
-- Run curl in the background (&) + Save curl's PID ($!) to a file
|
|
local cmd = cmdgen( ... )
|
|
cmd = string.format( cmd .. " 1> %s 2> %s & echo $! > %s", stdout_file, stderr_file, pid_file)
|
|
os.execute(cmd)
|
|
|
|
-- Read the PID that was generated
|
|
local f = io.open(pid_file, "r")
|
|
local pid = f:read("*a"):gsub("%s+", "")
|
|
f:close()
|
|
os.remove(pid_file) -- clean up pid file immediately
|
|
|
|
table.insert(unixy.jobs, {
|
|
pid = pid,
|
|
args = {...},
|
|
stdout_file = stdout_file,
|
|
stderr_file = stderr_file,
|
|
callback = callback
|
|
})
|
|
trace("[unixy] start job with pid " .. pid .. " => 1> " .. stdout_file .. " 2> " .. stderr_file)
|
|
end,
|
|
|
|
check_jobs = function()
|
|
for i = #unixy.jobs, 1, -1 do
|
|
local job = unixy.jobs[i]
|
|
-- 'kill -0' doesn't kill the process, it just checks if it exists.
|
|
local stdout, retcode = os.execute("kill -0 " .. job.pid .. " > /dev/null")
|
|
if retcode ~= 0 then
|
|
-- Process finished! Read stdout & stderr
|
|
local f = io.open(job.stdout_file, "r")
|
|
local stdout = f:read("*a")
|
|
f:close()
|
|
f = io.open(job.stderr_file, "r")
|
|
local stderr = f:read("*a")
|
|
f:close()
|
|
-- Clean up
|
|
os.remove(job.stdout_file)
|
|
os.remove(job.stderr_file)
|
|
job.callback(stdout, stderr, retcode, table.unpack(job.args) )
|
|
table.remove(unixy.jobs, i)
|
|
else
|
|
io.write(".")
|
|
io.flush()
|
|
end
|
|
end
|
|
end,
|
|
}
|
|
|
|
return unixy
|