From 80d78c81f7fc63d81e23cb8a759196115cec17cb Mon Sep 17 00:00:00 2001 From: Tanguy Date: Fri, 17 Feb 2023 18:37:26 +0100 Subject: [PATCH] Nim interop support (#138) --- multidim-interop/Makefile | 7 ++- multidim-interop/nim/mainv1.nim | 92 ++++++++++++++++++++++++++++ multidim-interop/nim/v1.0/Dockerfile | 20 ++++++ multidim-interop/nim/v1.0/Makefile | 29 +++++++++ multidim-interop/versions.ts | 8 +++ 5 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 multidim-interop/nim/mainv1.nim create mode 100644 multidim-interop/nim/v1.0/Dockerfile create mode 100644 multidim-interop/nim/v1.0/Makefile diff --git a/multidim-interop/Makefile b/multidim-interop/Makefile index 29f249d..3e2b6d0 100644 --- a/multidim-interop/Makefile +++ b/multidim-interop/Makefile @@ -1,14 +1,17 @@ GO_SUBDIRS := $(wildcard go/*/.) JS_SUBDIRS := $(wildcard js/*/.) RUST_SUBDIRS := $(wildcard rust/*/.) +NIM_SUBDIRS := $(wildcard nim/*/.) -all: $(GO_SUBDIRS) $(JS_SUBDIRS) $(RUST_SUBDIRS) +all: $(GO_SUBDIRS) $(JS_SUBDIRS) $(RUST_SUBDIRS) $(NIM_SUBDIRS) $(JS_SUBDIRS): $(MAKE) -C $@ $(GO_SUBDIRS): $(MAKE) -C $@ $(RUST_SUBDIRS): $(MAKE) -C $@ +$(NIM_SUBDIRS): + $(MAKE) -C $@ -.PHONY: $(GO_SUBDIRS) $(JS_SUBDIRS) $(RUST_SUBDIRS) all \ No newline at end of file +.PHONY: $(GO_SUBDIRS) $(JS_SUBDIRS) $(RUST_SUBDIRS) $(NIM_SUBDIRS) all diff --git a/multidim-interop/nim/mainv1.nim b/multidim-interop/nim/mainv1.nim new file mode 100644 index 0000000..7961426 --- /dev/null +++ b/multidim-interop/nim/mainv1.nim @@ -0,0 +1,92 @@ +import + std/[os, strutils, sequtils], + chronos, redis, serialization, json_serialization, + libp2p, libp2p/protocols/ping, libp2p/transports/wstransport + +type + ResultJson = object + handshakePlusOneRTTMillis: float + pingRTTMilllis: float + +let + testTimeout = + try: seconds(parseInt(getEnv("test_timeout_seconds"))) + except CatchableError: 3.minutes + +proc main {.async.} = + + let + transport = getEnv("transport") + muxer = getEnv("muxer") + secureChannel = getEnv("security") + isDialer = getEnv("is_dialer") == "true" + envIp = getEnv("ip", "0.0.0.0") + ip = + # nim-libp2p doesn't do snazzy ip expansion + if envIp == "0.0.0.0": + block: + let addresses = getInterfaces().filterIt(it.name == "eth0").mapIt(it.addresses) + if addresses.len < 1 or addresses[0].len < 1: + quit "Can't find local ip!" + ($addresses[0][0].host).split(":")[0] + else: + envIp + redisAddr = getEnv("redis_addr", "redis:6379").split(":") + + # using synchronous redis because async redis is based on + # asyncdispatch instead of chronos + redisClient = open(redisAddr[0], Port(parseInt(redisAddr[1]))) + + switchBuilder = SwitchBuilder.new() + + case transport: + of "tcp": + discard switchBuilder.withTcpTransport().withAddress( + MultiAddress.init("/ip4/" & ip & "/tcp/0").tryGet() + ) + of "ws": + discard switchBuilder.withTransport(proc (upgr: Upgrade): Transport = WsTransport.new(upgr)).withAddress( + MultiAddress.init("/ip4/" & ip & "/tcp/0/ws").tryGet() + ) + else: doAssert false + + case secureChannel: + of "noise": discard switchBuilder.withNoise() + else: doAssert false + + case muxer: + of "yamux": discard switchBuilder.withYamux() + of "mplex": discard switchBuilder.withMplex() + else: doAssert false + + let + rng = libp2p.newRng() + switch = switchBuilder.withRng(rng).build() + pingProtocol = Ping.new(rng = rng) + switch.mount(pingProtocol) + await switch.start() + defer: await switch.stop() + + if not isDialer: + discard redisClient.rPush("listenerAddr", $switch.peerInfo.fullAddrs.tryGet()[0]) + await sleepAsync(100.hours) # will get cancelled + else: + let + remoteAddr = MultiAddress.init(redisClient.bLPop(@["listenerAddr"], testTimeout.seconds.int)[1]).tryGet() + dialingStart = Moment.now() + remotePeerId = await switch.connect(remoteAddr) + stream = await switch.dial(remotePeerId, PingCodec) + pingDelay = await pingProtocol.ping(stream) + totalDelay = Moment.now() - dialingStart + await stream.close() + + echo Json.encode( + ResultJson( + handshakePlusOneRTTMillis: float(totalDelay.milliseconds), + pingRTTMilllis: float(pingDelay.milliseconds) + ) + ) + quit(0) + +discard waitFor(main().withTimeout(testTimeout)) +quit(1) diff --git a/multidim-interop/nim/v1.0/Dockerfile b/multidim-interop/nim/v1.0/Dockerfile new file mode 100644 index 0000000..4658b55 --- /dev/null +++ b/multidim-interop/nim/v1.0/Dockerfile @@ -0,0 +1,20 @@ +ARG NimVersion="1.6.10" +FROM nimlang/nim:${NimVersion}-alpine as builder + +WORKDIR /app + +COPY nim-libp2p nim-libp2p + +RUN \ + cd nim-libp2p && \ + nimble install_pinned + +RUN \ + cd nim-libp2p && \ + nimble install "redis@#b341fe240dbf11c544011dd0e033d3c3acca56af" + +COPY main.nim main.nim +RUN \ + nim c --NimblePath:nim-libp2p/nimbledeps/pkgs -p:nim-libp2p -d:chronicles_log_level=WARN --threads:off main.nim + +ENTRYPOINT ["/app/main"] diff --git a/multidim-interop/nim/v1.0/Makefile b/multidim-interop/nim/v1.0/Makefile new file mode 100644 index 0000000..8a7891f --- /dev/null +++ b/multidim-interop/nim/v1.0/Makefile @@ -0,0 +1,29 @@ +image_name := nim-v1.0 +commitSha := 408dcf12bdf44dcd6f9021a6c795c472679d6d02 + +all: image.json + +image.json: main.nim nim-libp2p Dockerfile + IMAGE_NAME=${image_name} ../../dockerBuildWrapper.sh . + docker image inspect ${image_name} -f "{{.Id}}" | \ + xargs -I {} echo "{\"imageID\": \"{}\"}" > $@ + +main.nim: ../mainv1.nim + cp ../mainv1.nim main.nim + +nim-libp2p: nim-libp2p-${commitSha} + rm -rf nim-libp2p + ln -s nim-libp2p-${commitSha} nim-libp2p + +nim-libp2p-${commitSha}: nim-libp2p-${commitSha}.zip + unzip -o nim-libp2p-${commitSha}.zip + +nim-libp2p-${commitSha}.zip: + wget -O $@ "https://github.com/status-im/nim-libp2p/archive/${commitSha}.zip" + +.PHONY: clean all + +clean: + rm -f main.nim + rm -f image.json + rm -rf nim-libp2p* diff --git a/multidim-interop/versions.ts b/multidim-interop/versions.ts index 95cf4ab..45aeea5 100644 --- a/multidim-interop/versions.ts +++ b/multidim-interop/versions.ts @@ -4,6 +4,7 @@ import gov023 from "./go/v0.23/image.json" import gov022 from "./go/v0.22/image.json" import rustv050 from "./rust/v0.50/image.json" import jsV041 from "./js/v0.41/node-image.json" +import nimv10 from "./nim/v1.0/image.json" import chromiumJsV041 from "./js/v0.41/chromium-image.json" export type Version = { @@ -66,4 +67,11 @@ export const versions: Array = [ secureChannels: ["tls", "noise"], muxers: ["mplex", "yamux"], }, + { + id: "nim-v1.0", + containerImageID: nimv10.imageID, + transports: ["tcp", "ws"], + secureChannels: ["noise"], + muxers: ["mplex", "yamux"], + }, ]