|
| 1 | +use std::cell::UnsafeCell; |
| 2 | +use crate::easytier::argument::{Argument, PortForward}; |
| 3 | +use easytier::common::config::{PortForwardConfig, TomlConfigLoader}; |
| 4 | +use easytier::launcher::NetworkInstance; |
| 5 | +use easytier::proto::api::instance::{ListRouteRequest, Route}; |
| 6 | +use easytier::proto::rpc_types::controller::BaseController; |
| 7 | +use easytier::socks5::Socks5Server; |
| 8 | +use std::fmt::Write; |
| 9 | +use std::net::Ipv4Addr; |
| 10 | +use std::sync::Arc; |
| 11 | +use tokio::runtime::Handle; |
| 12 | +use toml::{Table, Value}; |
| 13 | + |
| 14 | +lazy_static::lazy_static! { |
| 15 | + pub static ref FACTORY: EasytierFactory = create(); |
| 16 | +} |
| 17 | + |
| 18 | +pub struct EasytierFactory(); |
| 19 | + |
| 20 | +pub struct Easytier { |
| 21 | + instance: Option<(NetworkInstance, Arc<Socks5Server>)>, |
| 22 | +} |
| 23 | + |
| 24 | +fn create() -> EasytierFactory { |
| 25 | + EasytierFactory() |
| 26 | +} |
| 27 | + |
| 28 | +impl EasytierFactory { |
| 29 | + pub fn create(&self, args: Vec<Argument>) -> Easytier { |
| 30 | + let table = UnsafeCell::new(Table::new()); |
| 31 | + let acquire_table = || { |
| 32 | + unsafe { |
| 33 | + table.as_mut_unchecked() |
| 34 | + } |
| 35 | + }; |
| 36 | + |
| 37 | + acquire_table().insert("flags".into(), Value::Table(Table::new())); |
| 38 | + let flags = || acquire_table().get_mut("flags").unwrap().as_table_mut().unwrap(); |
| 39 | + |
| 40 | + acquire_table().insert("network_identity".into(), Value::Table(Table::new())); |
| 41 | + let identity = || acquire_table().get_mut("network_identity").unwrap().as_table_mut().unwrap(); |
| 42 | + |
| 43 | + acquire_table().insert("listeners".into(), Value::Array(vec![])); |
| 44 | + let listeners = || acquire_table().get_mut("listeners").unwrap().as_array_mut().unwrap(); |
| 45 | + |
| 46 | + acquire_table().insert("peer".into(), Value::Array(vec![])); |
| 47 | + let peer = || acquire_table().get_mut("peer").unwrap().as_array_mut().unwrap(); |
| 48 | + |
| 49 | + acquire_table().insert("port_forward".into(), Value::Array(vec![])); |
| 50 | + let forwards = || acquire_table().get_mut("port_forward").unwrap().as_array_mut().unwrap(); |
| 51 | + |
| 52 | + acquire_table().insert("tcp_whitelist".into(), Value::Array(vec![])); |
| 53 | + let tcp_whitelist = || acquire_table().get_mut("tcp_whitelist").unwrap().as_array_mut().unwrap(); |
| 54 | + |
| 55 | + acquire_table().insert("udp_whitelist".into(), Value::Array(vec![])); |
| 56 | + let udp_whitelist = || acquire_table().get_mut("udp_whitelist").unwrap().as_array_mut().unwrap(); |
| 57 | + |
| 58 | + for arg in args { |
| 59 | + match arg { |
| 60 | + Argument::NoTun => { |
| 61 | + flags().insert("no_tun".into(), Value::Boolean(true)); |
| 62 | + } |
| 63 | + Argument::Compression(name) => { |
| 64 | + flags().insert("data_compress_algo".into(), Value::Integer(match name.as_ref() { |
| 65 | + "zstd" => 2, |
| 66 | + _ => unimplemented!(), |
| 67 | + })); |
| 68 | + } |
| 69 | + Argument::MultiThread => { |
| 70 | + flags().insert("multi_thread".into(), Value::Boolean(true)); |
| 71 | + } |
| 72 | + Argument::LatencyFirst => { |
| 73 | + flags().insert("latency_first".into(), Value::Boolean(true)); |
| 74 | + } |
| 75 | + Argument::EnableKcpProxy => { |
| 76 | + flags().insert("enable_kcp_proxy".into(), Value::Boolean(true)); |
| 77 | + } |
| 78 | + Argument::PublicServer(server) => { |
| 79 | + peer().push(Value::String(server.into())); |
| 80 | + } |
| 81 | + Argument::NetworkName(name) => { |
| 82 | + identity().insert("network_name".into(), Value::String(name.into())); |
| 83 | + } |
| 84 | + Argument::NetworkSecret(secret) => { |
| 85 | + identity().insert("network_secret".into(), Value::String(secret.into())); |
| 86 | + } |
| 87 | + Argument::Listener { address, proto } => { |
| 88 | + listeners().push(Value::String(format!("{}://{}", proto.name(), address))); |
| 89 | + } |
| 90 | + Argument::PortForward(PortForward { local, remote, proto }) => { |
| 91 | + let mut forward = Table::new(); |
| 92 | + forward.insert("bind_addr".into(), Value::String(local.to_string())); |
| 93 | + forward.insert("dst_addr".into(), Value::String(remote.to_string())); |
| 94 | + forward.insert("proto".into(), Value::String(proto.name().into())); |
| 95 | + forwards().push(Value::Table(forward)); |
| 96 | + } |
| 97 | + Argument::DHCP => { |
| 98 | + acquire_table().insert("dhcp".into(), Value::Boolean(true)); |
| 99 | + } |
| 100 | + Argument::HostName(name) => { |
| 101 | + acquire_table().insert("hostname".into(), Value::String(name.into())); |
| 102 | + } |
| 103 | + Argument::IPv4(address) => { |
| 104 | + acquire_table().insert("ipv4".into(), Value::String(address.to_string())); |
| 105 | + } |
| 106 | + Argument::TcpWhitelist(port) => { |
| 107 | + tcp_whitelist().push(Value::Integer(port as i64)); |
| 108 | + } |
| 109 | + Argument::UdpWhitelist(port) => { |
| 110 | + udp_whitelist().push(Value::Integer(port as i64)); |
| 111 | + } |
| 112 | + } |
| 113 | + } |
| 114 | + |
| 115 | + let instance = toml::to_string(&Value::Table(table.into_inner())).ok() |
| 116 | + .and_then(|str| TomlConfigLoader::new_from_str(str.as_str()).ok()) |
| 117 | + .map(|config| NetworkInstance::new(config)); |
| 118 | + let instance = if let Some(mut instance) = instance && let Ok((_, server)) = instance.start() { |
| 119 | + Some((instance, server.unwrap())) |
| 120 | + } else { |
| 121 | + None |
| 122 | + }; |
| 123 | + Easytier { instance } |
| 124 | + } |
| 125 | + |
| 126 | + pub fn remove(&self) {} |
| 127 | +} |
| 128 | + |
| 129 | +impl Easytier { |
| 130 | + pub fn is_alive(&mut self) -> bool { |
| 131 | + self.instance.as_ref().is_some_and(|(instance, _)| instance.is_easytier_running()) |
| 132 | + } |
| 133 | + |
| 134 | + pub fn get_players(&mut self) -> Option<Vec<(String, Ipv4Addr)>> { |
| 135 | + self.instance.as_ref() |
| 136 | + .and_then(|(instance, _)| { |
| 137 | + instance.get_api_service() |
| 138 | + .and_then(|service| { |
| 139 | + Handle::current().block_on(service.get_peer_manage_service() |
| 140 | + .list_route(BaseController::default(), ListRouteRequest::default()) |
| 141 | + ).ok() |
| 142 | + }) |
| 143 | + .map(|response| response.routes) |
| 144 | + }) |
| 145 | + .map(|info: Vec<Route>| { |
| 146 | + info.into_iter() |
| 147 | + .filter_map(|route| route.ipv4_addr |
| 148 | + .and_then(|address| address.address) |
| 149 | + .map(|address| (route.hostname, Ipv4Addr::from_octets(address.addr.to_be_bytes()))) |
| 150 | + ) |
| 151 | + .collect::<Vec<_>>() |
| 152 | + }) |
| 153 | + } |
| 154 | + |
| 155 | + pub fn add_port_forward( |
| 156 | + &mut self, |
| 157 | + forwards: &[PortForward], |
| 158 | + ) -> bool { |
| 159 | + if let Some((_, socks5)) = self.instance.as_ref() { |
| 160 | + let mut stream = forwards.iter().map(|forward| { |
| 161 | + let task = socks5.add_port_forward(PortForwardConfig { |
| 162 | + bind_addr: forward.local, |
| 163 | + dst_addr: forward.remote, |
| 164 | + proto: forward.proto.name().into(), |
| 165 | + }); |
| 166 | + |
| 167 | + (task, forward) |
| 168 | + }).filter_map(|(task, forward)| { |
| 169 | + Handle::current().block_on(task).err().map(|e| (e, forward)) |
| 170 | + }); |
| 171 | + |
| 172 | + if let Some(mut item) = stream.next() { |
| 173 | + let mut msg = "Cannot adding port-forward rules: ".to_string(); |
| 174 | + loop { |
| 175 | + let (e, PortForward { local, remote, proto }) = item; |
| 176 | + write!(&mut msg, "{} -> {} ({}): {:?}", local, remote, proto.name(), e).unwrap(); |
| 177 | + |
| 178 | + if let Some(item2) = stream.next() { |
| 179 | + msg.push_str(", "); |
| 180 | + item = item2; |
| 181 | + } else { |
| 182 | + break; |
| 183 | + } |
| 184 | + } |
| 185 | + logging!("EasyTier CLI", "{}", msg); |
| 186 | + } else { |
| 187 | + return true; |
| 188 | + } |
| 189 | + } |
| 190 | + return false; |
| 191 | + } |
| 192 | +} |
| 193 | + |
| 194 | +impl Drop for Easytier { |
| 195 | + fn drop(&mut self) { |
| 196 | + logging!("EasyTier", "Killing EasyTier."); |
| 197 | + |
| 198 | + self.instance.take() |
| 199 | + .and_then(|(instance, _)| instance.get_stop_notifier()) |
| 200 | + .map(|stop| { |
| 201 | + Handle::current().block_on(stop.notified()); |
| 202 | + }); |
| 203 | + } |
| 204 | +} |
0 commit comments