1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
//! //! Reactor is based around two notions, an event loop (Reactor) and a Context, which is the main //! mailbox handler for a connection (or datagram receiver). A context is also the manager of the //! socket abstraction itself. Reactor offers utilities to make working with these easier, but the //! actual creation and interaction with the socket is out of the purview of reactor and is owned //! entirely by the Context impl. //! //! # Example //! //! In this example, we create two Socket Contexts, one for the client connection, ClientConn, and one //! for the accepting side of the connection, ServConn. //! listen() takes a handler which we use to create the server side of the connection, when we //! receive the connection, we start a timer for that connection, which we handle in the context's //! mailbox. The timer event will keep reregistering itself unless the count has reached 5, at //! which point it shuts down the event_loop and the program ends. //! //! Connect also takes a handler, which we use to construct the Client context when the connection //! completes. //! //!``` //! //! #![feature(slice_bytes)] //! //! extern crate reactor; //! //! use std::slice::bytes::copy_memory; //! use std::string::String; //! use std::io::{Read, Write}; //! use reactor::{ReactorCtrl, //! Reactor, //! ConnResult, //! Evented, //! EventSet, //! Context, //! EventType, //! Token}; //! //! use reactor::tcp::{TcpStream}; //! //! //!struct ClientConn { //! interest: EventSet, //! sock : TcpStream, //! token : Token //!} //! //!impl Context for ClientConn { //! //! //the event handler for the client connection, for this example, //! // we only care about readable events, we ignore the rest //! fn on_event(&mut self, ctrl : &mut ReactorCtrl, evt : EventType) { //! match evt { //! EventType::Readable => { //! let mut buf : [u8; 5] = [0; 5]; //! let num = self.sock.read(&mut buf).unwrap(); //! if num == 5 { //! let msg = String::from_utf8_lossy(&buf).into_owned(); //! //! if msg == "PING!" { //! copy_memory("PONG!".as_bytes(), &mut buf); //! self.sock.write(&buf).unwrap(); //! } //! } //! }, //! _ => {} //! } //! } //! //! fn get_evented(&self) -> &Evented { //! &self.sock as &Evented //! } //! //! fn get_interest(&self) -> EventSet { //! self.interest //! } //!} //! //!struct ServConn { //! interest: EventSet, //! sock : TcpStream, //! token : Token, //! count : u32, //!} //! //!// here we indicate that we wish to handle only Timeout and Readable //!// events, and ignore the rest //!impl Context for ServConn { //! fn on_event(&mut self, ctrl : &mut ReactorCtrl, evt : EventType) { //! match evt { //! EventType::Timeout(_) => { //! if self.count < 5 { //! let mut buf : [u8; 5] = [0; 5]; //! copy_memory("PING!".as_bytes(), &mut buf); //! self.sock.write(&buf).unwrap(); //! self.count += 1; //! ctrl.timeout_conn(1000, self.token).unwrap(); //! } //! else { //! ctrl.shutdown(); //! } //! }, //! EventType::Readable => { //! let mut buf : [u8; 5] = [0; 5]; //! let num = self.sock.read(&mut buf).unwrap(); //! let msg = String::from_utf8_lossy(&buf).into_owned(); //! assert!(msg == "PONG!"); //! }, //! _ => {} //! } //! } //! //! fn get_evented(&self) -> &Evented { //! &self.sock as &Evented //! } //! //! fn get_interest(&self) -> EventSet { //! self.interest //! } //!} //!fn main() { //! let mut client : Option<Token> = None; //! let mut server : Option<Token> = None; //! let mut r = Reactor::new(); //! //! //in order to listen, we must be prepared to create new connections //! //the handler for listen provides a socket a token, and the peer address //! //we then return an instance of Context of our choosing, in this case //! //we want to handle each inbound connection with an instance of ServConn //! let _ltoken = r.listen("127.0.0.1:10000", Box::new(|res, ctrl| { //! match res { //! ConnResult::Connected(sock, tok, addr) => { //! println!("Connection request from {}", addr); //! server = Some(tok); //! //! //We've received a connection. Initiate PINGPONG protocol in 1 second //! ctrl.timeout_conn(1000, tok).unwrap(); //! //! Some(Box::new(ServConn { //! interest: EventSet::readable(), //! token: tok.clone(), //! sock: sock, //! count: 0})) //! }, //! _ => {panic!("We shouldn't be here")} //! } //! })).unwrap(); //! //! println!("Connecting to localhost"); //! //! //Like listen, connect requires that we specify how to create an instance of //! //Context when we successfully complete our connection. In this case we create //! //an instance of ClientConn //! r.connect("localhost", 10000, Box::new(|res, _ctrl| { //! match res { //! ConnResult::Connected(sock, tok, addr) => { //! println!("Completing connection to {}", addr); //! client = Some(tok); //! Some(Box::new(ClientConn { //! interest: EventSet::readable(), //! token: tok.clone(), //! sock: sock, //! })) //! }, //! ConnResult::Failed(err) => {panic!("Failed to connect to localhost:10000 error: {}", err)} //! } //! })).unwrap(); //! //! //block while running the event loop until it is terminated //! r.run(); //! //!} //! //!``` //! //! #![feature(lookup_host)] #[macro_use] extern crate log; extern crate mio; extern crate tendril; mod context; mod reactor; mod reactor_ctrl; mod reactor_handler; pub mod utils; pub use mio::{EventSet, Evented, Token}; pub use mio::tcp; pub use mio::udp; pub use reactor::Reactor; pub use context::{Context, EventType}; pub use reactor_ctrl::{ ReactorCtrl, ConnHandler, ConnResult, TimeoutHandler, ListenRec, TimerRec};