Skip to content

Commit d97b860

Browse files
AkMo3lla-dane
authored andcommitted
fix: add nim libp2p echo interop
1 parent 2c03ac4 commit d97b860

File tree

5 files changed

+457
-1
lines changed

5 files changed

+457
-1
lines changed

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ dependencies = [
2020
"base58>=1.0.3",
2121
"coincurve==21.0.0",
2222
"exceptiongroup>=1.2.0; python_version < '3.11'",
23+
"fastecdsa==2.3.2; sys_platform != 'win32'",
2324
"grpcio>=1.41.0",
2425
"lru-dict>=1.1.6",
2526
"multiaddr (>=0.0.9,<0.0.10)",
@@ -32,7 +33,6 @@ dependencies = [
3233
"rpcudp>=3.0.0",
3334
"trio-typing>=0.0.4",
3435
"trio>=0.26.0",
35-
"fastecdsa==2.3.2; sys_platform != 'win32'",
3636
"zeroconf (>=0.147.0,<0.148.0)",
3737
]
3838
classifiers = [
@@ -282,4 +282,5 @@ project_excludes = [
282282
"**/*pb2.py",
283283
"**/*.pyi",
284284
".venv/**",
285+
"./tests/interop/nim_libp2p",
285286
]

tests/interop/nim_libp2p/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
nimble.develop
2+
nimble.paths
3+
4+
*.nimble
5+
nim-libp2p/
6+
7+
nim_echo_server
8+
config.nims
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
{.used.}
2+
3+
import chronos
4+
import stew/byteutils
5+
import libp2p
6+
7+
##
8+
# Simple Echo Protocol Implementation for py-libp2p Interop Testing
9+
##
10+
const EchoCodec = "/echo/1.0.0"
11+
12+
type EchoProto = ref object of LPProtocol
13+
14+
proc new(T: typedesc[EchoProto]): T =
15+
proc handle(conn: Connection, proto: string) {.async: (raises: [CancelledError]).} =
16+
try:
17+
echo "Echo server: Received connection from ", conn.peerId
18+
19+
# Read and echo messages in a loop
20+
while not conn.atEof:
21+
try:
22+
# Read length-prefixed message using nim-libp2p's readLp
23+
let message = await conn.readLp(1024 * 1024) # Max 1MB
24+
if message.len == 0:
25+
echo "Echo server: Empty message, closing connection"
26+
break
27+
28+
let messageStr = string.fromBytes(message)
29+
echo "Echo server: Received (", message.len, " bytes): ", messageStr
30+
31+
# Echo back using writeLp
32+
await conn.writeLp(message)
33+
echo "Echo server: Echoed message back"
34+
35+
except CatchableError as e:
36+
echo "Echo server: Error processing message: ", e.msg
37+
break
38+
39+
except CancelledError as e:
40+
echo "Echo server: Connection cancelled"
41+
raise e
42+
except CatchableError as e:
43+
echo "Echo server: Exception in handler: ", e.msg
44+
finally:
45+
echo "Echo server: Connection closed"
46+
await conn.close()
47+
48+
return T.new(codecs = @[EchoCodec], handler = handle)
49+
50+
##
51+
# Create QUIC-enabled switch
52+
##
53+
proc createSwitch(ma: MultiAddress, rng: ref HmacDrbgContext): Switch =
54+
var switch = SwitchBuilder
55+
.new()
56+
.withRng(rng)
57+
.withAddress(ma)
58+
.withQuicTransport()
59+
.build()
60+
result = switch
61+
62+
##
63+
# Main server
64+
##
65+
proc main() {.async.} =
66+
let
67+
rng = newRng()
68+
localAddr = MultiAddress.init("/ip4/0.0.0.0/udp/0/quic-v1").tryGet()
69+
echoProto = EchoProto.new()
70+
71+
echo "=== Nim Echo Server for py-libp2p Interop ==="
72+
73+
# Create switch
74+
let switch = createSwitch(localAddr, rng)
75+
switch.mount(echoProto)
76+
77+
# Start server
78+
await switch.start()
79+
80+
# Print connection info
81+
echo "Peer ID: ", $switch.peerInfo.peerId
82+
echo "Listening on:"
83+
for addr in switch.peerInfo.addrs:
84+
echo " ", $addr, "/p2p/", $switch.peerInfo.peerId
85+
echo "Protocol: ", EchoCodec
86+
echo "Ready for py-libp2p connections!"
87+
echo ""
88+
89+
# Keep running
90+
try:
91+
await sleepAsync(100.hours)
92+
except CancelledError:
93+
echo "Shutting down..."
94+
finally:
95+
await switch.stop()
96+
97+
# Graceful shutdown handler
98+
proc signalHandler() {.noconv.} =
99+
echo "\nShutdown signal received"
100+
quit(0)
101+
102+
when isMainModule:
103+
setControlCHook(signalHandler)
104+
try:
105+
waitFor(main())
106+
except CatchableError as e:
107+
echo "Error: ", e.msg
108+
quit(1)
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#!/usr/bin/env bash
2+
# Simple setup script for nim echo server interop testing
3+
4+
set -euo pipefail
5+
6+
# Colors
7+
GREEN='\033[0;32m'
8+
RED='\033[0;31m'
9+
YELLOW='\033[1;33m'
10+
NC='\033[0m'
11+
12+
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
13+
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
14+
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
15+
16+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17+
PROJECT_ROOT="${SCRIPT_DIR}/.."
18+
NIM_LIBP2P_DIR="${PROJECT_ROOT}/nim-libp2p"
19+
20+
# Check prerequisites
21+
check_nim() {
22+
if ! command -v nim &> /dev/null; then
23+
log_error "Nim not found. Install with: curl -sSf https://nim-lang.org/choosenim/init.sh | sh"
24+
exit 1
25+
fi
26+
if ! command -v nimble &> /dev/null; then
27+
log_error "Nimble not found. Please install Nim properly."
28+
exit 1
29+
fi
30+
}
31+
32+
# Setup nim-libp2p dependency
33+
setup_nim_libp2p() {
34+
log_info "Setting up nim-libp2p dependency..."
35+
36+
if [ ! -d "${NIM_LIBP2P_DIR}" ]; then
37+
log_info "Cloning nim-libp2p..."
38+
git clone https://github.com/status-im/nim-libp2p.git "${NIM_LIBP2P_DIR}"
39+
fi
40+
41+
cd "${NIM_LIBP2P_DIR}"
42+
log_info "Installing nim-libp2p dependencies..."
43+
nimble install -y --depsOnly
44+
}
45+
46+
# Build nim echo server
47+
build_echo_server() {
48+
log_info "Building nim echo server..."
49+
50+
cd "${PROJECT_ROOT}"
51+
52+
# Create nimble file if it doesn't exist
53+
cat > nim_echo_test.nimble << 'EOF'
54+
# Package
55+
version = "0.1.0"
56+
author = "py-libp2p interop"
57+
description = "nim echo server for interop testing"
58+
license = "MIT"
59+
60+
# Dependencies
61+
requires "nim >= 1.6.0"
62+
requires "libp2p"
63+
requires "chronos"
64+
requires "stew"
65+
66+
# Binary
67+
bin = @["nim_echo_server"]
68+
EOF
69+
70+
# Build the server
71+
log_info "Compiling nim echo server..."
72+
nim c -d:release -d:chronicles_log_level=INFO -d:libp2p_quic_support --opt:speed --gc:orc -o:nim_echo_server nim_echo_server.nim
73+
74+
if [ -f "nim_echo_server" ]; then
75+
log_info "✅ nim_echo_server built successfully"
76+
else
77+
log_error "❌ Failed to build nim_echo_server"
78+
exit 1
79+
fi
80+
}
81+
82+
main() {
83+
log_info "Setting up nim echo server for interop testing..."
84+
85+
# Create logs directory
86+
mkdir -p "${PROJECT_ROOT}/logs"
87+
88+
# Clean up any existing processes
89+
pkill -f "nim_echo_server" || true
90+
91+
check_nim
92+
setup_nim_libp2p
93+
build_echo_server
94+
95+
log_info "🎉 Setup complete! You can now run: python -m pytest test_echo_interop.py -v"
96+
}
97+
98+
main "$@"

0 commit comments

Comments
 (0)