This commit is contained in:
lubeilin
2023-03-10 23:01:57 +08:00
parent ebf84db204
commit 5b2c2435d5
39 changed files with 2493 additions and 2552 deletions
+43 -5
View File
@@ -2,15 +2,17 @@ use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::time::Duration;
use crate::command::entity::{DeviceItem, RouteItem, Status};
pub struct CommandClient {
udp: UdpSocket,
}
impl CommandClient {
pub fn new() -> io::Result<Self> {
let port = crate::config::read_command_port().unwrap();
let port = crate::config::read_command_port()?;
let udp = UdpSocket::bind("127.0.0.1:0")?;
udp.set_read_timeout(Some(Duration::from_secs(5)))?;
udp.set_read_timeout(Some(Duration::from_secs(2)))?;
udp.connect(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::new(127, 0, 0, 1),
port,
@@ -20,16 +22,52 @@ impl CommandClient {
}
impl CommandClient {
pub fn list(&self) -> io::Result<String> {
pub fn list(&self) -> io::Result<Vec<DeviceItem>> {
self.udp.send(b"list")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
Ok(String::from_utf8(buf[..len].to_vec()).unwrap())
match serde_json::from_slice::<Vec<DeviceItem>>(&buf[..len]) {
Ok(val) => {
Ok(val)
}
Err(e) => {
log::error!("{:?}",e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
}
}
}
pub fn status(&self) -> io::Result<String> {
pub fn route(&self) -> io::Result<Vec<RouteItem>> {
self.udp.send(b"route")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Vec<RouteItem>>(&buf[..len]) {
Ok(val) => {
Ok(val)
}
Err(e) => {
log::error!("{:?}",e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
}
}
}
pub fn status(&self) -> io::Result<Status> {
self.udp.send(b"status")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Status>(&buf[..len]) {
Ok(val) => {
Ok(val)
}
Err(e) => {
log::error!("{:?},{:?}",&buf[..len],e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
}
}
}
pub fn stop(&self) -> io::Result<String> {
self.udp.send(b"stop")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
Ok(String::from_utf8(buf[..len].to_vec()).unwrap())
}
}
+34
View File
@@ -0,0 +1,34 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct Status {
pub name: String,
pub virtual_ip: String,
pub virtual_gateway: String,
pub virtual_netmask: String,
pub connect_status: String,
pub relay_server: String,
pub nat_type: String,
pub public_ips: String,
pub local_ip: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct RouteItem {
pub destination: String,
pub next_hop: String,
pub metric: String,
pub rt: String,
pub interface: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DeviceItem {
pub name: String,
pub virtual_ip: String,
pub nat_type: String,
pub public_ips: String,
pub local_ip: String,
pub nat_traversal_type: String,
pub rt: String,
pub status: String,
}
+1
View File
@@ -1,2 +1,3 @@
pub mod client;
pub mod server;
pub mod entity;
+124 -98
View File
@@ -3,9 +3,9 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::sync::Arc;
use console::style;
use switch::core::Switch;
use crate::command::entity::{DeviceItem, RouteItem, Status};
use switch::handle::{PeerDeviceStatus, RouteType};
use switch::Switch;
pub struct CommandServer {}
@@ -54,111 +54,137 @@ impl CommandServer {
}
}
pub fn command_route(switch: &Switch) -> Vec<RouteItem> {
let route_table = switch.route_table();
let mut route_list = Vec::with_capacity(route_table.len());
for (destination, route) in route_table {
let next_hop = switch.route_key(&route.route_key()).map_or(String::new(), |v| v.to_string());
let metric = route.metric.to_string();
let rt = if route.rt < 0 {
"".to_string()
} else {
route.rt.to_string()
};
let interface = route.addr.to_string();
let item = RouteItem {
destination: destination.to_string(),
next_hop,
metric,
rt,
interface,
};
route_list.push(item);
}
route_list
}
pub fn command_list(switch: &Switch) -> Vec<DeviceItem> {
let device_list = switch.device_list();
let mut list = Vec::new();
for peer in device_list {
let name = peer.name;
let virtual_ip = peer.virtual_ip.to_string();
let (nat_type, public_ips, local_ip) = if let Some(nat_info) = switch.peer_nat_info(&peer.virtual_ip) {
let nat_type = format!("{:?}", nat_info.nat_type);
let public_ips: Vec<String> = nat_info.public_ips.iter().map(|v| v.to_string()).collect();
let public_ips = public_ips.join(",");
let local_ip = nat_info.local_ip.to_string();
(nat_type, public_ips, local_ip)
} else {
("".to_string(), "".to_string(), "".to_string())
};
let (nat_traversal_type, rt) = if let Some(route) = switch.route(&peer.virtual_ip) {
let nat_traversal_type = if route.metric == 1 { "p2p" } else { "relay" }.to_string();
let rt = if route.rt < 0 {
"".to_string()
} else {
route.rt.to_string()
};
(nat_traversal_type, rt)
} else {
("relay".to_string(), "".to_string())
};
let status = format!("{:?}", peer.status);
let item = DeviceItem {
name,
virtual_ip,
nat_type,
public_ips,
local_ip,
nat_traversal_type,
rt,
status,
};
list.push(item);
}
list
}
pub fn command_status(switch: &Switch) -> Status {
let current_device = switch.current_device();
let nat_info = switch.nat_info();
let name = switch.name().to_string();
let virtual_ip = current_device.virtual_ip().to_string();
let virtual_gateway = current_device.virtual_gateway().to_string();
let virtual_netmask = current_device.virtual_netmask.to_string();
let connect_status = format!("{:?}", switch.connection_status());
let relay_server = current_device.connect_server.to_string();
let nat_type = format!("{:?}", nat_info.nat_type);
let public_ips: Vec<String> = nat_info.public_ips.iter().map(|v| v.to_string()).collect();
let public_ips = public_ips.join(",");
let local_ip = nat_info.local_ip.to_string();
Status {
name,
virtual_ip,
virtual_gateway,
virtual_netmask,
connect_status,
relay_server,
nat_type,
public_ips,
local_ip,
}
}
fn command(cmd: &str, switch: &Switch) -> io::Result<String> {
let mut out_str = String::new();
match cmd {
"list" => {
let server_rt = switch.server_rt();
let device_list = switch.device_list();
if device_list.is_empty() {
return Ok("No other devices found\n".to_string());
let out_str = match cmd {
"route" => {
match serde_json::to_string(&command_route(switch)) {
Ok(str) => {
str
}
Err(e) => {
format!("{:?}", e)
}
}
for peer_device_info in device_list {
let route = switch.route(&peer_device_info.virtual_ip);
let str = if peer_device_info.status == PeerDeviceStatus::Online {
if route.route_type == RouteType::P2P {
let str = if route.rt >= 0 {
format!(
"[{}] {}(p2p delay:{}ms)\n",
peer_device_info.name, peer_device_info.virtual_ip, route.rt
)
} else {
format!(
"[{}] {}(p2p)",
peer_device_info.name, peer_device_info.virtual_ip
)
};
style(str).green().to_string()
} else {
let str = if server_rt >= 0 {
format!(
"[{}] {}(relay delay:{}ms)\n",
peer_device_info.name,
peer_device_info.virtual_ip,
server_rt * 2
)
} else {
format!(
"[{}] {}(relay)\n",
peer_device_info.name, peer_device_info.virtual_ip
)
};
style(str).blue().to_string()
}
} else {
let str = format!(
"[{}] {}(Offline)\n",
peer_device_info.name, peer_device_info.virtual_ip
);
style(str).red().to_string()
};
out_str.push_str(&str);
}
"list" => {
match serde_json::to_string(&command_list(switch)) {
Ok(str) => {
str
}
Err(e) => {
format!("{:?}", e)
}
}
}
"status" => {
let server_rt = switch.server_rt();
let current_device = switch.current_device();
let str = format!("Virtual ip:{}\n", style(current_device.virtual_ip).green());
out_str.push_str(&str);
let str = format!(
"Virtual gateway:{}\n",
style(current_device.virtual_gateway).green()
);
out_str.push_str(&str);
let str = format!(
"Connection status :{}\n",
style(format!("{:?}", switch.connection_status())).green()
);
out_str.push_str(&str);
let str = format!(
"Relay server :{}\n",
style(current_device.connect_server).green()
);
out_str.push_str(&str);
if server_rt >= 0 {
let str = format!("Delay of relay server :{}ms\n", style(server_rt).green());
out_str.push_str(&str);
}
if let Some(nat_info) = switch.nat_info() {
let str = format!(
"NAT type :{}",
style(format!("{:?}", nat_info.nat_type)).green()
);
out_str.push_str(&str);
match serde_json::to_string(&command_status(switch)) {
Ok(str) => {
str
}
Err(e) => {
format!("{:?}", e)
}
}
}
"help" | "h" => {
let str = format!("Options: \n");
out_str.push_str(&str);
let str = format!(
"{} , Query the virtual IP of other devices\n",
style("list").green()
);
out_str.push_str(&str);
let str = format!("{} , View current device status\n", style("status").green());
out_str.push_str(&str);
let str = format!("{} , Exit the program\n", style("exit").green());
out_str.push_str(&str);
}
"exit" => {
switch.stop_async();
"stop" => {
switch.stop()?;
"stopping".to_string()
}
_ => {
let str = format!("command '{}' not fount. \n", style(cmd).red());
out_str.push_str(&str);
let str = format!("Try to enter: '{}'\n", style("help").green());
out_str.push_str(&str);
format!("command '{}' not fount. \n Try to enter: 'help'\n", cmd)
}
}
};
Ok(out_str)
}