forked from sudo-tee/opencode.nvim
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver_job.lua
More file actions
159 lines (140 loc) · 4.59 KB
/
server_job.lua
File metadata and controls
159 lines (140 loc) · 4.59 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
155
156
157
158
159
local state = require('opencode.state')
local curl = require('opencode.curl')
local Promise = require('opencode.promise')
local opencode_server = require('opencode.opencode_server')
local M = {}
M.requests = {}
--- @param response {status: integer, body: string}
--- @param cb fun(err: any, result: any)
local function handle_api_response(response, cb)
local success, json_body = pcall(vim.json.decode, response.body)
if response.status >= 200 and response.status < 300 then
cb(nil, success and json_body or response.body)
else
cb(success and json_body or response.body, nil)
end
end
--- Make an HTTP API call to the opencode server.
--- @generic T
--- @param url string The API endpoint URL
--- @param method string|nil HTTP method (default: 'GET')
--- @param body table|nil|boolean Request body (will be JSON encoded)
--- @return Promise<T> promise A promise that resolves with the result or rejects with an error
function M.call_api(url, method, body)
local call_promise = Promise.new()
state.job_count = state.job_count + 1
local request_entry = { nil, call_promise }
table.insert(M.requests, request_entry)
-- Remove completed promises from list, update job_count
local function remove_from_requests()
for i, entry in ipairs(M.requests) do
if entry == request_entry then
table.remove(M.requests, i)
break
end
end
state.job_count = #M.requests
end
local opts = {
url = url,
method = method or 'GET',
headers = { ['Content-Type'] = 'application/json' },
proxy = '',
callback = function(response)
remove_from_requests()
handle_api_response(response, function(err, result)
if err then
local ok, pcall_err = pcall(function()
call_promise:reject(err)
end)
if not ok then
vim.schedule(function()
vim.notify('Error while handling API error response: ' .. vim.inspect(pcall_err))
end)
end
else
local ok, pcall_err = pcall(function()
call_promise:resolve(result)
end)
if not ok then
vim.schedule(function()
vim.notify('Error while handling API response: ' .. vim.inspect(pcall_err))
end)
end
end
end)
end,
on_error = function(err)
remove_from_requests()
local ok, pcall_err = pcall(function()
call_promise:reject(err)
end)
if not ok then
vim.schedule(function()
vim.notify('Error while handling API on_error: ' .. vim.inspect(pcall_err))
end)
end
end,
}
if body ~= nil then
opts.body = body and vim.json.encode(body) or '{}'
end
-- add opts to request_entry for request tracking
request_entry[1] = opts
curl.request(opts)
return call_promise
end
--- Make a streaming HTTP API call to the opencode server.
--- @param url string The API endpoint URL
--- @param method string|nil HTTP method (default: 'GET')
--- @param body table|nil|boolean Request body (will be JSON encoded)
--- @param on_chunk fun(chunk: string) Callback invoked for each chunk of data received
--- @return table The underlying job instance
function M.stream_api(url, method, body, on_chunk)
local opts = {
url = url,
method = method or 'GET',
proxy = '',
stream = function(err, chunk)
on_chunk(chunk)
end,
on_error = function(err)
--This means the job was killed, so we can ignore it
if err.message:match('exit_code=nil') then
return
end
vim.notify('Error in streaming request: ' .. vim.inspect(err), vim.log.levels.ERROR)
end,
on_exit = function(code, signal)
if code ~= 0 then
vim.notify('Streaming request exited with code ' .. tostring(code), vim.log.levels.WARN)
end
end,
}
if body ~= nil then
opts.body = body and vim.json.encode(body) or '{}'
end
return curl.request(opts) --[[@as table]]
end
--- Ensure the opencode server is running, starting it if necessary.
--- @return Promise<OpencodeServer> promise A promise that resolves with the server instance
function M.ensure_server()
local promise = Promise.new()
if state.opencode_server and state.opencode_server:is_running() then
return promise:resolve(state.opencode_server)
end
state.opencode_server = opencode_server.new()
state.opencode_server:spawn({
on_ready = function(_, base_url)
promise:resolve(state.opencode_server)
end,
on_error = function(err)
promise:reject(err)
end,
on_exit = function(exit_opts)
promise:reject('Server exited')
end,
})
return promise
end
return M