This commit is contained in:
Dmitriy Ryajov 2020-04-14 18:02:39 -06:00
parent b5e60a084a
commit f58744fabe
6 changed files with 348 additions and 338 deletions

View File

@ -1,276 +1,266 @@
import chronos
type
AsyncIterable*[T] = iterator(): Future[T] {.closure.}
import stream
template toFuture*[T](v: T): Future[T] =
var fut = newFuture[T]()
fut.complete(v)
fut
iterator items*[T](i: AsyncIterable[T]): Future[T] =
proc forEach*[T](iter: Source[T],
pred: proc(item: Future[T]):
Future[void] {.gcsafe.}) {.async.} =
for i in iter:
await pred(i)
proc collect*[T](iter: Source[T]): Future[seq[T]] =
for i in iter:
result.add(i)
proc map*[T, S](iter: Source[T],
pred: proc(item: Future[T]): Future[S] {.gcsafe.}):
Source[T] =
return iterator(): Future[S] =
for i in iter:
yield pred(i)
proc filter*[T](iter: Source[T],
pred: proc(item: Future[T]): Future[bool] {.gcsafe.}):
Source[T] =
return iterator(): Future[T] =
proc next(item: Future[T]): Future[T] {.async.} =
for i in iter:
if not (await pred(i)):
continue
result = await i
for i in iter:
yield next(i)
proc zip*[T,S](i: Source[T],
j: Source[S]):
iterator(): Future[tuple[a: Future[T], b: Future[S]]] {.gcsafe.} =
## Iterates through both iterators at the same time, returning a tuple of
## both elements as long as neither of the iterators has finished.
##
## .. code-block:: nim
## for x in zip(1..4, 20..24):
## echo x
return iterator(): Future[tuple[a: Future[T], b: Future[S]]] {.gcsafe.} =
while true:
var item = i()
if i.finished():
let res = (i(), j())
if finished(i) or finished(j):
break
yield res.toFuture
yield item
proc slice*[T](i: Source[T],
first = 0, last = 0, step = 1): Source[T] =
## Yields every `step` item in `i` from index `first` to `last`.
##
## .. code-block:: nim
## for i in slice(0..100, 10, 20)
## echo i
var pos = 0
return iterator(): Future[T] {.gcsafe.} =
for x in i:
if pos > last:
break
elif pos >= first and (pos - first) mod step == 0:
yield x
inc pos
# proc forEach*[T](iter: AsyncIterable[T],
# pred: proc(item: Future[T]):
# Future[void] {.gcsafe.}) {.async.} =
# for i in iter:
# await pred(i)
proc delete*[T](i: Source[T],
first = 0, last = 0): Source[T] =
## Yields the items in `i` except for the ones between `first` and `last`.
##
## .. code-block:: nim
## for x in delete(1..10, 4, 8):
## echo x
var pos = 0
return iterator(): Future[T] {.gcsafe.} =
for x in i:
if pos notin first..last:
yield x
inc pos
# proc collect*[T](iter: AsyncIterable[T]): Future[seq[T]] =
# for i in iter:
# result.add(i)
proc foldl*[T,S](i: Source[T],
f: proc(x: Future[S], y: Future[T]): Future[S] {.gcsafe.},
y: Future[S] | S):
Future[S] =
## Folds the values as the iterator yields them, returning the accumulation.
##
## As the initial value of the accumulation `y` is used.
##
## .. code-block:: nim
## echo foldl(1..10, proc(x,y: int): int = x + y, 0)
when type(y) is Future:
result = await y
else:
result = y.toFuture
# proc map*[T, S](iter: AsyncIterable[T],
# pred: proc(item: Future[T]): Future[S] {.gcsafe.}):
# AsyncIterable[T] =
# return iterator(): Future[S] =
# for i in iter:
# yield pred(i)
for x in i:
result = f(result, x)
# proc filter*[T](iter: AsyncIterable[T],
# pred: proc(item: Future[T]): Future[bool] {.gcsafe.}):
# AsyncIterable[T] =
# return iterator(): Future[T] =
# proc next(item: Future[T]): Future[T] {.async.} =
# for i in iter:
# if not (await pred(i)):
# continue
# result = await i
when isMainModule:
import unittest, strutils
# for i in iter:
# yield next(i)
suite "nimstreams":
test "forEach":
proc test(): Future[bool] {.async.} =
iterator stream(): Future[int] {.closure, gcsafe.} =
for i in @[1, 2, 3, 4, 5]:
yield i.toFuture
# proc zip*[T,S](i: AsyncIterable[T],
# j: AsyncIterable[S]):
# iterator(): Future[tuple[a: Future[T], b: Future[S]]] {.gcsafe.} =
# ## Iterates through both iterators at the same time, returning a tuple of
# ## both elements as long as neither of the iterators has finished.
# ##
# ## .. code-block:: nim
# ## for x in zip(1..4, 20..24):
# ## echo x
# return iterator(): Future[tuple[a: Future[T], b: Future[S]]] {.gcsafe.} =
# while true:
# let res = (i(), j())
# if finished(i) or finished(j):
# break
# yield res.toFuture
var count = 1
await stream.forEach(
proc(item: Future[int]): Future[void] {.async, gcsafe.} =
check:
count == await item
count.inc())
# proc slice*[T](i: AsyncIterable[T],
# first = 0, last = 0, step = 1): AsyncIterable[T] =
# ## Yields every `step` item in `i` from index `first` to `last`.
# ##
# ## .. code-block:: nim
# ## for i in slice(0..100, 10, 20)
# ## echo i
# var pos = 0
# return iterator(): Future[T] {.gcsafe.} =
# for x in i:
# if pos > last:
# break
# elif pos >= first and (pos - first) mod step == 0:
# yield x
# inc pos
result = true
# proc delete*[T](i: AsyncIterable[T],
# first = 0, last = 0): AsyncIterable[T] =
# ## Yields the items in `i` except for the ones between `first` and `last`.
# ##
# ## .. code-block:: nim
# ## for x in delete(1..10, 4, 8):
# ## echo x
# var pos = 0
# return iterator(): Future[T] {.gcsafe.} =
# for x in i:
# if pos notin first..last:
# yield x
# inc pos
check:
waitFor(test()) == true
# proc foldl*[T,S](i: AsyncIterable[T],
# f: proc(x: Future[S], y: Future[T]): Future[S] {.gcsafe.},
# y: Future[S] | S):
# Future[S] =
# ## Folds the values as the iterator yields them, returning the accumulation.
# ##
# ## As the initial value of the accumulation `y` is used.
# ##
# ## .. code-block:: nim
# ## echo foldl(1..10, proc(x,y: int): int = x + y, 0)
# when type(y) is Future:
# result = await y
# else:
# result = y.toFuture
test "map":
proc test(): Future[bool] {.async.} =
iterator stream(): Future[char] {.closure, gcsafe.} =
for i in @['a', 'b', 'c', 'd', 'e']:
yield i.toFuture
# for x in i:
# result = f(result, x)
var items = @['A', 'B', 'C', 'D', 'E']
var pos = 0
await stream
.map(
proc(item: Future[char]): Future[char] {.async, gcsafe.} =
result = (await item).toUpperAscii())
.forEach(
proc(item: Future[char]): Future[void] {.async, gcsafe.} =
check:
items[pos] == await item
pos.inc())
# when isMainModule:
# import unittest, strutils
result = true
# suite "nimstreams":
# test "forEach":
# proc test(): Future[bool] {.async.} =
# iterator stream(): Future[int] {.closure, gcsafe.} =
# for i in @[1, 2, 3, 4, 5]:
# yield i.toFuture
check:
waitFor(test()) == true
# var count = 1
# await stream.forEach(
# proc(item: Future[int]): Future[void] {.async, gcsafe.} =
# check:
# count == await item
# count.inc())
test "filter not empty":
proc test(): Future[bool] {.async.} =
iterator stream(): Future[int] {.closure, gcsafe.} =
for i in @[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
yield i.toFuture
# result = true
await stream
.filter(
proc (item: Future[int]): Future[bool] {.async, gcsafe.} =
result = (await item) mod 2 == 0)
.forEach(
proc(item: Future[int]): Future[void] {.async.} =
check:
(await item) mod 2 == 0)
result = true
# check:
# waitFor(test()) == true
check:
waitFor(test()) == true
# test "map":
# proc test(): Future[bool] {.async.} =
# iterator stream(): Future[char] {.closure, gcsafe.} =
# for i in @['a', 'b', 'c', 'd', 'e']:
# yield i.toFuture
test "filter empty":
proc test(): Future[bool] {.async.} =
iterator stream(): Future[int] {.closure, gcsafe.} =
discard
# var items = @['A', 'B', 'C', 'D', 'E']
# var pos = 0
# await stream
# .map(
# proc(item: Future[char]): Future[char] {.async, gcsafe.} =
# result = (await item).toUpperAscii())
# .forEach(
# proc(item: Future[char]): Future[void] {.async, gcsafe.} =
# check:
# items[pos] == await item
# pos.inc())
await stream
.filter(
proc(item: Future[int]): Future[bool] {.async, gcsafe.} =
discard)
.forEach(
proc(item: Future[int]): Future[void] {.async.} = discard)
result = true
# result = true
check:
waitFor(test()) == true
# check:
# waitFor(test()) == true
test "zip":
proc test(): Future[bool] {.async.} =
var iterable1 = @[1, 2, 3, 4, 5]
iterator stream1(): Future[int] {.closure, gcsafe.} =
for i in iterable1:
yield i.toFuture
# test "filter not empty":
# proc test(): Future[bool] {.async.} =
# iterator stream(): Future[int] {.closure, gcsafe.} =
# for i in @[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
# yield i.toFuture
var iterable2 = @[6, 7, 8]
iterator stream2(): Future[int] {.closure, gcsafe.} =
for i in iterable2:
yield i.toFuture
# await stream
# .filter(
# proc (item: Future[int]): Future[bool] {.async, gcsafe.} =
# result = (await item) mod 2 == 0)
# .forEach(
# proc(item: Future[int]): Future[void] {.async.} =
# check:
# (await item) mod 2 == 0)
# result = true
var count = 0
await stream1
.zip(stream2)
.forEach(
proc(item: Future[(Future[int], Future[int])]):
Future[void] {.async.} =
var (a, b) = await item
check:
iterable1[count] == (await a)
iterable2[count] == (await b)
count.inc())
# check:
# waitFor(test()) == true
result = true
# test "filter empty":
# proc test(): Future[bool] {.async.} =
# iterator stream(): Future[int] {.closure, gcsafe.} =
# discard
check:
waitFor(test()) == true
# await stream
# .filter(
# proc(item: Future[int]): Future[bool] {.async, gcsafe.} =
# discard)
# .forEach(
# proc(item: Future[int]): Future[void] {.async.} = discard)
# result = true
test "slice":
proc test(): Future[bool] {.async.} =
iterator stream(): Future[int] {.closure, gcsafe.} =
for i in @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
yield i.toFuture
# check:
# waitFor(test()) == true
var count = 4
await stream
.slice(4, 8)
.forEach(
proc(item: Future[int]): Future[void] {.async.} =
check:
count == await item
count.inc)
result = true
# test "zip":
# proc test(): Future[bool] {.async.} =
# var iterable1 = @[1, 2, 3, 4, 5]
# iterator stream1(): Future[int] {.closure, gcsafe.} =
# for i in iterable1:
# yield i.toFuture
check:
waitFor(test()) == true
# var iterable2 = @[6, 7, 8]
# iterator stream2(): Future[int] {.closure, gcsafe.} =
# for i in iterable2:
# yield i.toFuture
test "delete":
proc test(): Future[bool] {.async.} =
iterator stream(): Future[int] {.closure, gcsafe.} =
for i in @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
yield i.toFuture
# var count = 0
# await stream1
# .zip(stream2)
# .forEach(
# proc(item: Future[(Future[int], Future[int])]):
# Future[void] {.async.} =
# var (a, b) = await item
# check:
# iterable1[count] == (await a)
# iterable2[count] == (await b)
# count.inc())
var count = 5
await stream
.delete(5, 9)
.forEach(
proc(item: Future[int]): Future[void] {.async.} =
check:
count != await item
count.inc)
# result = true
result = count == 10
# check:
# waitFor(test()) == true
check:
waitFor(test()) == true
# test "slice":
# proc test(): Future[bool] {.async.} =
# iterator stream(): Future[int] {.closure, gcsafe.} =
# for i in @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
# yield i.toFuture
test "foldl":
proc test(): Future[bool] {.async.} =
iterator stream(): Future[int] {.closure, gcsafe.} =
for i in @[1, 2, 3, 4, 5]:
yield i.toFuture
# var count = 4
# await stream
# .slice(4, 8)
# .forEach(
# proc(item: Future[int]): Future[void] {.async.} =
# check:
# count == await item
# count.inc)
# result = true
var count = 1
var res = await stream.foldl(
proc(x: Future[int], y: Future[int]): Future[int] {.async, gcsafe.} =
result = ((await x) + (await y)),
0)
# check:
# waitFor(test()) == true
result = true
# test "delete":
# proc test(): Future[bool] {.async.} =
# iterator stream(): Future[int] {.closure, gcsafe.} =
# for i in @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
# yield i.toFuture
# var count = 5
# await stream
# .delete(5, 9)
# .forEach(
# proc(item: Future[int]): Future[void] {.async.} =
# check:
# count != await item
# count.inc)
# result = count == 10
# check:
# waitFor(test()) == true
# test "foldl":
# proc test(): Future[bool] {.async.} =
# iterator stream(): Future[int] {.closure, gcsafe.} =
# for i in @[1, 2, 3, 4, 5]:
# yield i.toFuture
# var count = 1
# var res = await stream.foldl(
# proc(x: Future[int], y: Future[int]): Future[int] {.async, gcsafe.} =
# result = ((await x) + (await y)),
# 0)
# result = true
# check:
# waitFor(test()) == true
check:
waitFor(test()) == true

View File

@ -8,7 +8,7 @@
## those terms.
import chronos, chronicles
import stream
import stream, asynciters
logScope:
topic = "ChronosStream"
@ -44,7 +44,7 @@ method sink*(c: ChronosStream): Sink[seq[byte]] =
if c.closed:
break
# saddly `await c.writer.write((await chunk))` breaks
# sadly `await c.writer.write((await chunk))` breaks
var cchunk = await chunk
await c.writer.write(cchunk)

View File

@ -9,11 +9,11 @@
import chronos, chronicles, sequtils
import transport,
../wire,
../connection,
../streams/connection,
../multiaddress,
../multicodec,
../stream/chronosstream
../streams/chronosstream,
../wire
logScope:
topic = "TcpTransport"
@ -21,9 +21,8 @@ logScope:
type TcpTransport* = ref object of Transport
server*: StreamServer
proc cleanup(t: Transport, conn: Connection) {.async.} =
await conn.closeEvent.wait()
t.connections.keepItIf(it != conn)
# proc cleanup(t: Transport, conn: Connection) {.async.} =
# t.connections.keepItIf(it != conn)
proc connHandler*(t: Transport,
server: StreamServer,
@ -31,18 +30,18 @@ proc connHandler*(t: Transport,
initiator: bool = false):
Future[Connection] {.async, gcsafe.} =
trace "handling connection for", address = $client.remoteAddress
let conn: Connection = newConnection(newChronosStream(server, client))
conn.observedAddrs = MultiAddress.init(client.remoteAddress)
let conn: Connection = Connection.init(ChronosStream.init(server, client))
conn.observedAddr = MultiAddress.init(client.remoteAddress)
if not initiator:
if not isNil(t.handler):
asyncCheck t.handler(conn)
t.connections.add(conn)
asyncCheck t.cleanup(conn)
# asyncCheck t.cleanup(conn)
result = conn
proc connCb(server: StreamServer,
proc connCallback(server: StreamServer,
client: StreamTransport) {.async, gcsafe.} =
trace "incomming connection for", address = $client.remoteAddress
let t: Transport = cast[Transport](server.udata)
@ -71,7 +70,7 @@ method listen*(t: TcpTransport,
discard await procCall Transport(t).listen(ma, handler) # call base
## listen on the transport
t.server = createStreamServer(t.ma, connCb, {}, t)
t.server = createStreamServer(t.ma, connCallback, {}, t)
t.server.start()
# always get the resolved address in case we're bound to 0.0.0.0:0

View File

@ -9,7 +9,7 @@
import sequtils
import chronos, chronicles
import ../connection,
import ../streams/[connection, stream],
../multiaddress,
../multicodec,
../errors

View File

@ -1,6 +1,6 @@
import unittest
import chronos
import ../libp2p/stream/[lenprefixed, stream]
import ../libp2p/streams/[lenprefixed, stream]
suite "LenPrefixed stream":
test "encode":

View File

@ -1,6 +1,7 @@
import unittest
import chronos
import ../libp2p/[connection,
import ../libp2p/[streams/stream,
streams/connection,
transports/transport,
transports/tcptransport,
multiaddress,
@ -9,127 +10,147 @@ import ../libp2p/[connection,
when defined(nimHasUsed): {.used.}
suite "TCP transport":
test "test listener: handle write":
proc testListener(): Future[bool] {.async, gcsafe.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
result = conn.write(cstring("Hello!"), 6)
# test "test listener: handle write":
# proc test(): Future[bool] {.async.} =
# let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
# proc connHandler(conn: Connection) {.async.} =
# iterator source(): Future[seq[byte]] {.closure.} =
# yield cast[seq[byte]]("Hello!").toFuture
let transport: TcpTransport = newTransport(TcpTransport)
asyncCheck await transport.listen(ma, connHandler)
let streamTransport: StreamTransport = await connect(transport.ma)
let msg = await streamTransport.read(6)
await transport.close()
await streamTransport.closeWait()
# var sink = conn.sink()
# await source.sink()
# await conn.close()
result = cast[string](msg) == "Hello!"
# let transport: TcpTransport = newTransport(TcpTransport)
# var transportFut = await transport.listen(ma, connHandler)
# let streamTransport: StreamTransport = await transport.ma.connect()
# let msg = await streamTransport.read(6)
check:
waitFor(testListener()) == true
# await transport.close()
# await streamTransport.closeWait()
# await transportFut
# result = cast[string](msg) == "Hello!"
# check:
# waitFor(test()) == true
test "test listener: handle read":
proc testListener(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
let msg = await conn.read(6)
check cast[string](msg) == "Hello!"
var source = conn.source()
for item in source:
var msg = await item
let transport: TcpTransport = newTransport(TcpTransport)
asyncCheck await transport.listen(ma, connHandler)
let streamTransport: StreamTransport = await connect(transport.ma)
check:
cast[string](msg) == "Hello!"
let transport = newTransport(TcpTransport)
let transportFut = await transport.listen(ma, connHandler)
let streamTransport = await connect(transport.ma)
let sent = await streamTransport.write("Hello!", 6)
result = sent == 6
await transport.close()
await streamTransport.closeWait()
await transportFut
check:
waitFor(testListener()) == true
test "test dialer: handle write":
proc testDialer(address: TransportAddress): Future[bool] {.async.} =
proc serveClient(server: StreamServer,
transp: StreamTransport) {.async, gcsafe.} =
var wstream = newAsyncStreamWriter(transp)
await wstream.write("Hello!")
await wstream.finish()
await wstream.closeWait()
await transp.closeWait()
server.stop()
server.close()
# test "test dialer handle write":
# proc testDialer(address: TransportAddress): Future[bool] {.async.} =
# proc serveClient(server: StreamServer,
# transp: StreamTransport) {.async, gcsafe.} =
# var wstream = newAsyncStreamWriter(transp)
# await wstream.write("Hello!")
var server = createStreamServer(address, serveClient, {ReuseAddr})
server.start()
# await wstream.finish()
# await wstream.closeWait()
# await transp.closeWait()
# server.stop()
# server.close()
let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress())
let transport: TcpTransport = newTransport(TcpTransport)
let conn = await transport.dial(ma)
let msg = await conn.read(6)
result = cast[string](msg) == "Hello!"
# var server = createStreamServer(address, serveClient)
# server.start()
server.stop()
server.close()
await server.join()
check waitFor(testDialer(initTAddress("0.0.0.0:0"))) == true
# let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress())
# let transport: TcpTransport = newTransport(TcpTransport)
# let conn = await transport.dial(ma)
# let source = conn.source()
# for item in source:
# let msg = await item
# result = cast[string](msg) == "Hello!"
test "test dialer: handle write":
proc testDialer(address: TransportAddress): Future[bool] {.async, gcsafe.} =
proc serveClient(server: StreamServer,
transp: StreamTransport) {.async, gcsafe.} =
var rstream = newAsyncStreamReader(transp)
let msg = await rstream.read(6)
check cast[string](msg) == "Hello!"
# await conn.close()
# server.stop()
# server.close()
# await server.join()
# check:
# waitFor(testDialer(initTAddress("0.0.0.0:0"))) == true
await rstream.closeWait()
await transp.closeWait()
server.stop()
server.close()
# test "test dialer: handle write":
# proc testDialer(address: TransportAddress): Future[bool] {.async, gcsafe.} =
# proc serveClient(server: StreamServer,
# transp: StreamTransport) {.async, gcsafe.} =
# var rstream = newAsyncStreamReader(transp)
# let msg = await rstream.read(6)
# check cast[string](msg) == "Hello!"
var server = createStreamServer(address, serveClient, {ReuseAddr})
server.start()
# await rstream.closeWait()
# await transp.closeWait()
# server.stop()
# server.close()
let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress())
let transport: TcpTransport = newTransport(TcpTransport)
let conn = await transport.dial(ma)
await conn.write(cstring("Hello!"), 6)
result = true
# var server = createStreamServer(address, serveClient, {ReuseAddr})
# server.start()
server.stop()
server.close()
await server.join()
check waitFor(testDialer(initTAddress("0.0.0.0:0"))) == true
# let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress())
# let transport: TcpTransport = newTransport(TcpTransport)
# let conn = await transport.dial(ma)
# await conn.write(cstring("Hello!"), 6)
# result = true
test "e2e: handle write":
proc testListenerDialer(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
result = conn.write(cstring("Hello!"), 6)
# server.stop()
# server.close()
# await server.join()
# check waitFor(testDialer(initTAddress("0.0.0.0:0"))) == true
let transport1: TcpTransport = newTransport(TcpTransport)
asyncCheck await transport1.listen(ma, connHandler)
# test "e2e: handle write":
# proc testListenerDialer(): Future[bool] {.async.} =
# let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
# proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
# result = conn.write(cstring("Hello!"), 6)
let transport2: TcpTransport = newTransport(TcpTransport)
let conn = await transport2.dial(transport1.ma)
let msg = await conn.read(6)
await transport1.close()
# let transport1: TcpTransport = newTransport(TcpTransport)
# asyncCheck await transport1.listen(ma, connHandler)
result = cast[string](msg) == "Hello!"
# let transport2: TcpTransport = newTransport(TcpTransport)
# let conn = await transport2.dial(transport1.ma)
# let msg = await conn.read(6)
# await transport1.close()
check:
waitFor(testListenerDialer()) == true
# result = cast[string](msg) == "Hello!"
test "e2e: handle read":
proc testListenerDialer(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
let msg = await conn.read(6)
check cast[string](msg) == "Hello!"
# check:
# waitFor(testListenerDialer()) == true
let transport1: TcpTransport = newTransport(TcpTransport)
asyncCheck await transport1.listen(ma, connHandler)
# test "e2e: handle read":
# proc testListenerDialer(): Future[bool] {.async.} =
# let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
# proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
# let msg = await conn.read(6)
# check cast[string](msg) == "Hello!"
let transport2: TcpTransport = newTransport(TcpTransport)
let conn = await transport2.dial(transport1.ma)
await conn.write(cstring("Hello!"), 6)
await transport1.close()
result = true
# let transport1: TcpTransport = newTransport(TcpTransport)
# asyncCheck await transport1.listen(ma, connHandler)
check:
waitFor(testListenerDialer()) == true
# let transport2: TcpTransport = newTransport(TcpTransport)
# let conn = await transport2.dial(transport1.ma)
# await conn.write(cstring("Hello!"), 6)
# await transport1.close()
# result = true
# check:
# waitFor(testListenerDialer()) == true