forked from sudo-tee/opencode.nvim
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcurl.lua
More file actions
154 lines (133 loc) · 3.58 KB
/
curl.lua
File metadata and controls
154 lines (133 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
local M = {}
--- Build curl command arguments from options
--- @param opts table Options for the curl request
--- @return table args Array of curl command arguments
local function build_curl_args(opts)
local args = { 'curl', '-s', '--no-buffer' }
if opts.method and opts.method ~= 'GET' then
table.insert(args, '-X')
table.insert(args, opts.method)
end
if opts.headers then
for key, value in pairs(opts.headers) do
table.insert(args, '-H')
table.insert(args, key .. ': ' .. value)
end
end
if opts.body then
table.insert(args, '-d')
table.insert(args, opts.body)
end
if opts.proxy and opts.proxy ~= '' then
table.insert(args, '--proxy')
table.insert(args, opts.proxy)
end
table.insert(args, opts.url)
return args
end
--- Parse HTTP response headers and body
--- @param output string Raw curl output with headers
--- @return table response Response object with status, headers, and body
local function parse_response(output)
local lines = vim.split(output, '\n')
local status = 200
local headers = {}
local body_start = 1
-- Find status line and headers
for i, line in ipairs(lines) do
if line:match('^HTTP/') then
status = tonumber(line:match('HTTP/[%d%.]+%s+(%d+)')) or 200
elseif line:match('^[%w%-]+:') then
local key, value = line:match('^([%w%-]+):%s*(.*)$')
if key and value then
headers[key:lower()] = value
end
elseif line == '' then
body_start = i + 1
break
end
end
local body_lines = {}
for i = body_start, #lines do
table.insert(body_lines, lines[i])
end
local body = table.concat(body_lines, '\n')
return {
status = status,
headers = headers,
body = body,
}
end
--- Make an HTTP request
--- @param opts table Request options
--- @return table|nil job Job object for streaming requests, nil for regular requests
function M.request(opts)
local args = build_curl_args(opts)
if opts.stream then
local buffer = ''
local job = vim.system(args, {
stdout = function(err, chunk)
if err then
if opts.on_error then
opts.on_error({ message = err })
end
return
end
if chunk then
buffer = buffer .. chunk
-- Extract complete lines
while buffer:find('\n') do
local line, rest = buffer:match('([^\n]*\n)(.*)')
if line then
opts.stream(nil, line)
buffer = rest
else
break
end
end
end
end,
stderr = function(err, data)
if err and opts.on_error then
opts.on_error({ message = err })
end
end,
}, opts.on_exit and function(result)
-- Flush any remaining buffer content
if buffer and buffer ~= '' then
opts.stream(nil, buffer)
end
opts.on_exit(result.code, result.signal)
end or nil)
return {
_job = job,
is_running = function()
return job and job.pid ~= nil
end,
shutdown = function()
if job and job.pid then
pcall(function()
job:kill('sigterm')
end)
end
end,
}
else
table.insert(args, 2, '-i')
vim.system(args, {
text = true,
}, function(result)
if result.code ~= 0 then
if opts.on_error then
opts.on_error({ message = result.stderr or 'curl failed' })
end
return
end
local response = parse_response(result.stdout or '')
if opts.callback then
opts.callback(response)
end
end)
end
end
return M