2022-11-04 09:52:27 +00:00
|
|
|
when (NimMajor, NimMinor) < (1, 4):
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
else:
|
|
|
|
{.push raises: [].}
|
2022-06-02 09:45:00 +00:00
|
|
|
|
|
|
|
import
|
2022-06-28 10:22:59 +00:00
|
|
|
stew/results,
|
2022-06-02 09:45:00 +00:00
|
|
|
stew/shims/net,
|
2022-06-28 10:22:59 +00:00
|
|
|
chronicles,
|
|
|
|
chronos,
|
2022-06-02 09:45:00 +00:00
|
|
|
presto
|
|
|
|
|
|
|
|
|
2022-06-28 10:22:59 +00:00
|
|
|
type RestServerResult*[T] = Result[T, cstring]
|
2022-06-02 09:45:00 +00:00
|
|
|
|
|
|
|
|
2022-06-28 10:22:59 +00:00
|
|
|
### Configuration
|
2022-06-02 09:45:00 +00:00
|
|
|
|
|
|
|
type RestServerConf* = object
|
|
|
|
cacheSize*: Natural ## \
|
|
|
|
## The maximum number of recently accessed states that are kept in \
|
|
|
|
## memory. Speeds up requests obtaining information for consecutive
|
|
|
|
## slots or epochs.
|
|
|
|
|
|
|
|
cacheTtl*: Natural ## \
|
|
|
|
## The number of seconds to keep recently accessed states in memory
|
|
|
|
|
|
|
|
requestTimeout*: Natural ## \
|
|
|
|
## The number of seconds to wait until complete REST request will be received
|
|
|
|
|
|
|
|
maxRequestBodySize*: Natural ## \
|
|
|
|
## Maximum size of REST request body (kilobytes)
|
|
|
|
|
|
|
|
maxRequestHeadersSize*: Natural ## \
|
|
|
|
## Maximum size of REST request headers (kilobytes)
|
|
|
|
|
2022-06-28 10:22:59 +00:00
|
|
|
proc default*(T: type RestServerConf): T =
|
2022-06-02 09:45:00 +00:00
|
|
|
RestServerConf(
|
|
|
|
cacheSize: 3,
|
|
|
|
cacheTtl: 60,
|
|
|
|
requestTimeout: 0,
|
|
|
|
maxRequestBodySize: 16_384,
|
|
|
|
maxRequestHeadersSize: 64
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-06-28 10:22:59 +00:00
|
|
|
### Initialization
|
|
|
|
|
|
|
|
proc getRouter(allowedOrigin: Option[string]): RestRouter =
|
|
|
|
# TODO: Review this `validate` method. Check in nim-presto what is this used for.
|
|
|
|
proc validate(pattern: string, value: string): int =
|
|
|
|
## This is rough validation procedure which should be simple and fast,
|
|
|
|
## because it will be used for query routing.
|
|
|
|
if pattern.startsWith("{") and pattern.endsWith("}"): 0
|
|
|
|
else: 1
|
|
|
|
|
|
|
|
RestRouter.init(validate, allowedOrigin = allowedOrigin)
|
|
|
|
|
|
|
|
proc init*(T: type RestServerRef,
|
2022-06-02 09:45:00 +00:00
|
|
|
ip: ValidIpAddress, port: Port,
|
2022-06-28 10:22:59 +00:00
|
|
|
allowedOrigin=none(string),
|
|
|
|
conf=RestServerConf.default()): RestServerResult[T] =
|
2022-06-02 09:45:00 +00:00
|
|
|
let address = initTAddress(ip, port)
|
|
|
|
let serverFlags = {
|
|
|
|
HttpServerFlags.QueryCommaSeparatedArray,
|
|
|
|
HttpServerFlags.NotifyDisconnect
|
|
|
|
}
|
|
|
|
|
|
|
|
let
|
|
|
|
headersTimeout = if conf.requestTimeout == 0: chronos.InfiniteDuration
|
|
|
|
else: seconds(int64(conf.requestTimeout))
|
|
|
|
maxHeadersSize = conf.maxRequestHeadersSize * 1024
|
|
|
|
maxRequestBodySize = conf.maxRequestBodySize * 1024
|
|
|
|
|
|
|
|
let router = getRouter(allowedOrigin)
|
|
|
|
|
2022-06-28 10:22:59 +00:00
|
|
|
var res: RestResult[RestServerRef]
|
|
|
|
try:
|
|
|
|
res = RestServerRef.new(
|
|
|
|
router,
|
|
|
|
address,
|
|
|
|
serverFlags = serverFlags,
|
|
|
|
httpHeadersTimeout = headersTimeout,
|
|
|
|
maxHeadersSize = maxHeadersSize,
|
|
|
|
maxRequestBodySize = maxRequestBodySize
|
|
|
|
)
|
|
|
|
except CatchableError as ex:
|
|
|
|
return err(cstring(ex.msg))
|
|
|
|
|
|
|
|
res
|
|
|
|
|
|
|
|
proc newRestHttpServer*(ip: ValidIpAddress, port: Port,
|
|
|
|
allowedOrigin=none(string),
|
|
|
|
conf=RestServerConf.default()): RestServerResult[RestServerRef] =
|
|
|
|
RestServerRef.init(ip, port, allowedOrigin, conf)
|
|
|
|
|