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};