feat(waku rest): Initial implementation of waku rest api
This commit is contained in:
parent
21c3d92aa8
commit
618884c0e2
|
@ -0,0 +1,57 @@
|
||||||
|
import
|
||||||
|
# Nimble packages
|
||||||
|
chronicles,
|
||||||
|
presto/[route, segpath, server],
|
||||||
|
serialization, json_serialization,
|
||||||
|
|
||||||
|
# Local packages
|
||||||
|
./types,
|
||||||
|
../../[rest_constants, rest_serialization],
|
||||||
|
../../../waku,
|
||||||
|
../../../../../libs/waku_utils/waku_pair
|
||||||
|
|
||||||
|
proc wakuApiError(status: HttpCode, msg: string): RestApiResponse =
|
||||||
|
let data =
|
||||||
|
block:
|
||||||
|
var default: string
|
||||||
|
try:
|
||||||
|
var stream = memoryOutput()
|
||||||
|
var writer = JsonWriter[RestJson].init(stream)
|
||||||
|
writer.beginRecord()
|
||||||
|
writer.writeField("message", msg)
|
||||||
|
writer.endRecord()
|
||||||
|
stream.getOutput(string)
|
||||||
|
except SerializationError:
|
||||||
|
default
|
||||||
|
except IOError:
|
||||||
|
default
|
||||||
|
RestApiResponse.error(status, data, "application/json")
|
||||||
|
|
||||||
|
proc installWakuApiHandlers*(router: var RestRouter,
|
||||||
|
wakuHost: ref WakuHost) =
|
||||||
|
router.api(MethodPost, "/waku/pair"
|
||||||
|
) do (contentBody: Option[ContentBody]) -> RestApiResponse:
|
||||||
|
let wakuPairData =
|
||||||
|
block:
|
||||||
|
if contentBody.isNone():
|
||||||
|
return wakuApiError(Http404, EmptyRequestBodyError)
|
||||||
|
let dres = decodeBody(WakuPairRequestData, contentBody.get())
|
||||||
|
|
||||||
|
if dres.isErr():
|
||||||
|
return wakuApiError(Http400, InvalidWakuPairObjects)
|
||||||
|
dres.get()
|
||||||
|
try:
|
||||||
|
let wakuPairResult = await wakuPair(wakuHost[].rng,
|
||||||
|
wakuHost[].wakuNode,
|
||||||
|
wakuPairData.qr,
|
||||||
|
wakuPairData.qrMessageNameTag,
|
||||||
|
wakuPairData.pubSubTopic)
|
||||||
|
|
||||||
|
wakuHost.wakuNode = wakuPairResult.wakuNode
|
||||||
|
wakuHost.wakuHandshake = wakuPairResult.wakuHandshakeResult
|
||||||
|
|
||||||
|
notice "Waku pairing successful! Request fulfilled."
|
||||||
|
return RestApiResponse.response("Successful pairing", Http200, "application/json")
|
||||||
|
except:
|
||||||
|
return wakuApiError(Http500, "Internal Server Error")
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import
|
||||||
|
# Nimble packages
|
||||||
|
chronicles,
|
||||||
|
presto/[route, segpath, client],
|
||||||
|
serialization, json_serialization,
|
||||||
|
stew/byteutils,
|
||||||
|
|
||||||
|
# Local packages
|
||||||
|
./types,
|
||||||
|
../../common,
|
||||||
|
../../rest_serialization
|
||||||
|
|
||||||
|
proc wakuPairPlain*(body: WakuPairRequestData): RestPlainResponse {.
|
||||||
|
rest, endpoint: "/waku/pair",
|
||||||
|
meth: MethodPost.}
|
||||||
|
|
||||||
|
proc wakuPair*(client: RestClientRef, wakuPairData: WakuPairRequestData) {.async.} =
|
||||||
|
notice "Initiating Waku Pair request..."
|
||||||
|
let
|
||||||
|
resp = await client.wakuPairPlain(wakuPairData)
|
||||||
|
respMsg = string.fromBytes(resp.data)
|
||||||
|
case resp.status:
|
||||||
|
of 200:
|
||||||
|
notice "Waku Pair request successful", body=respMsg
|
||||||
|
of 400, 401, 403, 404, 500:
|
||||||
|
notice "Waku Pair request failed", status=resp.status, body=respMsg
|
||||||
|
else:
|
||||||
|
raiseUnknownStatusError(resp)
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import waku/waku_core
|
||||||
|
|
||||||
|
type WakuPairRequestData* = object
|
||||||
|
qr*: string
|
||||||
|
qrMessageNameTag*: string
|
||||||
|
pubSubTopic*: PubsubTopic
|
|
@ -1,13 +1,14 @@
|
||||||
import
|
import
|
||||||
# Standard library
|
# Standard library
|
||||||
std/[typetraits],
|
std/[typetraits],
|
||||||
|
presto/[client],
|
||||||
|
|
||||||
# Nimble packages
|
# Nimble packages
|
||||||
chronos, confutils, presto, metrics,
|
chronos, confutils, presto, metrics,
|
||||||
chronicles, stew/io2,
|
chronicles, stew/io2,
|
||||||
|
|
||||||
# Project modules
|
# Project modules
|
||||||
../config.nim
|
../config
|
||||||
|
|
||||||
func restValidate*(key: string, value: string): int =
|
func restValidate*(key: string, value: string): int =
|
||||||
0
|
0
|
||||||
|
@ -44,3 +45,8 @@ proc init*(T: type RestServerRef,
|
||||||
let server = res.get()
|
let server = res.get()
|
||||||
notice "Starting REST HTTP server", url = "http://" & $server.localAddress()
|
notice "Starting REST HTTP server", url = "http://" & $server.localAddress()
|
||||||
server
|
server
|
||||||
|
|
||||||
|
proc raiseUnknownStatusError*(resp: RestPlainResponse) {.
|
||||||
|
noreturn, raises: [RestError].} =
|
||||||
|
let msg = "Unknown response status error (" & $resp.status & ")"
|
||||||
|
raise newException(RestError, msg)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
const
|
||||||
|
EmptyRequestBodyError* =
|
||||||
|
"Empty request body"
|
||||||
|
InvalidWakuPairObjects* =
|
||||||
|
"Invalid Waku pair objects found"
|
|
@ -6,23 +6,42 @@ import
|
||||||
chronos, stew/byteutils,
|
chronos, stew/byteutils,
|
||||||
presto/[route, segpath, server, client],
|
presto/[route, segpath, server, client],
|
||||||
json_serialization,
|
json_serialization,
|
||||||
serialization
|
serialization,
|
||||||
|
|
||||||
|
# Local modules
|
||||||
|
./apis/waku/types
|
||||||
|
|
||||||
const ApplicationJsonMediaType* = MediaType.init("application/json")
|
const ApplicationJsonMediaType* = MediaType.init("application/json")
|
||||||
|
|
||||||
createJsonFlavor RestJson
|
createJsonFlavor RestJson
|
||||||
|
|
||||||
RestJson.useDefaultSerializationFor(
|
RestJson.useDefaultSerializationFor(
|
||||||
auto
|
WakuPairRequestData
|
||||||
)
|
)
|
||||||
|
|
||||||
type
|
type
|
||||||
DecodeTypes* =
|
DecodeTypes* =
|
||||||
auto
|
WakuPairRequestData
|
||||||
|
|
||||||
type
|
type
|
||||||
EncodeTypes* =
|
EncodeTypes* =
|
||||||
auto
|
WakuPairRequestData
|
||||||
|
|
||||||
|
proc jsonResponsePlain*(t: typedesc[RestApiResponse],
|
||||||
|
data: auto): RestApiResponse =
|
||||||
|
let res =
|
||||||
|
block:
|
||||||
|
var default: seq[byte]
|
||||||
|
try:
|
||||||
|
var stream = memoryOutput()
|
||||||
|
var writer = JsonWriter[RestJson].init(stream)
|
||||||
|
writer.writeValue(data)
|
||||||
|
stream.getOutput(seq[byte])
|
||||||
|
except SerializationError:
|
||||||
|
default
|
||||||
|
except IOError:
|
||||||
|
default
|
||||||
|
RestApiResponse.response(res, Http200, "application/json")
|
||||||
|
|
||||||
proc encodeBytes*[T: EncodeTypes](value: T,
|
proc encodeBytes*[T: EncodeTypes](value: T,
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
|
|
Loading…
Reference in New Issue