Created
September 18, 2014 05:15
-
-
Save jasonprado/0e2595f51541b335fd02 to your computer and use it in GitHub Desktop.
Sketch of an IRC BNC in Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::comm::Sender; | |
use std::io::net::tcp::TcpStream; | |
use std::io::{Listener, Acceptor}; | |
use std::io::net::tcp::TcpListener; | |
use std::io::timer; | |
use std::time::duration::Duration; | |
// A sketch of the architecture for an IRC BNC that supports multiple client connections. | |
// I am curious if this is the optimal way to architect this kind of program. | |
fn main() { | |
// This task simulates an irc server and sends a message every five seconds. | |
// It is presented only to provide a more complete example. | |
spawn(proc() { | |
let mut acceptor = TcpListener::bind("127.0.0.1", 7666).listen().unwrap(); | |
for opt_stream in acceptor.incoming() { | |
spawn(proc() { | |
let mut stream = opt_stream.unwrap(); | |
loop { | |
stream.write_str("msg\n").unwrap(); | |
timer::sleep(Duration::seconds(5)) | |
} | |
}) | |
} | |
}); | |
let (irc_tx, irc_rx) = channel::<String>(); | |
// This task connects to the simulated irc server and reads messages in a loop. It forwards them to the coordinator task. | |
spawn(proc() { | |
let mut stream = TcpStream::connect("127.0.0.1", 7666); | |
loop { | |
let incoming_vec = stream.read_exact(4).unwrap(); | |
let incoming_string = incoming_vec.into_ascii().into_string(); | |
println!("IRC client task got a msg: {}. Forwarding to coordinator.", incoming_string.as_slice().trim_chars('\n')); | |
irc_tx.send(incoming_string); | |
} | |
}); | |
let (coordinator_tx, coordinator_rx) = channel::<Sender<String>>(); | |
// This task receives messages from the irc task and forwards them to client tasks. Client tasks register with this task. | |
spawn(proc() { | |
let mut client_tx_vec: Vec<Sender<String>> = Vec::new(); | |
loop { | |
select! ( | |
incoming_string = irc_rx.recv() => { | |
println!("Coordinator task got a msg: {}. Forwarding to client tasks.", incoming_string.as_slice().trim_chars('\n')); | |
for client_tx in client_tx_vec.iter() { | |
client_tx.send(incoming_string.clone()); | |
} | |
}, | |
new_client_tx = coordinator_rx.recv() => { | |
client_tx_vec.push(new_client_tx) | |
} | |
) | |
} | |
}); | |
// This task serves clients connected to the bnc itself. You can telnet to 9099 with multiple clients and receive the messages. | |
spawn(proc() { | |
let mut acceptor = TcpListener::bind("127.0.0.1", 9099).listen().unwrap(); | |
for opt_stream in acceptor.incoming() { | |
let local_coordinator_tx = coordinator_tx.clone(); | |
spawn(proc() { | |
let (client_tx, client_rx) = channel::<String>(); | |
local_coordinator_tx.send(client_tx); | |
let mut stream = opt_stream.unwrap(); | |
loop { | |
let incoming_string = client_rx.recv(); | |
println!("Client task got a msg: {}. Forwarding to actual client.", incoming_string.as_slice().trim_chars('\n')); | |
stream.write(incoming_string.as_bytes()).unwrap(); | |
} | |
}) | |
} | |
}); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment