diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/luarocks/fun.tl | 6 | ||||
| -rw-r--r-- | src/luarocks/type_check.tl | 36 | ||||
| -rw-r--r-- | src/luarocks/upload/api.tl | 232 |
3 files changed, 138 insertions, 136 deletions
diff --git a/src/luarocks/fun.tl b/src/luarocks/fun.tl index 9d9551ed..16873dc2 100644 --- a/src/luarocks/fun.tl +++ b/src/luarocks/fun.tl | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | local record fun | 3 | local record fun |
| 4 | end | 4 | end |
| 5 | 5 | ||
| 6 | function fun.concat(xs: {any}, ys: {any}): {any} --? not generic becuse lua suports differnt types in one array | 6 | function fun.concat<K>(xs: {K}, ys: {K}): {K} |
| 7 | local rs = {} | 7 | local rs = {} |
| 8 | local n = #xs | 8 | local n = #xs |
| 9 | for i = 1, n do | 9 | for i = 1, n do |
| @@ -16,7 +16,7 @@ function fun.concat(xs: {any}, ys: {any}): {any} --? not generic becuse lua supo | |||
| 16 | return rs | 16 | return rs |
| 17 | end | 17 | end |
| 18 | 18 | ||
| 19 | function fun.contains(xs: {any}, v: any): boolean --? same logic as above fine? | 19 | function fun.contains<K>(xs: {K}, v: K): boolean --? same logic as above fine? |
| 20 | for _, x in ipairs(xs) do | 20 | for _, x in ipairs(xs) do |
| 21 | if v == x then | 21 | if v == x then |
| 22 | return true | 22 | return true |
| @@ -55,7 +55,7 @@ function fun.traverse<K, V>(t: {K}, f: function(K): V): {V} | V --? right or {an | |||
| 55 | end) | 55 | end) |
| 56 | end | 56 | end |
| 57 | 57 | ||
| 58 | function fun.reverse_in(t: {any}): {any} | 58 | function fun.reverse_in<K>(t: {K}): {K} |
| 59 | for i = 1, math.floor(#t/2) do | 59 | for i = 1, math.floor(#t/2) do |
| 60 | local m, n = i, #t - i + 1 | 60 | local m, n = i, #t - i + 1 |
| 61 | local a, b = t[m], t[n] | 61 | local a, b = t[m], t[n] |
diff --git a/src/luarocks/type_check.tl b/src/luarocks/type_check.tl index 09dfa96d..1252133d 100644 --- a/src/luarocks/type_check.tl +++ b/src/luarocks/type_check.tl | |||
| @@ -14,7 +14,7 @@ local vers = require("luarocks.core.vers") | |||
| 14 | type_check.MAGIC_PLATFORMS = 0xEBABEFAC | 14 | type_check.MAGIC_PLATFORMS = 0xEBABEFAC |
| 15 | 15 | ||
| 16 | do | 16 | do |
| 17 | local function fill_in_version(tbl, version?) | 17 | local function fill_in_version(tbl: {any: any}, version?: string) --! tighter bound? --? What is filled if no version is provided |
| 18 | for _, v in pairs(tbl) do | 18 | for _, v in pairs(tbl) do |
| 19 | if v is table then | 19 | if v is table then |
| 20 | if v._version == nil then | 20 | if v._version == nil then |
| @@ -25,9 +25,9 @@ do | |||
| 25 | end | 25 | end |
| 26 | end | 26 | end |
| 27 | 27 | ||
| 28 | local function expand_magic_platforms(tbl) | 28 | local function expand_magic_platforms(tbl: {any: any}) --! tbl type |
| 29 | for k,v in pairs(tbl) do | 29 | for k,v in pairs(tbl) do |
| 30 | if v == type_check.MAGIC_PLATFORMS then | 30 | if v == type_check.MAGIC_PLATFORMS then --! v is int, next line it is not |
| 31 | tbl[k] = { | 31 | tbl[k] = { |
| 32 | _any = util.deep_copy(tbl) | 32 | _any = util.deep_copy(tbl) |
| 33 | } | 33 | } |
| @@ -43,9 +43,9 @@ do | |||
| 43 | -- and the value is a schema specification. Schema versions are considered | 43 | -- and the value is a schema specification. Schema versions are considered |
| 44 | -- incremental: version "2.0" only needs to specify what's new/changed from | 44 | -- incremental: version "2.0" only needs to specify what's new/changed from |
| 45 | -- version "1.0". | 45 | -- version "1.0". |
| 46 | function type_check.declare_schemas(inputs: {string: any}): {any: any}, {any} --? | 46 | function type_check.declare_schemas(inputs: {string: {any: any}}): {string : {any : any}}, {string} --! schema type: {string: {any: any}} |
| 47 | local schemas = {} | 47 | local schemas: {string: {any: any}} = {} |
| 48 | local parent_version | 48 | local parent_version: string |
| 49 | 49 | ||
| 50 | local versions = fun.reverse_in(fun.sort_in(util.keys(inputs), vers.compare_versions)) | 50 | local versions = fun.reverse_in(fun.sort_in(util.keys(inputs), vers.compare_versions)) |
| 51 | 51 | ||
| @@ -68,7 +68,7 @@ end | |||
| 68 | 68 | ||
| 69 | -------------------------------------------------------------------------------- | 69 | -------------------------------------------------------------------------------- |
| 70 | 70 | ||
| 71 | local function check_version(version: string, typetbl, context: string) | 71 | local function check_version(version: string, typetbl: {string: string}, context: string): boolean, string --! typetbl |
| 72 | local typetbl_version = typetbl._version or "1.0" | 72 | local typetbl_version = typetbl._version or "1.0" |
| 73 | if vers.compare_versions(typetbl_version, version) then | 73 | if vers.compare_versions(typetbl_version, version) then |
| 74 | if context == "" then | 74 | if context == "" then |
| @@ -80,6 +80,8 @@ local function check_version(version: string, typetbl, context: string) | |||
| 80 | return true | 80 | return true |
| 81 | end | 81 | end |
| 82 | 82 | ||
| 83 | |||
| 84 | |||
| 83 | --- Type check an object. | 85 | --- Type check an object. |
| 84 | -- The object is compared against an archetypical value | 86 | -- The object is compared against an archetypical value |
| 85 | -- matching the expected type -- the actual values don't matter, | 87 | -- matching the expected type -- the actual values don't matter, |
| @@ -92,8 +94,7 @@ end | |||
| 92 | -- @return boolean or (nil, string): true if type checking | 94 | -- @return boolean or (nil, string): true if type checking |
| 93 | -- succeeded, or nil and an error message if it failed. | 95 | -- succeeded, or nil and an error message if it failed. |
| 94 | -- @see type_check_table | 96 | -- @see type_check_table |
| 95 | local function type_check_item(version, item, typetbl, context) | 97 | local function type_check_item(version: string, item: any, typetbl: {string: string}, context: string): boolean, string --! typetbl |
| 96 | assert(type(version) == "string") | ||
| 97 | 98 | ||
| 98 | if typetbl._version and typetbl._version ~= "1.0" then | 99 | if typetbl._version and typetbl._version ~= "1.0" then |
| 99 | local ok, err = check_version(version, typetbl, context) | 100 | local ok, err = check_version(version, typetbl, context) |
| @@ -115,9 +116,9 @@ local function type_check_item(version, item, typetbl, context) | |||
| 115 | end | 116 | end |
| 116 | local pattern = typetbl._pattern | 117 | local pattern = typetbl._pattern |
| 117 | if pattern then | 118 | if pattern then |
| 118 | if not item:match("^"..pattern.."$") then | 119 | if not item:match("^"..pattern.."$") then --! cast or tostring |
| 119 | local what = typetbl._name or ("'"..pattern.."'") | 120 | local what = typetbl._name or ("'"..pattern.."'") |
| 120 | return nil, "Type mismatch on field "..context..": invalid value '"..item.."' does not match " .. what | 121 | return nil, "Type mismatch on field "..context..": invalid value '"..item.."' does not match " .. what --! cast or tostring |
| 121 | end | 122 | end |
| 122 | end | 123 | end |
| 123 | elseif expected_type == "table" then | 124 | elseif expected_type == "table" then |
| @@ -132,10 +133,10 @@ local function type_check_item(version, item, typetbl, context) | |||
| 132 | return true | 133 | return true |
| 133 | end | 134 | end |
| 134 | 135 | ||
| 135 | local function mkfield(context, field) | 136 | local function mkfield(context: string, field: any): string |
| 136 | if context == "" then | 137 | if context == "" then |
| 137 | return tostring(field) | 138 | return tostring(field) |
| 138 | elseif type(field) == "string" then | 139 | elseif field is string then |
| 139 | return context.."."..field | 140 | return context.."."..field |
| 140 | else | 141 | else |
| 141 | return context.."["..tostring(field).."]" | 142 | return context.."["..tostring(field).."]" |
| @@ -164,10 +165,7 @@ end | |||
| 164 | -- to be used by error messages. | 165 | -- to be used by error messages. |
| 165 | -- @return boolean or (nil, string): true if type checking | 166 | -- @return boolean or (nil, string): true if type checking |
| 166 | -- succeeded, or nil and an error message if it failed. | 167 | -- succeeded, or nil and an error message if it failed. |
| 167 | function type_check.type_check_table(version, tbl, typetbl, context) | 168 | function type_check.type_check_table(version: string, tbl: {any: any}, typetbl: {string: string}, context: string): boolean, string --! tbl and typetbl types |
| 168 | assert(type(version) == "string") | ||
| 169 | assert(type(tbl) == "table") | ||
| 170 | assert(type(typetbl) == "table") | ||
| 171 | 169 | ||
| 172 | local ok, err = check_version(version, typetbl, context) | 170 | local ok, err = check_version(version, typetbl, context) |
| 173 | if not ok then | 171 | if not ok then |
| @@ -188,7 +186,7 @@ function type_check.type_check_table(version, tbl, typetbl, context) | |||
| 188 | end | 186 | end |
| 189 | end | 187 | end |
| 190 | for k, v in pairs(typetbl) do | 188 | for k, v in pairs(typetbl) do |
| 191 | if k:sub(1,1) ~= "_" and v._mandatory then | 189 | if k:sub(1,1) ~= "_" and v._mandatory then --! |
| 192 | if not tbl[k] then | 190 | if not tbl[k] then |
| 193 | return nil, "Mandatory field "..mkfield(context, k).." is missing." | 191 | return nil, "Mandatory field "..mkfield(context, k).." is missing." |
| 194 | end | 192 | end |
| @@ -197,7 +195,7 @@ function type_check.type_check_table(version, tbl, typetbl, context) | |||
| 197 | return true | 195 | return true |
| 198 | end | 196 | end |
| 199 | 197 | ||
| 200 | function type_check.check_undeclared_globals(globals, typetbl) | 198 | function type_check.check_undeclared_globals(globals: {string: any}, typetbl: {string: string}): boolean, string --! tbl and typetbl types |
| 201 | local undeclared = {} | 199 | local undeclared = {} |
| 202 | for glob, _ in pairs(globals) do | 200 | for glob, _ in pairs(globals) do |
| 203 | if not (typetbl[glob] or typetbl["MUST_"..glob]) then | 201 | if not (typetbl[glob] or typetbl["MUST_"..glob]) then |
diff --git a/src/luarocks/upload/api.tl b/src/luarocks/upload/api.tl index fd837fd8..0c94a6ee 100644 --- a/src/luarocks/upload/api.tl +++ b/src/luarocks/upload/api.tl | |||
| @@ -15,9 +15,13 @@ local record Api | |||
| 15 | raw_method: function(Api, string) | 15 | raw_method: function(Api, string) |
| 16 | record config | 16 | record config |
| 17 | server: any --! why to string | 17 | server: any --! why to string |
| 18 | key: string | ||
| 18 | end | 19 | end |
| 20 | debug: boolean | ||
| 19 | end | 21 | end |
| 20 | 22 | ||
| 23 | local type Parameters = multipart.Parameters | ||
| 24 | |||
| 21 | local function upload_config_file(): string | 25 | local function upload_config_file(): string |
| 22 | if not cfg.config_files.user.file then | 26 | if not cfg.config_files.user.file then |
| 23 | return nil | 27 | return nil |
| @@ -32,7 +36,7 @@ function Api:load_config(): {any: any} --? tighter bound? | |||
| 32 | return config | 36 | return config |
| 33 | end | 37 | end |
| 34 | 38 | ||
| 35 | function Api:save_config() | 39 | function Api:save_config(): nil, string --! nil? |
| 36 | -- Test configuration before saving it. | 40 | -- Test configuration before saving it. |
| 37 | local res, err = self:raw_method("status") | 41 | local res, err = self:raw_method("status") |
| 38 | if not res then | 42 | if not res then |
| @@ -90,25 +94,25 @@ function Api:method(...) | |||
| 90 | return res | 94 | return res |
| 91 | end | 95 | end |
| 92 | 96 | ||
| 93 | function Api.raw_method(self: Api, path: string, ...) --! path, ... type | 97 | function Api:raw_method(path: string, ...) --! path, ... type |
| 94 | self:check_version() | 98 | self:check_version() |
| 95 | local url = tostring(self.config.server) .. "/api/" .. tostring(cfg.upload.api_version) .. "/" .. tostring(self.config.key) .. "/" .. path | 99 | local url = tostring(self.config.server) .. "/api/" .. tostring(cfg.upload.api_version) .. "/" .. tostring(self.config.key) .. "/" .. path |
| 96 | return self:request(url, ...) | 100 | return self:request(url, ...) |
| 97 | end | 101 | end |
| 98 | 102 | ||
| 99 | local function encode_query_string(t, sep) | 103 | local function encode_query_string(t: Parameters, sep?: string): string |
| 100 | if sep == nil then | 104 | if sep == nil then |
| 101 | sep = "&" | 105 | sep = "&" |
| 102 | end | 106 | end |
| 103 | local i = 0 | 107 | local i = 0 |
| 104 | local buf = { } | 108 | local buf: {string} = { } |
| 105 | for k, v in pairs(t) do | 109 | for k, v in pairs(t.map) do --! pairs problem for Parameters |
| 106 | if type(k) == "number" and type(v) == "table" then | 110 | if k is number and v is {string} then |
| 107 | k, v = v[1], v[2] | 111 | k, v = v[1], v[2] |
| 108 | end | 112 | end |
| 109 | buf[i + 1] = multipart.url_escape(k) | 113 | buf[i + 1] = multipart.url_escape(k as string) --! cast |
| 110 | buf[i + 2] = "=" | 114 | buf[i + 2] = "=" |
| 111 | buf[i + 3] = multipart.url_escape(v) | 115 | buf[i + 3] = multipart.url_escape(v as string) --! cast |
| 112 | buf[i + 4] = sep | 116 | buf[i + 4] = sep |
| 113 | i = i + 4 | 117 | i = i + 4 |
| 114 | end | 118 | end |
| @@ -116,140 +120,140 @@ local function encode_query_string(t, sep) | |||
| 116 | return table.concat(buf) | 120 | return table.concat(buf) |
| 117 | end | 121 | end |
| 118 | 122 | ||
| 119 | local function redact_api_url(url) | 123 | local function redact_api_url(url: any): string |
| 120 | url = tostring(url) | 124 | url = tostring(url) |
| 121 | return (url:gsub(".*/api/[^/]+/[^/]+", "")) or "" | 125 | return ((url as string):gsub(".*/api/[^/]+/[^/]+", "")) or "" --! cast |
| 122 | end | 126 | end |
| 123 | 127 | ||
| 124 | local ltn12_ok, ltn12 = pcall(require, "ltn12") | 128 | local ltn12_ok, ltn12 = pcall(require, "ltn12") |
| 125 | if not ltn12_ok then -- If not using LuaSocket and/or LuaSec... | 129 | if not ltn12_ok then -- If not using LuaSocket and/or LuaSec... |
| 126 | 130 | ||
| 127 | function Api.request(self: Api, url: string, params?, post_params?): {string : any}, string | 131 | function Api:request(url: string, params?: Parameters, post_params?: Parameters): {string : any}, string |
| 128 | local vars = cfg.variables | 132 | local vars = cfg.variables |
| 129 | |||
| 130 | if fs.which_tool("downloader") == "wget" then | ||
| 131 | local curl_ok, err = fs.is_tool_available(vars.CURL, "curl") | ||
| 132 | if not curl_ok then | ||
| 133 | return nil, err | ||
| 134 | end | ||
| 135 | end | ||
| 136 | 133 | ||
| 137 | if not self.config.key then | 134 | if fs.which_tool("downloader") == "wget" then |
| 138 | return nil, "Must have API key before performing any actions." | 135 | local curl_ok, err = fs.is_tool_available(vars.CURL, "curl") |
| 139 | end | 136 | if not curl_ok then |
| 140 | if params and next(params) then | 137 | return nil, err |
| 141 | url = url .. ("?" .. encode_query_string(params)) | ||
| 142 | end | ||
| 143 | local method = "GET" | ||
| 144 | local out | ||
| 145 | local tmpfile = fs.tmpname() | ||
| 146 | if post_params then | ||
| 147 | method = "POST" | ||
| 148 | local curl_cmd = vars.CURL.." "..vars.CURLNOCERTFLAG.." -f -L --silent --user-agent \""..cfg.user_agent.." via curl\" " | ||
| 149 | for k,v in pairs(post_params) do | ||
| 150 | local var = v | ||
| 151 | if type(v) == "table" then | ||
| 152 | var = "@"..v.fname | ||
| 153 | end | 138 | end |
| 154 | curl_cmd = curl_cmd .. "--form \""..k.."="..var.."\" " | ||
| 155 | end | 139 | end |
| 156 | if cfg.connection_timeout and cfg.connection_timeout > 0 then | 140 | |
| 157 | curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." " | 141 | if not self.config.key then |
| 142 | return nil, "Must have API key before performing any actions." | ||
| 158 | end | 143 | end |
| 159 | local ok = fs.execute_string(curl_cmd..fs.Q(url).." -o "..fs.Q(tmpfile)) | 144 | if params and next(params) then --! |
| 160 | if not ok then | 145 | url = url .. ("?" .. encode_query_string(params)) |
| 161 | return nil, "API failure: " .. redact_api_url(url) | ||
| 162 | end | 146 | end |
| 163 | else | 147 | local method = "GET" |
| 164 | local ok, err = fs.download(url, tmpfile) | 148 | local out: string |
| 165 | if not ok then | 149 | local tmpfile = fs.tmpname() |
| 166 | return nil, "API failure: " .. tostring(err) .. " - " .. redact_api_url(url) | 150 | if post_params then |
| 151 | method = "POST" | ||
| 152 | local curl_cmd = vars.CURL.." "..vars.CURLNOCERTFLAG.." -f -L --silent --user-agent \""..cfg.user_agent.." via curl\" " | ||
| 153 | for k,v in pairs(post_params) do | ||
| 154 | local var = v | ||
| 155 | if v is {string: string} then | ||
| 156 | var = "@"..v.fname | ||
| 157 | end | ||
| 158 | curl_cmd = curl_cmd .. "--form \""..k.."="..var as string.."\" " --! cast | ||
| 159 | end | ||
| 160 | if cfg.connection_timeout and cfg.connection_timeout > 0 then | ||
| 161 | curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." " | ||
| 162 | end | ||
| 163 | local ok = fs.execute_string(curl_cmd..fs.Q(url).." -o "..fs.Q(tmpfile)) | ||
| 164 | if not ok then | ||
| 165 | return nil, "API failure: " .. redact_api_url(url) | ||
| 166 | end | ||
| 167 | else | ||
| 168 | local ok, err = fs.download(url, tmpfile) | ||
| 169 | if not ok then | ||
| 170 | return nil, "API failure: " .. tostring(err) .. " - " .. redact_api_url(url) | ||
| 171 | end | ||
| 167 | end | 172 | end |
| 168 | end | ||
| 169 | 173 | ||
| 170 | local tmpfd = io.open(tmpfile) | 174 | local tmpfd = io.open(tmpfile) |
| 171 | if not tmpfd then | 175 | if not tmpfd then |
| 176 | os.remove(tmpfile) | ||
| 177 | return nil, "API failure reading temporary file - " .. redact_api_url(url) | ||
| 178 | end | ||
| 179 | out = tmpfd:read("*a") | ||
| 180 | tmpfd:close() | ||
| 172 | os.remove(tmpfile) | 181 | os.remove(tmpfile) |
| 173 | return nil, "API failure reading temporary file - " .. redact_api_url(url) | ||
| 174 | end | ||
| 175 | out = tmpfd:read("*a") | ||
| 176 | tmpfd:close() | ||
| 177 | os.remove(tmpfile) | ||
| 178 | 182 | ||
| 179 | if self.debug then | 183 | if self.debug then |
| 180 | util.printout("[" .. tostring(method) .. " via curl] " .. redact_api_url(url) .. " ... ") | 184 | util.printout("[" .. tostring(method) .. " via curl] " .. redact_api_url(url) .. " ... ") |
| 181 | end | 185 | end |
| 182 | 186 | ||
| 183 | return json.decode(out) | 187 | return json.decode(out) |
| 184 | end | 188 | end |
| 185 | 189 | ||
| 186 | else -- use LuaSocket and LuaSec | 190 | else -- use LuaSocket and LuaSec |
| 187 | 191 | ||
| 188 | local warned_luasec = false | 192 | local warned_luasec = false |
| 189 | 193 | ||
| 190 | function Api:request(url, params, post_params) | 194 | function Api:request(url: string, params?: Parameters, post_params?: Parameters): {string : any}, string |
| 191 | local server = tostring(self.config.server) | 195 | local server = tostring(self.config.server) |
| 192 | local http_ok, http | 196 | local http_ok, http: boolean, any |
| 193 | local via = "luasocket" | 197 | local via = "luasocket" |
| 194 | if server:match("^https://") then | 198 | if server:match("^https://") then |
| 195 | http_ok, http = pcall(require, "ssl.https") | 199 | http_ok, http = pcall(require, "ssl.https") --! a lot of new files in the src dir |
| 196 | if http_ok then | 200 | if http_ok then |
| 197 | via = "luasec" | 201 | via = "luasec" |
| 198 | else | 202 | else |
| 199 | if not warned_luasec then | 203 | if not warned_luasec then |
| 200 | util.printerr("LuaSec is not available; using plain HTTP. Install 'luasec' to enable HTTPS.") | 204 | util.printerr("LuaSec is not available; using plain HTTP. Install 'luasec' to enable HTTPS.") |
| 201 | warned_luasec = true | 205 | warned_luasec = true |
| 206 | end | ||
| 207 | http_ok, http = pcall(require, "socket.http") | ||
| 208 | url = url:gsub("^https", "http") | ||
| 209 | via = "luasocket" | ||
| 202 | end | 210 | end |
| 211 | else | ||
| 203 | http_ok, http = pcall(require, "socket.http") | 212 | http_ok, http = pcall(require, "socket.http") |
| 204 | url = url:gsub("^https", "http") | ||
| 205 | via = "luasocket" | ||
| 206 | end | 213 | end |
| 207 | else | 214 | if not http_ok then |
| 208 | http_ok, http = pcall(require, "socket.http") | 215 | return nil, "Failed loading socket library!" |
| 209 | end | 216 | end |
| 210 | if not http_ok then | ||
| 211 | return nil, "Failed loading socket library!" | ||
| 212 | end | ||
| 213 | 217 | ||
| 214 | if not self.config.key then | 218 | if not self.config.key then |
| 215 | return nil, "Must have API key before performing any actions." | 219 | return nil, "Must have API key before performing any actions." |
| 216 | end | 220 | end |
| 217 | local body | 221 | local body: string |
| 218 | local headers = {} | 222 | local headers: {string: string | integer} = {} |
| 219 | if params and next(params) then | 223 | if params and next(params) then --! |
| 220 | url = url .. ("?" .. encode_query_string(params)) | 224 | url = url .. ("?" .. encode_query_string(params)) |
| 221 | end | 225 | end |
| 222 | if post_params then | 226 | if post_params then |
| 223 | local boundary | 227 | local boundary: string |
| 224 | body, boundary = multipart.encode(post_params) | 228 | body, boundary = multipart.encode(post_params) |
| 225 | headers["Content-length"] = #body | 229 | headers["Content-length"] = #body |
| 226 | headers["Content-type"] = "multipart/form-data; boundary=" .. tostring(boundary) | 230 | headers["Content-type"] = "multipart/form-data; boundary=" .. tostring(boundary) |
| 227 | end | 231 | end |
| 228 | local method = post_params and "POST" or "GET" | 232 | local method = post_params and "POST" or "GET" |
| 229 | if self.debug then | 233 | if self.debug then |
| 230 | util.printout("[" .. tostring(method) .. " via "..via.."] " .. redact_api_url(url) .. " ... ") | 234 | util.printout("[" .. tostring(method) .. " via "..via.."] " .. redact_api_url(url) .. " ... ") |
| 231 | end | 235 | end |
| 232 | local out = {} | 236 | local out = {} |
| 233 | local _, status = http.request({ | 237 | local _, status = http.request({ |
| 234 | url = url, | 238 | url = url, |
| 235 | headers = headers, | 239 | headers = headers, |
| 236 | method = method, | 240 | method = method, |
| 237 | sink = ltn12.sink.table(out), | 241 | sink = ltn12.sink.table(out), |
| 238 | source = body and ltn12.source.string(body) | 242 | source = body and ltn12.source.string(body) |
| 239 | }) | 243 | }) |
| 240 | if self.debug then | 244 | if self.debug then |
| 241 | util.printout(tostring(status)) | 245 | util.printout(tostring(status)) |
| 242 | end | 246 | end |
| 243 | local pok, ret, err = pcall(json.decode, table.concat(out)) | 247 | local pok, ret, err = pcall(json.decode, table.concat(out)) |
| 244 | if pok and ret then | 248 | if pok and ret then |
| 245 | return ret | 249 | return ret |
| 250 | end | ||
| 251 | return nil, "API returned " .. tostring(status) .. " - " .. redact_api_url(url) | ||
| 246 | end | 252 | end |
| 247 | return nil, "API returned " .. tostring(status) .. " - " .. redact_api_url(url) | ||
| 248 | end | ||
| 249 | 253 | ||
| 250 | end | 254 | end |
| 251 | 255 | ||
| 252 | function api.new(args) | 256 | function api.new(args): Api |
| 253 | local self = {} | 257 | local self = {} |
| 254 | setmetatable(self, { __index = Api }) | 258 | setmetatable(self, { __index = Api }) |
| 255 | self.config = self:load_config() or {} | 259 | self.config = self:load_config() or {} |
