#![allow(clippy::type_complexity, dead_code)] use mpstthree::binary::struct_trait::{end::End, recv::Recv, send::Send}; use mpstthree::generate; use mpstthree::role::broadcast::RoleBroadcast; use mpstthree::role::end::RoleEnd; use std::error::Error; use rand::{thread_rng, Rng}; // Create roles and implementations generate!( "rec_and_cancel", MeshedChannels, Client, ProxyOne, ProxyTwo, Server ); // Payload types // Request by the client // We embed the method directly // in the label of the message struct OpenTCPConnection; struct RequestGet { // method: String, version_protocol: i32, header: String, } struct RequestPost { // method: String, version_protocol: i32, header: String, } struct RequestPut { // method: String, version_protocol: i32, header: String, } // Response by the server // We embed the status directly // in the label of the message struct Response200 { version_protocol: i32, // status_code: String, status_message: String, header: String, } struct Response404 { version_protocol: i32, // status_code: String, status_message: String, header: String, } struct Response418 { version_protocol: i32, // status_code: String, status_message: String, header: String, } struct Fail; struct Success; struct Close; // Binary types // Client thread // Try to open TCP communication type ClientToProxyOneTCP = Send; // Send OpenTCPConnection to ProxyOne type ClientToProxyTwoTCP = End; // No communications with ProxyTwo type ClientToServerTCP = Recv; // Receive choice from Server // For ProxyOne enum RequestByClientToProxyOne { RequestGet( MeshedChannels< Recv, // Receive request from Client Send, // Forward request to ProxyTwo Recv, // Receive choice from Server RoleClient>>, NameProxyOne, >, ), RequestPut( MeshedChannels< Recv, // Receive request from Client Send, // Forward request to ProxyTwo Recv, // Receive choice from Server RoleClient>>, NameProxyOne, >, ), RequestPost( MeshedChannels< Recv, // Receive request from Client Send, // Forward request to ProxyTwo Recv, // Receive choice from Server RoleClient>>, NameProxyOne, >, ), Close( MeshedChannels< Recv, // Receive Close from Client Send, // Forward Close to ProxyTwo End, // No communication with Server RoleClient>, NameProxyOne, >, ), } // For ProxyTwo enum RequestByClientToProxyTwo { RequestGet( MeshedChannels< End, // No communication with Client Recv, // Receive request from ProxyOne Send>, // Forward request to Server and receive choice from Server RoleProxyOne>>, NameProxyTwo, >, ), RequestPut( MeshedChannels< End, // No communication with Client Recv, // Receive request from ProxyOne Send>, // Forward request to Server and receive choice from Server RoleProxyOne>>, NameProxyTwo, >, ), RequestPost( MeshedChannels< End, // No communication with Client Recv, // Receive request from ProxyOne Send>, // Forward request to Server and receive choice from Server RoleProxyOne>>, NameProxyTwo, >, ), Close( MeshedChannels< End, // No communication with Client Recv, // Receive Close from ProxyOne Send, // Forward Close to Server RoleProxyOne>, NameProxyTwo, >, ), } // For Server enum RequestByClientToServer { RequestGet( MeshedChannels< Send, // Send choice to Client Send, // Send choice to ProxyOne Recv>, // Receive request from ProxyTwo and send choice to ProxyTwo RoleProxyTwo, NameServer, >, ), RequestPut( MeshedChannels< Send, // Send choice to Client Send, // Send choice to ProxyOne Recv>, // Receive request from ProxyTwo and send choice to ProxyTwo RoleProxyTwo, NameServer, >, ), RequestPost( MeshedChannels< Send, // Send choice to Client Send, // Send choice to ProxyOne Recv>, // Receive request from ProxyTwo and send choice to ProxyTwo RoleProxyTwo, NameServer, >, ), Close( MeshedChannels< End, End, Recv, // Receive Close from ProxyTwo RoleProxyTwo, NameServer, >, ), } // ProxyOne thread // Open TCP communication by Client type ProxyOneToClientTCP = Recv; // Receive OpenTCPConnection from Client type ProxyOneToProxyTwoTCP = Send; // Forward OpenTCPConnection to ProxyTwo type ProxyOneToServerTCP = Recv; // Receive choice from Server // ProxyTwo thread type ProxyTwoToClientTCP = End; // No communication with Client type ProxyTwoToProxyOneTCP = Recv; // Receive OpenTCPConnection from ProxyOne type ProxyTwoToServerTCP = Send>; // Forward OpenTCPConnection to Server and receive choice // Server thread type ServerToClientTCP = Send; // Send choice to Client type ServerToProxyOneTCP = Send; // Send choice to ProxyOne type ServerToProxyTwoTCP = Recv>; // Receive OpenTCPConnection from ProxyTwo and send choice // Answer to OpenTCPConnection // For Client enum OpenTCPConnectionByServerToClient { Fail( MeshedChannels< Recv, // Recv Fail from ProxyOne End, // No communication with ProxyTwo End, // No communication with Server RoleProxyOne, NameClient, >, ), Success( MeshedChannels< Recv>, // Recv Success from ProxyOne and send choice Send, // Send choice to ProxyTwo Send, // Send choice to Server RoleProxyOne, NameClient, >, ), } // For ProxyOne enum OpenTCPConnectionByServerToProxyOne { Fail( MeshedChannels< Send, // Forward Fail to Client Recv, // Recv Fail from ProxyTwo End, // End connection RoleProxyTwo>, NameProxyOne, >, ), Success( MeshedChannels< Send>, // Forward Success to Client and receive choice Recv, // Receive choice from ProxyTwo End, // No communication with Server RoleProxyTwo>>, NameProxyOne, >, ), } // For ProxyTwo enum OpenTCPConnectionByServerToProxyTwo { Fail( MeshedChannels< End, // No communication with Client Send, // Forward Fail from Server Recv, // Recv Fail from Server RoleServer>, NameProxyTwo, >, ), Success( MeshedChannels< Recv, // Receive choice from Client Send, // Forward Success to ProxyOne Recv, // Receive Success from Server RoleServer>>, NameProxyTwo, >, ), } // Answer to Resquest / Send Response // For Client enum ResponseByServerToClient { Response200( MeshedChannels< Recv>, // Receive Response200 from ProxyOne and send choice Send, // Send choice to ProxyTwo Send, // Send choice to Server RoleProxyOne, NameClient, >, ), Response404( MeshedChannels< Recv>, // Receive Response404 from ProxyOne and send choice Send, // Send choice to ProxyTwo Send, // Send choice to Server RoleProxyOne, NameClient, >, ), Response418( MeshedChannels< Recv>, // Receive Response418 from ProxyOne and send choice Send, // Send choice to ProxyTwo Send, // Send choice to Server RoleProxyOne, NameClient, >, ), } // For ProxyOne enum ResponseByServerToProxyOne { Response200( MeshedChannels< Send>, // Forward Response200 to Client ProxyOne and receive choice Recv, // Receive Response200 from ProxyTwo End, // No communication with Server RoleProxyTwo>>, NameProxyOne, >, ), Response404( MeshedChannels< Send>, // Forward Response404 to Client ProxyOne and receive choice Recv, // Receive Response404 from ProxyTwo End, // No communication with Server RoleProxyTwo>>, NameProxyOne, >, ), Response418( MeshedChannels< Send>, // Forward Response418 to Client ProxyOne and receive choice Recv, // Receive Response418 from ProxyTwo End, // No communication with Server RoleProxyTwo>>, NameProxyOne, >, ), } // For ProxyTwo enum ResponseByServerToProxyTwo { Response200( MeshedChannels< Recv, // Receive choice from Client Send, // Forward Response200 to ProxyOne Recv, // Receive Response200 from Server RoleServer>>, NameProxyTwo, >, ), Response404( MeshedChannels< Recv, // Receive choice from Client Send, // Forward Response404 to ProxyOne Recv, // Receive Response404 from Server RoleServer>>, NameProxyTwo, >, ), Response418( MeshedChannels< Recv, // Receive choice from Client Send, // Forward Response418 to ProxyOne Recv, // Receive Response418 from Server RoleServer>>, NameProxyTwo, >, ), } // Orderings type OrderingClient = RoleProxyOne>; type OrderingProxyOne = RoleClient>>; type OrderingProxyTwo = RoleProxyOne>>; type OrderingServer = RoleProxyTwo; // MeshedChannels // CLient type EndpointClient = MeshedChannels< ClientToProxyOneTCP, ClientToProxyTwoTCP, ClientToServerTCP, OrderingClient, NameClient, >; type RecursClient = MeshedChannels< Send, Send, Send, RoleBroadcast, NameClient, >; type EndpointClientClose = MeshedChannels, End, End, RoleProxyOne, NameClient>; type EndpointClientRequestGet = MeshedChannels< Send, End, Recv, RoleProxyOne>, NameClient, >; type EndpointClientRequestPut = MeshedChannels< Send, End, Recv, RoleProxyOne>, NameClient, >; type EndpointClientRequestPost = MeshedChannels< Send, End, Recv, RoleProxyOne>, NameClient, >; // ProxyOne type EndpointProxyOne = MeshedChannels< ProxyOneToClientTCP, ProxyOneToProxyTwoTCP, ProxyOneToServerTCP, OrderingProxyOne, NameProxyOne, >; type RecursProxyOne = MeshedChannels< Recv, End, End, RoleClient, NameProxyOne, >; // ProxyTwo type EndpointProxyTwo = MeshedChannels< ProxyTwoToClientTCP, ProxyTwoToProxyOneTCP, ProxyTwoToServerTCP, OrderingProxyTwo, NameProxyTwo, >; type RecursProxyTwo = MeshedChannels< Recv, End, End, RoleClient, NameProxyTwo, >; // Server type EndpointServer = MeshedChannels< ServerToClientTCP, ServerToProxyOneTCP, ServerToProxyTwoTCP, OrderingServer, NameServer, >; type EndpointServerFail = MeshedChannels, RoleProxyTwo, NameServer>; type EndpointServerSuccess = MeshedChannels< Recv, End, Send, RoleProxyTwo>, NameServer, >; type RecursServer = MeshedChannels, End, End, RoleClient, NameServer>; type EndpointServerResponse200 = MeshedChannels< Recv, End, Send, RoleProxyTwo>, NameServer, >; type EndpointServerResponse404 = MeshedChannels< Recv, End, Send, RoleProxyTwo>, NameServer, >; type EndpointServerResponse418 = MeshedChannels< Recv, End, Send, RoleProxyTwo>, NameServer, >; // Functions ///////////////////////// // Functions related to endpoints fn endpoint_client(s: EndpointClient) -> Result<(), Box> { let s = s.send(OpenTCPConnection {})?; offer_mpst!(s, { OpenTCPConnectionByServerToClient::Fail(s) => { let (_, s) = s.recv()?; s.close() }, OpenTCPConnectionByServerToClient::Success(s) => { let (_, s) = s.recv()?; recurs_client(s, 100) }, }) } // Functions related to endpoints fn recurs_client(s: RecursClient, loops: i32) -> Result<(), Box> { if loops == 0 { let s: EndpointClientClose = choose_mpst_client_to_all!( s, RequestByClientToProxyOne::Close, RequestByClientToProxyTwo::Close, RequestByClientToServer::Close ); let s = s.send(Close {})?; s.close() } else { match thread_rng().gen_range(1..3) { 1 => { let s: EndpointClientRequestGet = choose_mpst_client_to_all!( s, RequestByClientToProxyOne::RequestGet, RequestByClientToProxyTwo::RequestGet, RequestByClientToServer::RequestGet ); let s = s.send(RequestGet { version_protocol: 5, header: String::from("GET"), })?; offer_mpst!(s, { ResponseByServerToClient::Response200(s) => { let (_, s) = s.recv()?; recurs_client(s, loops -1) }, ResponseByServerToClient::Response404(s) => { let (_, s) = s.recv()?; recurs_client(s, loops -1) }, ResponseByServerToClient::Response418(s) => { let (_, s) = s.recv()?; recurs_client(s, loops -1) }, }) } 2 => { let s: EndpointClientRequestPut = choose_mpst_client_to_all!( s, RequestByClientToProxyOne::RequestPut, RequestByClientToProxyTwo::RequestPut, RequestByClientToServer::RequestPut ); let s = s.send(RequestPut { version_protocol: 5, header: String::from("PUT"), })?; offer_mpst!(s, { ResponseByServerToClient::Response200(s) => { let (_, s) = s.recv()?; recurs_client(s, loops -1) }, ResponseByServerToClient::Response404(s) => { let (_, s) = s.recv()?; recurs_client(s, loops -1) }, ResponseByServerToClient::Response418(s) => { let (_, s) = s.recv()?; recurs_client(s, loops -1) }, }) } 3 => { let s: EndpointClientRequestPost = choose_mpst_client_to_all!( s, RequestByClientToProxyOne::RequestPost, RequestByClientToProxyTwo::RequestPost, RequestByClientToServer::RequestPost ); let s = s.send(RequestPost { version_protocol: 5, header: String::from("POST"), })?; offer_mpst!(s, { ResponseByServerToClient::Response200(s) => { let (_, s) = s.recv()?; recurs_client(s, loops -1) }, ResponseByServerToClient::Response404(s) => { let (_, s) = s.recv()?; recurs_client(s, loops -1) }, ResponseByServerToClient::Response418(s) => { let (_, s) = s.recv()?; recurs_client(s, loops -1) }, }) } _ => panic!("Error, unexpected input"), } } } ///////////////////////// fn endpoint_proxyone(s: EndpointProxyOne) -> Result<(), Box> { let (opentcpconnection, s) = s.recv()?; let s = s.send(opentcpconnection)?; offer_mpst!(s, { OpenTCPConnectionByServerToProxyOne::Fail(s) => { let (fail, s) = s.recv()?; let s = s.send(fail)?; s.close() }, OpenTCPConnectionByServerToProxyOne::Success(s) => { let (fail, s) = s.recv()?; let s = s.send(fail)?; recurs_proxyone(s) }, }) } fn recurs_proxyone(s: RecursProxyOne) -> Result<(), Box> { offer_mpst!(s, { RequestByClientToProxyOne::RequestGet(s) => { let (request, s) = s.recv()?; let s = s.send(request)?; offer_mpst!(s, { ResponseByServerToProxyOne::Response200(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxyone(s) }, ResponseByServerToProxyOne::Response404(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxyone(s) }, ResponseByServerToProxyOne::Response418(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxyone(s) }, }) }, RequestByClientToProxyOne::RequestPut(s) => { let (request, s) = s.recv()?; let s = s.send(request)?; offer_mpst!(s, { ResponseByServerToProxyOne::Response200(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxyone(s) }, ResponseByServerToProxyOne::Response404(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxyone(s) }, ResponseByServerToProxyOne::Response418(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxyone(s) }, }) }, RequestByClientToProxyOne::RequestPost(s) => { let (request, s) = s.recv()?; let s = s.send(request)?; offer_mpst!(s, { ResponseByServerToProxyOne::Response200(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxyone(s) }, ResponseByServerToProxyOne::Response404(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxyone(s) }, ResponseByServerToProxyOne::Response418(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxyone(s) }, }) }, RequestByClientToProxyOne::Close(s) => { let (request, s) = s.recv()?; let s = s.send(request)?; s.close() }, }) } ///////////////////////// fn endpoint_proxytwo(s: EndpointProxyTwo) -> Result<(), Box> { let (opentcpconnection, s) = s.recv()?; let s = s.send(opentcpconnection)?; offer_mpst!(s, { OpenTCPConnectionByServerToProxyTwo::Fail(s) => { let (fail, s) = s.recv()?; let s = s.send(fail)?; s.close() }, OpenTCPConnectionByServerToProxyTwo::Success(s) => { let (fail, s) = s.recv()?; let s = s.send(fail)?; recurs_proxytwo(s) }, }) } fn recurs_proxytwo(s: RecursProxyTwo) -> Result<(), Box> { offer_mpst!(s, { RequestByClientToProxyTwo::RequestGet(s) => { let (request, s) = s.recv()?; let s = s.send(request)?; offer_mpst!(s, { ResponseByServerToProxyTwo::Response200(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxytwo(s) }, ResponseByServerToProxyTwo::Response404(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxytwo(s) }, ResponseByServerToProxyTwo::Response418(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxytwo(s) }, }) }, RequestByClientToProxyTwo::RequestPut(s) => { let (request, s) = s.recv()?; let s = s.send(request)?; offer_mpst!(s, { ResponseByServerToProxyTwo::Response200(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxytwo(s) }, ResponseByServerToProxyTwo::Response404(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxytwo(s) }, ResponseByServerToProxyTwo::Response418(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxytwo(s) }, }) }, RequestByClientToProxyTwo::RequestPost(s) => { let (request, s) = s.recv()?; let s = s.send(request)?; offer_mpst!(s, { ResponseByServerToProxyTwo::Response200(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxytwo(s) }, ResponseByServerToProxyTwo::Response404(s) => { let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxytwo(s) }, ResponseByServerToProxyTwo::Response418(s) => { println!("ProxyTwo Request GET"); let (response, s) = s.recv()?; let s = s.send(response)?; recurs_proxytwo(s) }, }) }, RequestByClientToProxyTwo::Close(s) => { let (request, s) = s.recv()?; let s = s.send(request)?; s.close() }, }) } ///////////////////////// fn endpoint_server(s: EndpointServer) -> Result<(), Box> { let (_, s) = s.recv()?; // 10 percent chance of failure match thread_rng().gen_range(1..10) { 1 => { let s: EndpointServerFail = choose_mpst_server_to_all!( s, OpenTCPConnectionByServerToClient::Fail, OpenTCPConnectionByServerToProxyOne::Fail, OpenTCPConnectionByServerToProxyTwo::Fail ); let s = s.send(Fail {})?; s.close() } _ => { let s: EndpointServerSuccess = choose_mpst_server_to_all!( s, OpenTCPConnectionByServerToClient::Success, OpenTCPConnectionByServerToProxyOne::Success, OpenTCPConnectionByServerToProxyTwo::Success ); let s = s.send(Success {})?; recurs_server(s) } } } fn recurs_server(s: RecursServer) -> Result<(), Box> { offer_mpst!(s, { RequestByClientToServer::RequestGet(s) => { let (_, s) = s.recv()?; match thread_rng().gen_range(1..3) { 1 => { let s: EndpointServerResponse200 = choose_mpst_server_to_all!( s, ResponseByServerToClient::Response200, ResponseByServerToProxyOne::Response200, ResponseByServerToProxyTwo::Response200 ); let s = s.send(Response200 { version_protocol: 5, status_message: String::from("OK"), header: String::from("200") })?; recurs_server(s) } 2 => { let s: EndpointServerResponse404 = choose_mpst_server_to_all!( s, ResponseByServerToClient::Response404, ResponseByServerToProxyOne::Response404, ResponseByServerToProxyTwo::Response404 ); let s = s.send(Response404 { version_protocol: 5, status_message: String::from("Resource not found"), header: String::from("404") })?; recurs_server(s) } 3 => { let s: EndpointServerResponse418 = choose_mpst_server_to_all!( s, ResponseByServerToClient::Response418, ResponseByServerToProxyOne::Response418, ResponseByServerToProxyTwo::Response418 ); let s = s.send(Response418 { version_protocol: 5, status_message: String::from("I'm a tea pot"), header: String::from("418") })?; recurs_server(s) } _ => panic!("Error, unexpected number") } }, RequestByClientToServer::RequestPut(s) => { let (_, s) = s.recv()?; match thread_rng().gen_range(1..3) { 1 => { let s: EndpointServerResponse200 = choose_mpst_server_to_all!( s, ResponseByServerToClient::Response200, ResponseByServerToProxyOne::Response200, ResponseByServerToProxyTwo::Response200 ); let s = s.send(Response200 { version_protocol: 5, status_message: String::from("OK"), header: String::from("200") })?; recurs_server(s) } 2 => { let s: EndpointServerResponse404 = choose_mpst_server_to_all!( s, ResponseByServerToClient::Response404, ResponseByServerToProxyOne::Response404, ResponseByServerToProxyTwo::Response404 ); let s = s.send(Response404 { version_protocol: 5, status_message: String::from("Resource not found"), header: String::from("404") })?; recurs_server(s) } 3 => { let s: EndpointServerResponse418 = choose_mpst_server_to_all!( s, ResponseByServerToClient::Response418, ResponseByServerToProxyOne::Response418, ResponseByServerToProxyTwo::Response418 ); let s = s.send(Response418 { version_protocol: 5, status_message: String::from("I'm a tea pot"), header: String::from("418") })?; recurs_server(s) } _ => panic!("Error, unexpected number") } }, RequestByClientToServer::RequestPost(s) => { let (_, s) = s.recv()?; match thread_rng().gen_range(1..3) { 1 => { let s: EndpointServerResponse200 = choose_mpst_server_to_all!( s, ResponseByServerToClient::Response200, ResponseByServerToProxyOne::Response200, ResponseByServerToProxyTwo::Response200 ); let s = s.send(Response200 { version_protocol: 5, status_message: String::from("OK"), header: String::from("200") })?; recurs_server(s) } 2 => { let s: EndpointServerResponse404 = choose_mpst_server_to_all!( s, ResponseByServerToClient::Response404, ResponseByServerToProxyOne::Response404, ResponseByServerToProxyTwo::Response404 ); let s = s.send(Response404 { version_protocol: 5, status_message: String::from("Resource not found"), header: String::from("404") })?; recurs_server(s) } 3 => { let s: EndpointServerResponse418 = choose_mpst_server_to_all!( s, ResponseByServerToClient::Response418, ResponseByServerToProxyOne::Response418, ResponseByServerToProxyTwo::Response418 ); let s = s.send(Response418 { version_protocol: 5, status_message: String::from("I'm a tea pot"), header: String::from("418") })?; recurs_server(s) } _ => panic!("Error, unexpected number") } }, RequestByClientToServer::Close(s) => { let (_, s) = s.recv()?; s.close() }, }) } //////////////////////////////////////// fn main() { let (thread_client, thread_proxyone, thread_proxytwo, thread_server) = fork_mpst( endpoint_client, endpoint_proxyone, endpoint_proxytwo, endpoint_server, ); thread_client.join().unwrap(); thread_proxyone.join().unwrap(); thread_proxytwo.join().unwrap(); thread_server.join().unwrap(); }