Skip to content

Instantly share code, notes, and snippets.

@MCJack123
Last active August 2, 2022 23:53
Show Gist options
  • Save MCJack123/9561f3391c85d520d4b64c175ca750d0 to your computer and use it in GitHub Desktop.
Save MCJack123/9561f3391c85d520d4b64c175ca750d0 to your computer and use it in GitHub Desktop.
Fetch work-alike for CC, implementing async HTTP requests
-- 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