use tox_crypto::*;
use tox_packet::relay::*;
use tox_packet::relay::connection_id::ConnectionId;
use crate::relay::links::Links;
use tox_packet::onion::InnerOnionResponse;
use crate::time::*;
use crate::utils::*;
use std::io::{Error, ErrorKind};
use std::net::IpAddr;
use std::time::{Instant, Duration};
use futures::channel::mpsc;
use futures::SinkExt;
pub const TCP_PING_FREQUENCY: Duration = Duration::from_secs(30);
pub const TCP_PING_TIMEOUT: Duration = Duration::from_secs(10);
pub const TCP_SEND_TIMEOUT: Duration = Duration::from_secs(1);
pub struct Client {
pk: PublicKey,
ip_addr: IpAddr,
port: u16,
tx: mpsc::Sender<Packet>,
links: Links,
ping_id: u64,
last_pinged: Instant,
last_pong_resp: Instant
}
impl Client {
pub fn new(tx: mpsc::Sender<Packet>, pk: &PublicKey, ip_addr: IpAddr, port: u16) -> Client {
Client {
pk: *pk,
ip_addr,
port,
tx,
links: Links::new(),
ping_id: 0,
last_pinged: clock_now(),
last_pong_resp: clock_now()
}
}
pub fn pk(&self) -> PublicKey {
self.pk
}
pub fn ip_addr(&self) -> IpAddr {
self.ip_addr
}
pub fn port(&self) -> u16 {
self.port
}
pub fn ping_id(&self) -> u64 {
self.ping_id
}
pub fn set_last_pong_resp(&mut self, time: Instant) {
self.last_pong_resp = time;
}
pub fn is_pong_timedout(&self) -> bool {
clock_elapsed(self.last_pong_resp) > TCP_PING_TIMEOUT + TCP_PING_FREQUENCY
}
pub fn is_ping_interval_passed(&self) -> bool {
clock_elapsed(self.last_pinged) >= TCP_PING_FREQUENCY
}
pub fn links(&self) -> &Links {
&self.links
}
pub fn links_mut(&mut self) -> &mut Links {
&mut self.links
}
async fn send(&self, packet: Packet) -> Result<(), Error> {
let mut tx = self.tx.clone();
let timeout = tokio::time::timeout(
TCP_SEND_TIMEOUT,
tx.send(packet)
);
match timeout.await {
Err(e) => Err(Error::new(
ErrorKind::Other,
format!("Failed to send packet: {:?}", e)
)),
Ok(Err(e)) => Err(Error::new(
ErrorKind::Other,
format!("Failed to send packet: {:?}", e)
)),
Ok(_) => Ok(())
}
}
async fn send_ignore_error(&self, packet: Packet) {
self.send(packet).await.ok();
}
pub async fn send_route_response(&self, pk: &PublicKey, connection_id: ConnectionId) -> Result<(), Error> {
self.send(
Packet::RouteResponse(RouteResponse { connection_id, pk: *pk })
).await
}
pub async fn send_connect_notification(&self, connection_id: ConnectionId) {
self.send_ignore_error(
Packet::ConnectNotification(ConnectNotification { connection_id })
).await;
}
pub async fn send_disconnect_notification(&self, connection_id: ConnectionId) {
self.send_ignore_error(
Packet::DisconnectNotification(DisconnectNotification { connection_id })
).await;
}
pub async fn send_pong_response(&self, ping_id: u64) -> Result<(), Error> {
self.send(
Packet::PongResponse(PongResponse { ping_id })
).await
}
pub async fn send_oob(&self, sender_pk: &PublicKey, data: Vec<u8>) {
self.send_ignore_error(
Packet::OobReceive(OobReceive { sender_pk: *sender_pk, data })
).await;
}
pub async fn send_onion_response(&self, payload: InnerOnionResponse) -> Result<(), Error> {
self.send(
Packet::OnionResponse(OnionResponse { payload })
).await
}
pub async fn send_data(&self, connection_id: ConnectionId, data: DataPayload) -> Result<(), Error> {
self.send(
Packet::Data(Data { connection_id, data })
).await
}
pub async fn send_ping_request(&mut self) -> Result<(), Error> {
let ping_id = gen_ping_id();
self.last_pinged = Instant::now();
self.ping_id = ping_id;
self.send(
Packet::PingRequest(PingRequest { ping_id })
).await
}
}