mirror of
https://github.com/CFC-Servers/cfc_network_promises.git
synced 2025-03-04 03:03:19 -05:00
Added xdcall, net.http.request, improved promise errors
This commit is contained in:
parent
7f2c437c68
commit
784270082e
@ -7,3 +7,4 @@ NP = networkPromise -- shorthand name, networkPromise will get a bit cumbersome
|
||||
include( "network_promises/http.lua" )
|
||||
include( "network_promises/net.lua" )
|
||||
include( "network_promises/async.lua" )
|
||||
include( "network_promises/xdcall.lua" )
|
@ -1,6 +1,7 @@
|
||||
NP.http = {}
|
||||
|
||||
-- Returns a promise that resolves after t seconds
|
||||
-- fail : Should the promise reject after timeout
|
||||
function NP.timeout( t, fail )
|
||||
method = fail and "reject" or "resolve"
|
||||
local d = promise.new()
|
||||
@ -10,20 +11,24 @@ function NP.timeout( t, fail )
|
||||
return d
|
||||
end
|
||||
|
||||
local function responseSuccess( d, body, status, headers )
|
||||
-- Check body is valid Json, if not, reject
|
||||
local data = util.JSONToTable( body )
|
||||
local method = "reject"
|
||||
if math.floor( status / 100 ) == 2 and data then
|
||||
method = "resolve"
|
||||
end
|
||||
d[method]( d, data or "Invalid json response", status, headers )
|
||||
end
|
||||
|
||||
-- http.post as a promise, resolves whenever http finishes, or never if it doesn't (Looking at you, ISteamHTTP)
|
||||
-- url : post url
|
||||
-- data : post args as table
|
||||
-- resolves to function( statusCode, data, headers )
|
||||
-- resolves to function( data, statusCode, headers )
|
||||
function NP.http.postIndef( url, data )
|
||||
local d = promise.new() -- promise itself
|
||||
http.Post( url, data, function( body, len, headers, status )
|
||||
-- Check body is valid Json, if not, reject
|
||||
local data = util.JSONToTable( body )
|
||||
local method = "reject"
|
||||
if math.floor(status / 100) == 2 and data then
|
||||
method = "resolve"
|
||||
end
|
||||
d[method]( d, data or "Invalid json response", status, headers )
|
||||
responseSuccess( d, body, status, headers )
|
||||
end, function( err )
|
||||
d:reject( err, -1 )
|
||||
end )
|
||||
@ -34,25 +39,45 @@ end
|
||||
function NP.http.fetchIndef( url )
|
||||
local d = promise.new()
|
||||
http.Fetch( url, function( body, len, headers, status )
|
||||
-- Check body is valid Json, if not, reject
|
||||
local data = util.JSONToTable( body )
|
||||
local method = "reject"
|
||||
if math.floor(status / 100) == 2 then
|
||||
method = "resolve"
|
||||
end
|
||||
d[method]( d, data or "Invalid json response", status, headers )
|
||||
responseSuccess( d, body, status, headers )
|
||||
end, function( err )
|
||||
d:reject( err, -1 )
|
||||
end )
|
||||
return d
|
||||
end
|
||||
|
||||
-- HTTP as a promise, resolves whenever http finishes, or never if it doesn't (Looking at you, ISteamHTTP)
|
||||
-- method : GET, PUT, etc.
|
||||
-- endPoint : Appended to settings.apiRoot
|
||||
-- params : params for GET, POST, HEAD
|
||||
-- settings : { apiRoot = "myRoot", apiKey = "myKey", timeout = 5 } - timeout only functional in NP.http.request
|
||||
-- resolves to function( data, statusCode, headers )
|
||||
function NP.http.requestIndef( method, endPoint, params, settings )
|
||||
method = method or "GET"
|
||||
local d = promise.new()
|
||||
local url = settings.apiRoot .. endPoint
|
||||
|
||||
local struct = HTTPRequest({
|
||||
failed = function( err )
|
||||
d:reject( err, -1 )
|
||||
end,
|
||||
success = function( status, body, headers )
|
||||
responseSuccess( d, body, status, headers )
|
||||
end,
|
||||
method = method,
|
||||
url = url,
|
||||
parameters = params,
|
||||
type = "application/json",
|
||||
Token = settings.apiKey
|
||||
})
|
||||
end
|
||||
|
||||
-- Post but with enforced timeout
|
||||
-- This promise is guaranteed to resolve/reject eventually
|
||||
-- url : post url
|
||||
-- data : post args as table
|
||||
-- timeout : optional timeout in seconds (def 5)
|
||||
-- resolves to function( statusCode, data, headers )
|
||||
-- resolves to function( data, statusCode, headers )
|
||||
function NP.http.post( url, data, timeout )
|
||||
timeout = timeout or 5
|
||||
return promise.first{
|
||||
@ -69,3 +94,12 @@ function NP.http.fetch( url, timeout )
|
||||
NP.timeout( timeout, true )
|
||||
}
|
||||
end
|
||||
|
||||
-- Same as above but for request
|
||||
function NP.http.request( method, endPoint, params, settings )
|
||||
local timeout = settings.timeout or 5
|
||||
return promise.first{
|
||||
NP.http.fetchIndef( url ),
|
||||
NP.timeout( timeout, true )
|
||||
}
|
||||
end
|
@ -25,7 +25,10 @@ local function finish(deferred, state)
|
||||
end
|
||||
end
|
||||
if state == REJECTED and #deferred.queue == 0 then
|
||||
error("Uncaught rejection or exception in promise:\n" .. table.concat(deferred.value, "\t"))
|
||||
timer.Simple(0, function()
|
||||
error("Uncaught rejection or exception in promise:\n" .. table.concat(deferred.value, "\n") .. "IGNORE FOLLOWING 4 LINES")
|
||||
end )
|
||||
|
||||
end
|
||||
deferred.state = state
|
||||
end
|
||||
@ -41,7 +44,7 @@ end
|
||||
local function promise(deferred, next, success, failure, nonpromisecb)
|
||||
if type(deferred) == 'table' and type(deferred.value[1]) == 'table' and isfunction(next) then
|
||||
local called = false
|
||||
local ok, err = pcall(next, deferred.value[1], function( ... )
|
||||
local ok, err, stack = xdcall(next, deferred.value[1], function( ... )
|
||||
if called then return end
|
||||
called = true
|
||||
deferred.value = { ... }
|
||||
@ -53,7 +56,7 @@ local function promise(deferred, next, success, failure, nonpromisecb)
|
||||
failure()
|
||||
end)
|
||||
if not ok and not called then
|
||||
deferred.value = { err }
|
||||
deferred.value = { err, stack }
|
||||
failure()
|
||||
end
|
||||
else
|
||||
@ -76,14 +79,14 @@ local function fire(deferred)
|
||||
local ok
|
||||
local v
|
||||
if deferred.state == RESOLVING and isfunction(deferred.success) then
|
||||
local ret = { pcall(deferred.success, unpack(deferred.value)) }
|
||||
local ret = { xdcall(deferred.success, unpack(deferred.value)) }
|
||||
ok = table.remove(ret, 1)
|
||||
v = ret
|
||||
if not ok then
|
||||
table.insert(ret, "\nContaining next defined in " .. deferred.successInfo.short_src .. " at line " .. deferred.successInfo.linedefined .. "\n")
|
||||
end
|
||||
elseif deferred.state == REJECTING and isfunction(deferred.failure) then
|
||||
local ret = { pcall(deferred.failure, unpack(deferred.value)) }
|
||||
local ret = { xdcall(deferred.failure, unpack(deferred.value)) }
|
||||
ok = table.remove(ret, 1)
|
||||
v = ret
|
||||
if ok then
|
||||
|
@ -54,7 +54,7 @@ function NP.net.receive( name, func )
|
||||
net.WriteTable( args )
|
||||
net.Send( ply )
|
||||
end
|
||||
if ret[1] and ret[1].next then
|
||||
if ret[1] and type(ret[1]) == "table" and ret[1].next then
|
||||
ret[1]:next( function( ... )
|
||||
finish( true, { ... } )
|
||||
end,
|
||||
|
44
lua/network_promises/xdcall.lua
Normal file
44
lua/network_promises/xdcall.lua
Normal file
@ -0,0 +1,44 @@
|
||||
networkPromise.oldYield = networkPromise.oldYield or coroutine.yield
|
||||
local oldYield = networkPromise.oldYield
|
||||
|
||||
-- like pcall but returns a real traceback back as well
|
||||
-- xpcall allows you to get a traceback, but its not very good. Getting the trace from an errored coroutine is more accurate
|
||||
|
||||
-- Unique object that nothing else could return
|
||||
local trueYield = {}
|
||||
|
||||
local function capturedYield( ... )
|
||||
return oldYield( trueYield, ... )
|
||||
end
|
||||
|
||||
-- takes func, args
|
||||
-- if success, returns true, retArgs
|
||||
-- if not , returns false, error, stack
|
||||
function xdcall( func, ... )
|
||||
local co = coroutine.create( func )
|
||||
local args = { ... }
|
||||
while true do
|
||||
|
||||
coroutine.yield = capturedYield
|
||||
local data = { coroutine.resume( co, unpack(args) ) }
|
||||
coroutine.yield = oldYield
|
||||
|
||||
--p(data)
|
||||
local success = table.remove( data, 1 )
|
||||
if success then
|
||||
if data[1] == trueYield then
|
||||
-- They called yield internally
|
||||
table.remove( data, 1 )
|
||||
args = { oldYield( unpack( data ) ) }
|
||||
else
|
||||
-- successfully finished running
|
||||
return true, unpack( data )
|
||||
end
|
||||
else
|
||||
-- thats an error, dawg
|
||||
local err = data[1]
|
||||
return false, err, debug.traceback( co )
|
||||
end
|
||||
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user