diff --git a/src/status_node_manager/rest/apis/waku/rest_waku_api.nim b/src/status_node_manager/rest/apis/waku/rest_waku_api.nim new file mode 100644 index 0000000..b35e30b --- /dev/null +++ b/src/status_node_manager/rest/apis/waku/rest_waku_api.nim @@ -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") + diff --git a/src/status_node_manager/rest/apis/waku/rest_waku_calls.nim b/src/status_node_manager/rest/apis/waku/rest_waku_calls.nim new file mode 100644 index 0000000..46ce196 --- /dev/null +++ b/src/status_node_manager/rest/apis/waku/rest_waku_calls.nim @@ -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) + diff --git a/src/status_node_manager/rest/apis/waku/types.nim b/src/status_node_manager/rest/apis/waku/types.nim new file mode 100644 index 0000000..1b0939e --- /dev/null +++ b/src/status_node_manager/rest/apis/waku/types.nim @@ -0,0 +1,6 @@ +import waku/waku_core + +type WakuPairRequestData* = object + qr*: string + qrMessageNameTag*: string + pubSubTopic*: PubsubTopic diff --git a/src/status_node_manager/rest/common.nim b/src/status_node_manager/rest/common.nim index cf75c2d..d23eb68 100644 --- a/src/status_node_manager/rest/common.nim +++ b/src/status_node_manager/rest/common.nim @@ -1,13 +1,14 @@ import # Standard library std/[typetraits], + presto/[client], # Nimble packages chronos, confutils, presto, metrics, chronicles, stew/io2, # Project modules - ../config.nim + ../config func restValidate*(key: string, value: string): int = 0 @@ -44,3 +45,8 @@ proc init*(T: type RestServerRef, let server = res.get() notice "Starting REST HTTP server", url = "http://" & $server.localAddress() server + +proc raiseUnknownStatusError*(resp: RestPlainResponse) {. + noreturn, raises: [RestError].} = + let msg = "Unknown response status error (" & $resp.status & ")" + raise newException(RestError, msg) diff --git a/src/status_node_manager/rest/rest_constants.nim b/src/status_node_manager/rest/rest_constants.nim new file mode 100644 index 0000000..19fdb1a --- /dev/null +++ b/src/status_node_manager/rest/rest_constants.nim @@ -0,0 +1,5 @@ +const + EmptyRequestBodyError* = + "Empty request body" + InvalidWakuPairObjects* = + "Invalid Waku pair objects found" diff --git a/src/status_node_manager/rest/rest_serialization.nim b/src/status_node_manager/rest/rest_serialization.nim index 1b79edc..21add7b 100644 --- a/src/status_node_manager/rest/rest_serialization.nim +++ b/src/status_node_manager/rest/rest_serialization.nim @@ -6,23 +6,42 @@ import chronos, stew/byteutils, presto/[route, segpath, server, client], json_serialization, - serialization + serialization, + + # Local modules + ./apis/waku/types const ApplicationJsonMediaType* = MediaType.init("application/json") createJsonFlavor RestJson RestJson.useDefaultSerializationFor( - auto + WakuPairRequestData ) type DecodeTypes* = - auto + WakuPairRequestData type 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, contentType: string): RestResult[seq[byte]] =