feat(scraper): add stdin pipe to NDJSON spawn; stream submit with on_status
Problem: The NDJSON spawn path had no stdin support, so `M.submit` used one-shot `vim.system()` with no live feedback. Status events from the scraper were never surfaced to Neovim. Solution: Conditionally create a `stdin_pipe` in the NDJSON path and write `opts.stdin` after spawn. Switch `M.submit` to `ndjson=true`; route `ev.status` events to a new `on_status` callback and `ev.success` to the existing `callback`. A `done` flag prevents double-callback on crash.
This commit is contained in:
parent
6faf9c7537
commit
ecbe60cbd8
1 changed files with 34 additions and 11 deletions
|
|
@ -73,6 +73,10 @@ local function run_scraper(platform, subcommand, args, opts)
|
||||||
|
|
||||||
if opts and opts.ndjson then
|
if opts and opts.ndjson then
|
||||||
local uv = vim.uv
|
local uv = vim.uv
|
||||||
|
local stdin_pipe = nil
|
||||||
|
if opts.stdin then
|
||||||
|
stdin_pipe = uv.new_pipe(false)
|
||||||
|
end
|
||||||
local stdout = uv.new_pipe(false)
|
local stdout = uv.new_pipe(false)
|
||||||
local stderr = uv.new_pipe(false)
|
local stderr = uv.new_pipe(false)
|
||||||
local buf = ''
|
local buf = ''
|
||||||
|
|
@ -80,7 +84,7 @@ local function run_scraper(platform, subcommand, args, opts)
|
||||||
local handle
|
local handle
|
||||||
handle = uv.spawn(cmd[1], {
|
handle = uv.spawn(cmd[1], {
|
||||||
args = vim.list_slice(cmd, 2),
|
args = vim.list_slice(cmd, 2),
|
||||||
stdio = { nil, stdout, stderr },
|
stdio = { stdin_pipe, stdout, stderr },
|
||||||
env = spawn_env_list(env),
|
env = spawn_env_list(env),
|
||||||
cwd = plugin_path,
|
cwd = plugin_path,
|
||||||
}, function(code, signal)
|
}, function(code, signal)
|
||||||
|
|
@ -94,6 +98,9 @@ local function run_scraper(platform, subcommand, args, opts)
|
||||||
if opts.on_exit then
|
if opts.on_exit then
|
||||||
opts.on_exit({ success = (code == 0), code = code, signal = signal })
|
opts.on_exit({ success = (code == 0), code = code, signal = signal })
|
||||||
end
|
end
|
||||||
|
if stdin_pipe and not stdin_pipe:is_closing() then
|
||||||
|
stdin_pipe:close()
|
||||||
|
end
|
||||||
if not stdout:is_closing() then
|
if not stdout:is_closing() then
|
||||||
stdout:close()
|
stdout:close()
|
||||||
end
|
end
|
||||||
|
|
@ -106,10 +113,21 @@ local function run_scraper(platform, subcommand, args, opts)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if not handle then
|
if not handle then
|
||||||
|
if stdin_pipe and not stdin_pipe:is_closing() then
|
||||||
|
stdin_pipe:close()
|
||||||
|
end
|
||||||
logger.log('Failed to start scraper process', vim.log.levels.ERROR)
|
logger.log('Failed to start scraper process', vim.log.levels.ERROR)
|
||||||
return { success = false, error = 'spawn failed' }
|
return { success = false, error = 'spawn failed' }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if stdin_pipe then
|
||||||
|
uv.write(stdin_pipe, opts.stdin, function()
|
||||||
|
uv.shutdown(stdin_pipe, function()
|
||||||
|
stdin_pipe:close()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
uv.read_start(stdout, function(_, data)
|
uv.read_start(stdout, function(_, data)
|
||||||
if data == nil then
|
if data == nil then
|
||||||
if buf ~= '' and opts.on_event then
|
if buf ~= '' and opts.on_event then
|
||||||
|
|
@ -260,18 +278,23 @@ function M.scrape_all_tests(platform, contest_id, callback)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.submit(platform, contest_id, problem_id, language, source_code, credentials, callback)
|
function M.submit(platform, contest_id, problem_id, language, source_code, credentials, on_status, callback)
|
||||||
local creds_json = vim.json.encode(credentials)
|
local done = false
|
||||||
run_scraper(platform, 'submit', { contest_id, problem_id, language }, {
|
run_scraper(platform, 'submit', { contest_id, problem_id, language }, {
|
||||||
|
ndjson = true,
|
||||||
stdin = source_code,
|
stdin = source_code,
|
||||||
env_extra = { CP_CREDENTIALS = creds_json },
|
env_extra = { CP_CREDENTIALS = vim.json.encode(credentials) },
|
||||||
on_exit = function(result)
|
on_event = function(ev)
|
||||||
if type(callback) == 'function' then
|
if ev.status ~= nil then
|
||||||
if result and result.success then
|
if type(on_status) == 'function' then on_status(ev.status) end
|
||||||
callback(result.data or { success = true })
|
elseif ev.success ~= nil then
|
||||||
else
|
done = true
|
||||||
callback({ success = false, error = result and result.error or 'unknown' })
|
if type(callback) == 'function' then callback(ev) end
|
||||||
end
|
end
|
||||||
|
end,
|
||||||
|
on_exit = function(proc)
|
||||||
|
if not done and type(callback) == 'function' then
|
||||||
|
callback({ success = false, error = 'submit process exited (code=' .. tostring(proc.code) .. ')' })
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue