Skip to content

Instantly share code, notes, and snippets.

@jasonprado
Created September 18, 2014 05:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasonprado/0e2595f51541b335fd02 to your computer and use it in GitHub Desktop.
Save jasonprado/0e2595f51541b335fd02 to your computer and use it in GitHub Desktop.
Sketch of an IRC BNC in Rust
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