exchange.nct
see ./index.nct
use std/io.{Reader, Writer}
use std/io/buffer.{BufReader, BufWriter}
use std/net
use std/net.{IpAddress, Ipv4Address, SocketAddress}
use std/task
use std/task.Timeout
use std/time.Duration
struct ExchangeComplete {}
func loopback(): SocketAddress {
return SocketAddress.new(IpAddress.from_ipv4(Ipv4Address.loopback()), 0)
}
async func serve(stream: net.TcpStream): ExchangeComplete! {
var input = BufReader.with_capacity(move stream, 3)
let request_line = await input.read_line()? otherwise {
return error.new("async-loopback.request_eof", "client closed before one request line")
}
if request_line != "ping" {
return error.new("async-loopback.request", "server received an unexpected request line")
}
let response_stream = input.finish()
var output = BufWriter.with_capacity(move response_stream, 2)
await output.write_line("pong")?
var completed_stream = await output.finish()?
completed_stream.close()
return ExchangeComplete {}
}
async func exchange_request(stream: net.TcpStream): ExchangeComplete! {
var output = BufWriter.with_capacity(move stream, 2)
await output.write_line("ping")?
let response_stream = await output.finish()?
var input = BufReader.with_capacity(move response_stream, 3)
let response = await input.read_line()? otherwise {
return error.new("async-loopback.response_eof", "server closed before one response line")
}
if response != "pong" {
return error.new("async-loopback.response", "client received an unexpected response line")
}
var completed_stream = input.finish()
completed_stream.close()
return ExchangeComplete {}
}
async func run(): i32! {
let timeout = Duration.from_seconds(1)
var listener = await net.bind_tcp(loopback())?
let listening_address = listener.local_address()?
let connection = await task.join(
net.connect_tcp_with_timeout(listening_address, timeout),
listener.accept_with_timeout(timeout),
)
let client_result = move connection.0
let accepted_result = move connection.1
let client = move client_result?
let accepted = move accepted_result?
let exchange = await task.with_timeout(
task.join(exchange_request(move client), serve(move accepted.0)),
timeout,
)
match move exchange {
Timeout.completed(results) {
let exchange_client_result = move results.0
let server_result = move results.1
let _client = move exchange_client_result?
let _server = move server_result?
return 0
}
Timeout.elapsed {
return error.new("async-loopback.timeout", "buffered line exchange timed out")
}
}
}