use crate::{
error::Error,
options::{DatagramOptions, SessionOptions, StreamOptions},
proto::session::SessionController,
style::{
private::{SessionStyle as SealedSessionStyle, Subsession as SealedSubsession},
SessionStyle, Subsession,
},
synchronous::{read_response, stream::Stream},
};
use std::{io::Write, net::TcpStream};
pub mod style;
pub struct Session<S> {
controller: SessionController,
options: SessionOptions,
context: S,
}
impl<S: SessionStyle> Session<S> {
pub fn new(options: SessionOptions) -> crate::Result<Self> {
let mut controller = SessionController::new(options.clone())?;
let mut context = S::new(options.clone())?;
let command = controller.handshake_session()?;
context.write_command(&command)?;
let response = context.read_command()?;
controller.handle_response(&response)?;
let command = controller.create_session(context.create_session())?;
context.write_command(&command)?;
let response = context.read_command()?;
controller.handle_response(&response)?;
Ok(Self {
controller,
options,
context,
})
}
pub fn destination(&self) -> &str {
self.controller.destination()
}
pub fn send_command(&mut self, command: &str) -> crate::Result<String> {
self.context.write_command(command.as_bytes())?;
self.context.read_command()
}
}
impl Session<style::Stream> {
pub fn connect(&mut self, destination: &str) -> crate::Result<Stream> {
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", self.options.samv3_tcp_port))?;
let command = self.controller.handshake_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let command = self.controller.create_stream(&destination, Default::default())?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
Ok(Stream::from_stream(stream, destination.to_string()))
}
pub async fn connect_with_options(
&mut self,
destination: &str,
options: StreamOptions,
) -> crate::Result<Stream> {
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", self.options.samv3_tcp_port))?;
let command = self.controller.handshake_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let command = self.controller.create_stream(&destination, options)?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
Ok(Stream::from_stream(stream, destination.to_string()))
}
pub fn accept(&mut self) -> crate::Result<Stream> {
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", self.options.samv3_tcp_port))?;
let command = self.controller.handshake_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let command = self.controller.accept_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
Ok(Stream::from_stream(stream, response.to_string()))
}
pub fn forward(&mut self, port: u16) -> crate::Result<()> {
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", self.options.samv3_tcp_port))?;
let command = self.controller.handshake_stream()?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
let command = self.controller.forward_stream(port)?;
stream.write_all(&command)?;
let response = read_response(&mut stream).ok_or(Error::Malformed)?;
self.controller.handle_response(&response)?;
style::Stream::store_forwarded(&mut self.context, stream);
Ok(())
}
}
impl Session<style::Repliable> {
pub fn send_to(&mut self, buf: &[u8], destination: &str) -> crate::Result<()> {
style::Repliable::send_to(&mut self.context, buf, destination)
}
pub fn send_to_with_options(
&mut self,
buf: &[u8],
destination: &str,
options: DatagramOptions,
) -> crate::Result<()> {
style::Repliable::send_to_with_options(&mut self.context, buf, destination, options)
}
pub fn recv_from(&mut self, buf: &mut [u8]) -> crate::Result<(usize, String)> {
style::Repliable::recv_from(&mut self.context, buf)
}
}
impl Session<style::Anonymous> {
pub fn send_to(&mut self, buf: &[u8], destination: &str) -> crate::Result<()> {
style::Anonymous::send_to(&mut self.context, buf, destination)
}
pub fn send_to_with_options(
&mut self,
buf: &[u8],
destination: &str,
options: DatagramOptions,
) -> crate::Result<()> {
style::Anonymous::send_to_with_options(&mut self.context, buf, destination, options)
}
pub fn recv(&mut self, buf: &mut [u8]) -> crate::Result<usize> {
style::Anonymous::recv(&mut self.context, buf)
}
}
impl Session<style::Primary> {
pub fn create_subsession<S: Subsession>(
&mut self,
options: SessionOptions,
) -> crate::Result<Session<S>> {
let session = <S as SealedSubsession>::new(options.clone())?;
let parameters = <S as SealedSessionStyle>::create_session(&session);
let command = self.controller.create_subsession(&options.nickname, parameters)?;
self.context.write_command(&command)?;
let response = self.context.read_command()?;
self.controller.handle_response(&response)?;
Ok(Session {
context: session,
options: options.clone(),
controller: self.controller.new_for_subsession(options),
})
}
}