use crate::portpool::ports;
use std::sync::mpsc;
pub enum ReplyMessage {
AllocatePort(u16),
ListAllocations(Vec<ports::UsedPort>),
}
type Reply = Result<ReplyMessage, String>;
pub enum RequestMessage {
AllocatePort {
service_name: String,
user_name: String,
reply_chan: mpsc::Sender<Reply>,
},
FreePort(u16),
ListAllocations(mpsc::Sender<Reply>),
Terminate,
}
pub fn responder(base: u16, num: u16, request_chan: mpsc::Receiver<RequestMessage>) {
let mut pool = ports::PortPool::new(base, num);
loop {
let request = request_chan.recv().unwrap();
match request {
RequestMessage::AllocatePort {
service_name,
user_name,
reply_chan,
} => match pool.allocate(&service_name, &user_name) {
Ok(alloc) => reply_chan
.send(Ok(ReplyMessage::AllocatePort(alloc.port())))
.unwrap(),
Err(msg) => reply_chan.send(Err(msg)).unwrap(),
},
RequestMessage::FreePort(p) => {
let _ = pool.free(p).is_ok(); }
RequestMessage::ListAllocations(reply_chan) => {
reply_chan
.send(Ok(ReplyMessage::ListAllocations(pool.usage())))
.unwrap();
}
RequestMessage::Terminate => break,
}
}
}
pub fn request_port(
service_name: &str,
user_name: &str,
request: &mpsc::Sender<RequestMessage>,
) -> Result<u16, String> {
let (reply_sender, reply_receiver) = mpsc::channel();
request
.send(RequestMessage::AllocatePort {
service_name: String::from(service_name),
user_name: String::from(user_name),
reply_chan: reply_sender,
})
.unwrap();
match reply_receiver.recv().unwrap() {
Ok(msg) => match msg {
ReplyMessage::AllocatePort(port) => Ok(port),
_ => Err(String::from("Invalid reply message type")),
},
Err(msg) => Err(msg),
}
}
pub fn release_port(
port: u16,
request: &mpsc::Sender<RequestMessage>,
) -> Result<(), mpsc::SendError<RequestMessage>> {
request.send(RequestMessage::FreePort(port))
}
pub fn get_allocations(
request: &mpsc::Sender<RequestMessage>,
) -> Result<Vec<ports::UsedPort>, String> {
let (reply_sender, reply_receiver) = mpsc::channel();
request
.send(RequestMessage::ListAllocations(reply_sender))
.unwrap();
match reply_receiver.recv() {
Ok(msg) => match msg {
Ok(replyok) => {
if let ReplyMessage::ListAllocations(allocs) = replyok {
Ok(allocs)
} else {
Err(String::from("Invalid reply from port manager"))
}
}
Err(msg) => Err(msg),
},
Err(msg) => Err(msg.to_string()),
}
}