Last active
August 2, 2022 23:53
-
-
Save MCJack123/9561f3391c85d520d4b64c175ca750d0 to your computer and use it in GitHub Desktop.
Fetch work-alike for CC, implementing async HTTP requests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Made by JackMacWindows, licensed under CC0 | |
local expect = require "cc.expect".expect | |
local activeRequests = {} | |
local kPromiseSuccess, kPromiseFailure = {}, {} | |
local openHandlers = 0 | |
-- To use, call this function with each URL and optionally a table with options. | |
-- Then call it with no arguments to process the requests in the queue. | |
-- The function returns once the request queue is depleted. | |
return function(resource, init) | |
if resource == nil then | |
while next(activeRequests) do | |
for k,v in pairs(activeRequests) do | |
if not v.sent and openHandlers < 16 then | |
http.request(v.options) | |
openHandlers = openHandlers + 1 | |
v.sent = true | |
end | |
end | |
local ev, url, res, errh = os.pullEvent() | |
if (ev == "http_success" or (ev == "http_failure" and errh)) and activeRequests[url] then | |
openHandlers = openHandlers - 1 | |
if ev == "http_failure" then | |
res = errh | |
res.ok = false | |
else res.ok = true end | |
local req = activeRequests[url] | |
activeRequests[url] = nil | |
if req.resolve == 0 then res.close() else | |
res.array = function() | |
local retval = {} | |
local c, n = res.read(1), 1 | |
while c ~= nil do | |
retval[n] = c:byte() | |
c, n = res.read(1), n + 1 | |
end | |
res.close() | |
return kPromiseSuccess, retval | |
end | |
res.formData = function() | |
return kPromiseFailure, "Not implemented" | |
end | |
res.json = function() | |
local text = res.readAll() | |
res.close() | |
if textutils.unserializeJSON == nil then return kPromiseFailure, "Unserializing JSON requires CC:T 1.87+" end | |
local json, err = textutils.unserializeJSON(text) | |
if json then return kPromiseSuccess, json | |
else return kPromiseFailure, err end | |
end | |
res.text = function() | |
local text = res.readAll() | |
res.close() | |
return kPromiseSuccess, text | |
end | |
local i = 1 | |
local data, key = res | |
repeat | |
key, data = req.resolve[i](data) | |
if key == kPromiseFailure then req.reject(data) end | |
i=i+1 | |
until key ~= kPromiseSuccess or not req.resolve[i] | |
end | |
if req.finish then req.finish() end | |
elseif ev == "http_failure" and activeRequests[url] then | |
openHandlers = openHandlers - 1 | |
local req = activeRequests[url] | |
activeRequests[url] = nil | |
if req.reject then req.reject(res) end | |
end | |
end | |
else | |
expect(1, resource, "string") | |
expect(2, init, "table", "nil") | |
if not init then init = {} end | |
init.url = resource | |
local req = {options = init, resolve = {}} | |
activeRequests[resource] = req | |
local promise | |
promise = { | |
Then = function(fn) | |
req.resolve[#req.resolve+1] = fn | |
return promise | |
end, | |
catch = function(fn) | |
req.reject = fn | |
return promise | |
end, | |
finally = function(fn) | |
req.finish = fn | |
return promise | |
end | |
} | |
promise["then"] = promise.Then -- for compatibility, but you'll have to do ["then"] | |
return promise | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment