first commit
This commit is contained in:
160
lua/jasper/api.lua
Normal file
160
lua/jasper/api.lua
Normal file
@@ -0,0 +1,160 @@
|
||||
--- jasper/api.lua
|
||||
--- Low-level HTTP calls to the Jasper API, executed via curl.
|
||||
|
||||
local M = {}
|
||||
|
||||
local JASPER_URL = "https://jasper.4sigma.it"
|
||||
|
||||
--- Run a curl command and return the parsed JSON body + HTTP status code.
|
||||
--- @param args string[] full curl argument list (without the URL, which is last)
|
||||
--- @return table|nil decoded JSON body
|
||||
--- @return number HTTP status code (0 on curl error)
|
||||
--- @return string|nil error message
|
||||
local function curl(args)
|
||||
-- Append -w to get the HTTP status on a separate last line
|
||||
local full_args = vim.list_extend(vim.list_slice(args, 1), { "-s", "-w", "\n%{http_code}" })
|
||||
-- args already contains the URL; rebuild properly:
|
||||
-- Actually we receive the full arg list already. Add -w trick.
|
||||
table.insert(args, "-w")
|
||||
table.insert(args, "\n%{http_code}")
|
||||
|
||||
local result = vim.system(args, { text = true }):wait()
|
||||
if result.code ~= 0 then
|
||||
return nil, 0, "curl error (exit " .. result.code .. ")"
|
||||
end
|
||||
|
||||
-- Split body and status code
|
||||
local last_newline = result.stdout:match(".*\n()")
|
||||
local status_code = tonumber(result.stdout:sub(last_newline)) or 0
|
||||
local body = result.stdout:sub(1, last_newline - 2) -- strip trailing \n + status line
|
||||
|
||||
local ok, data = pcall(vim.fn.json_decode, body)
|
||||
if not ok then
|
||||
return nil, status_code, "JSON decode error"
|
||||
end
|
||||
return data, status_code, nil
|
||||
end
|
||||
|
||||
--- @param path string API path, e.g. "/api/v1/timer/"
|
||||
--- @param token string
|
||||
--- @return table|nil, number, string|nil
|
||||
local function get(path, token)
|
||||
return curl({
|
||||
"curl",
|
||||
"-H", "Authorization: Token " .. token,
|
||||
JASPER_URL .. path,
|
||||
})
|
||||
end
|
||||
|
||||
--- @param path string
|
||||
--- @param token string
|
||||
--- @param form table<string,any>|nil key/value pairs sent as form data
|
||||
--- @return table|nil, number, string|nil
|
||||
local function post(path, token, form)
|
||||
local args = {
|
||||
"curl", "-X", "POST",
|
||||
"-H", "Authorization: Token " .. token,
|
||||
}
|
||||
if form then
|
||||
for k, v in pairs(form) do
|
||||
table.insert(args, "--data-urlencode")
|
||||
table.insert(args, k .. "=" .. tostring(v))
|
||||
end
|
||||
end
|
||||
table.insert(args, JASPER_URL .. path)
|
||||
return curl(args)
|
||||
end
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Public API
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
--- Fetch all timers for the current user.
|
||||
--- @param token string
|
||||
--- @return table[]|nil list of timer objects
|
||||
--- @return string|nil error message
|
||||
function M.get_timers(token)
|
||||
local data, status, err = get("/api/v1/timer/", token)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
if status == 401 then
|
||||
return nil, "unauthorized"
|
||||
end
|
||||
if status ~= 200 then
|
||||
return nil, "unexpected HTTP status " .. status
|
||||
end
|
||||
local timers_dict = data.data and data.data.timers
|
||||
if type(timers_dict) ~= "table" then
|
||||
return nil, "unexpected response shape"
|
||||
end
|
||||
local timers = {}
|
||||
for _, v in pairs(timers_dict) do
|
||||
table.insert(timers, v)
|
||||
end
|
||||
return timers, nil
|
||||
end
|
||||
|
||||
--- Start (play) a timer.
|
||||
--- @param token string
|
||||
--- @param timer_id number
|
||||
--- @return boolean ok
|
||||
--- @return string|nil error
|
||||
function M.start_timer(token, timer_id)
|
||||
local data, status, err = post("/api/v1/timer/" .. timer_id .. "/play/", token)
|
||||
if err then
|
||||
return false, err
|
||||
end
|
||||
if status ~= 200 then
|
||||
return false, "HTTP " .. status
|
||||
end
|
||||
if data.error ~= nil and data.error ~= vim.NIL then
|
||||
return false, tostring(data.error)
|
||||
end
|
||||
return true, nil
|
||||
end
|
||||
|
||||
--- Pause a timer.
|
||||
--- @param token string
|
||||
--- @param timer_id number
|
||||
--- @return boolean ok
|
||||
--- @return string|nil error
|
||||
function M.stop_timer(token, timer_id)
|
||||
local data, status, err = post("/api/v1/timer/" .. timer_id .. "/pausa/", token)
|
||||
if err then
|
||||
return false, err
|
||||
end
|
||||
if status ~= 200 then
|
||||
return false, "HTTP " .. status
|
||||
end
|
||||
if data.error ~= nil and data.error ~= vim.NIL then
|
||||
return false, tostring(data.error)
|
||||
end
|
||||
return true, nil
|
||||
end
|
||||
|
||||
--- Associate an attivita with a (new) timer slot.
|
||||
--- @param token string
|
||||
--- @param timer_id number desired slot id (smallest free integer)
|
||||
--- @param attivita_id number
|
||||
--- @return boolean ok
|
||||
--- @return string|nil error
|
||||
function M.create_timer(token, timer_id, attivita_id)
|
||||
local data, status, err = post(
|
||||
"/api/v1/timer/" .. timer_id .. "/attivita/",
|
||||
token,
|
||||
{ attivita_id = attivita_id }
|
||||
)
|
||||
if err then
|
||||
return false, err
|
||||
end
|
||||
if status ~= 200 then
|
||||
return false, "HTTP " .. status
|
||||
end
|
||||
if data.error ~= nil and data.error ~= vim.NIL then
|
||||
return false, tostring(data.error)
|
||||
end
|
||||
return true, nil
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user