use super::*; // silly test to make sure that the PDL will never be an issue when doing TCP // stuff with the actual components #[test] fn test_stdlib_file() { compile_and_create_component(" import std.internet as inet; comp fake_listener_once(out tx) { channel cmd_tx -> cmd_rx; channel data_tx -> data_rx; new fake_socket(cmd_rx, data_tx); sync put(tx, inet::TcpConnection{ tx: cmd_tx, rx: data_rx, }); } comp fake_socket(in cmds, out tx) { auto to_send = {}; auto shutdown = false; while (!shutdown) { auto keep_going = true; sync { while (keep_going) { auto cmd = get(cmds); if (let inet::ClientCmd::Send(data) = cmd) { to_send = data; keep_going = false; } else if (let inet::ClientCmd::Receive = cmd) { put(tx, to_send); } else if (let inet::ClientCmd::Finish = cmd) { keep_going = false; } else if (let inet::ClientCmd::Shutdown = cmd) { keep_going = false; shutdown = true; } } } } } comp fake_client(inet::TcpConnection conn) { sync put(conn.tx, inet::ClientCmd::Send({1, 3, 3, 7})); sync { put(conn.tx, inet::ClientCmd::Receive); auto val = get(conn.rx); while (val[0] != 1 || val[1] != 3 || val[2] != 3 || val[3] != 7) { print(\"this is going very wrong\"); } put(conn.tx, inet::ClientCmd::Finish); } sync put(conn.tx, inet::ClientCmd::Shutdown); } comp constructor() { channel conn_tx -> conn_rx; new fake_listener_once(conn_tx); // Same crap as before: channel cmd_tx -> unused_cmd_rx; channel unused_data_tx -> data_rx; auto connection = inet::TcpConnection{ tx: cmd_tx, rx: data_rx }; sync { connection = get(conn_rx); } new fake_client(connection); } ", "constructor", no_args()); } #[test] fn test_tcp_listener_and_client() { compile_and_create_component(" import std.internet::*; func listen_port() -> u16 { return 2393; } comp server(u32 num_connections) { // Start tcp listener channel listen_cmd_tx -> listen_cmd_rx; channel listen_conn_tx -> listen_conn_rx; new tcp_listener({}, listen_port(), listen_cmd_rx, listen_conn_tx); // Fake channels such that we can create a dummy connection variable channel client_cmd_tx -> unused_client_cmd_rx; channel unused_client_data_tx -> client_data_rx; auto new_connection = TcpConnection{ tx: client_cmd_tx, rx: client_data_rx, }; auto connection_counter = 0; while (connection_counter < num_connections) { // Wait until we get a connection print(\"server: waiting for an accepted connection\"); sync { put(listen_cmd_tx, ListenerCmd::Accept); new_connection = get(listen_conn_rx); } // We have a new connection, spawn an 'echoer' for it print(\"server: spawning an echo'ing component\"); new echo_machine(new_connection); connection_counter += 1; } // Shut down the listener print(\"server: shutting down listener\"); } // Waits for a single TCP byte (to simplify potentially having to // concatenate requests) and echos it comp echo_machine(TcpConnection conn) { auto data_to_echo = {}; // Wait for a message sync { print(\"echo: receiving data\"); put(conn.tx, ClientCmd::Receive); data_to_echo = get(conn.rx); put(conn.tx, ClientCmd::Finish); } // Echo the message print(\"echo: sending back data\"); sync put(conn.tx, ClientCmd::Send(data_to_echo)); // Ask the tcp connection to shut down print(\"echo: shutting down\"); sync put(conn.tx, ClientCmd::Shutdown); } comp echo_requester(u8 byte_to_send) { channel cmd_tx -> cmd_rx; channel data_tx -> data_rx; new tcp_client({127, 0, 0, 1}, listen_port(), cmd_rx, data_tx); // Send the message print(\"requester: sending bytes\"); sync put(cmd_tx, ClientCmd::Send({ byte_to_send })); // Receive the echo'd byte auto received_byte = byte_to_send + 1; sync { print(\"requester: receiving echo response\"); put(cmd_tx, ClientCmd::Receive); received_byte = get(data_rx)[0]; put(cmd_tx, ClientCmd::Finish); } // Silly check, as always while (byte_to_send != received_byte) { print(\"requester: Oh no! The echo is an otherworldly distorter\"); } // Shut down the TCP connection print(\"requester: shutting down TCP component\"); sync put(cmd_tx, ClientCmd::Shutdown); } comp constructor() { auto num_connections = 1; new server(num_connections); auto connection_index = 0; while (connection_index < num_connections) { new echo_requester(cast(connection_index)); } } ", "constructor", no_args()); }