cfc_network_promises/README.md
2021-01-16 22:34:21 +00:00

116 lines
4.9 KiB
Markdown

# cfc_network_promises
Network-based promise library
## Requirements
- [cfc_detached_timer](https://github.com/CFC-Servers/cfc_detached_timer)
## Async + Await
This project implements a C#/javascript style async and await functionality.
Similarly to Javascript, this is built on top of promises.
The `await` function takes a promise, and stops the execution thread until that promise resolves or rejects.
However, `await` can only be used in an `async` function, defined as `myFunc = async(function( a, b ) /* My code */end)`
`async` functions return a promise, and thus can be used in `await` themselves. This allows you to chain async functions as you would with promises.
## Usage
- `NP.net.send( name, ... )`
Send a net message on `name` containing the varargs `...`, no need for any `net.WriteString` or likewise.
Returns a promise resolving or rejecting with whatever data returned via `NP.net.receive()`
**Note:** This function sends more than just the varargs, only receive this with `NP.net.receive()`
- `NP.net.sendBlind( name, ... )`
Similar to `NP.net.send` but it does not wait for a response from the server, the returned promise resolves immediately.
**Note:** Any data returned by `NP.net.receive` from a blind message is discarded.
- `NP.net.receive( name, func )`
Receive a net message on `name` calling `func`, where func is of the form:
`function( callingPly, ... )`
The `...` will be whatever they were in the corresponding `NP.net.send()`
**Note:** Both send and receive will check if the name is already pooled, and if not, will add it as a network string ( `NP.net.send` will still error if called on client using an unpooled name )
- `NP.http.post( url, data, timeout )`
Post data to a `url`, with an optional `timeout` ( defaulting to 5 seconds ).
Returns a promise resolving in the form:
`function( statusCode, jsonData, headers )`
where jsonData is parsed from the post body, or rejecting in the form:
`function ( errorStr )`
**Note:** The url must return in JSON, if the JSON cannot be parsed with `util.JSONToTable()` then the promise will reject.
- `NP.http.fetch( url, timeout )`
Identical to `NP.http.post()` but fetches instead.
- `NP.http.request( method, endPoint, params, settings )`
This is a more in-depth way to make http requests, the arguments are as follows:
- `method` - One of [these http methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
- `endPoint` - The endpoint string to be appended to settings.apiRoot
- `params` - Parameters for GET, POST, HEAD
- `settings` - In the following structure:
```lua
{
apiRoot: "http://www.mywebsite.com/",
apikey: "somesupersecretkey",
timeout: 5 -- optional
}
```
- `async( func )`
Wraps the function `func` in a coroutine, passing any arguments onto it. This is required for `await` to be used.
The new function will return a promise, which will resolve with any return args of the inner function, or reject with any errors.
- `asyncCall( func )`
Equivalent to calling `async( func )()` but nicer looking.
- `await( promise )`
Halts an enclosing coroutine until the promise resolves/rejects, returns `resolved, ...` where `...` are the return args of the promise, or the error.
**NOTE:** This MUST be called within an async function.
## Example
Server side:
```lua
-- "getData" automatically pooled by this function.
-- Receive on getData, return the result of fetching the scripting url
NP.net.receive( "getData", function( ply )
return NP.http.fetch( "https://cfcservers.org/getData" )
end )
-- Alternative implementation:
NP.net.receive( "getData", async( function( ply )
local success, body, status = await( NP.http.fetch( "https://cfcservers.org/getData" ) )
if success then
return body, status
else
error( "Failed to reach end point" )
end
end ) )
```
Client side:
```lua
-- Send net message, print result or error
NP.net.send( "getData" ):next( function( body, status, headers )
-- Success
print( status ) -- Hopefully 200
PrintTable( util.JSONToTable( body ) ) -- Some data
end, function( err )
-- Failure
print( "Error: ", err )
end )
-- Alternative implementation:
asyncCall( function()
-- Thread is halted until the net send finishes, allowing you to treat it as a synchronous function.
local success, body, status = await( NP.net.send( "getData" ) )
if success then
print( status )
PrintTable( util.JSONToTable( body ) )
else
print( "Error: ", err )
end
end )
```
## Credit
The deferred library (`lua/network_promises/include/deferred.lua`) was written by [zserge](https://github.com/zserge), [here](https://github.com/zserge/lua-promises), and modified for CFC to support varargs in promise resolves and rejects.