diff --git a/Cargo.lock b/Cargo.lock index 32f8095..ca9f45b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -756,7 +756,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "playit-agent-core" -version = "0.12.0" +version = "0.14.0" dependencies = [ "async-trait", "byteorder", @@ -789,7 +789,7 @@ dependencies = [ [[package]] name = "playit-cli" -version = "0.12.0" +version = "0.14.0" dependencies = [ "clap", "crossterm", diff --git a/Cargo.toml b/Cargo.toml index 95bdf91..8d40761 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ ] [workspace.package] -version = "0.13.0" +version = "0.14.0" [workspace.dependencies] tokio = { version = "1.32", features = ["full"] } diff --git a/packages/agent_cli/src/autorun.rs b/packages/agent_cli/src/autorun.rs index 36d0f17..a0cf3cc 100644 --- a/packages/agent_cli/src/autorun.rs +++ b/packages/agent_cli/src/autorun.rs @@ -1,45 +1,36 @@ use std::{ + fmt::Write, net::{IpAddr, SocketAddr}, - sync::{atomic::Ordering, Arc, Mutex}, + sync::{Arc, atomic::Ordering, Mutex}, time::Duration, - fmt::Write, }; use playit_agent_core::{ - api::api::{AccountTunnelAllocation, AccountTunnels, PortType, ReqTunnelsList, TunnelOrigin}, + api::api::*, network::address_lookup::{AddressLookup, AddressValue}, tunnel_runner::TunnelRunner, utils::now_milli, }; use playit_agent_core::api::api::AgentType; -use crate::{match_ip::MatchIp, playit_secret::PlayitSecret, ui::UI, CliError, API_BASE}; +use crate::{API_BASE, CliError, match_ip::MatchIp, playit_secret::PlayitSecret, ui::UI}; pub async fn autorun(ui: &mut UI, mut secret: PlayitSecret) -> Result<(), CliError> { let secret_code = secret - .with_default_path().await .ensure_valid(ui) .await? .get_or_setup(ui) .await?; let api = secret.create_api().await?; - let agents = api.agents_list().await?; - tokio::time::sleep(Duration::from_secs(2)).await; let lookup = { - let account_tunnels = api - .tunnels_list(ReqTunnelsList { - tunnel_id: None, - agent_id: None, - }) - .await?; - + let data = api.agents_rundata().await?; let lookup = Arc::new(LocalLookup { data: Mutex::new(vec![]), }); - lookup.update(account_tunnels).await; + lookup.update(data.tunnels).await; lookup }; @@ -70,17 +61,13 @@ pub async fn autorun(ui: &mut UI, mut secret: PlayitSecret) -> Result<(), CliErr ui.write_screen("tunnel running"); + let mut guest_login_link: Option<(String, u64)> = None; + loop { tokio::time::sleep(Duration::from_secs(3)).await; - let account_tunnels_res = api - .tunnels_list(ReqTunnelsList { - tunnel_id: None, - agent_id: None, - }) - .await; - - let account_tunnels = match account_tunnels_res { + let account_tunnels_res = api.agents_rundata().await; + let agent_data = match account_tunnels_res { Ok(v) => v, Err(error) => { ui.write_error("Failed to load latest tunnels", error); @@ -90,47 +77,92 @@ pub async fn autorun(ui: &mut UI, mut secret: PlayitSecret) -> Result<(), CliErr }; let mut msg = format!( - "playit (v{}): {} tunnel running, {} tunnels registered\n\nTUNNELS\n", + "playit (v{}): {} tunnel running, {} tunnels registered\n\n", env!("CARGO_PKG_VERSION"), now_milli(), - account_tunnels.tunnels.len() + agent_data.tunnels.len() ); + match agent_data.account_status { + AgentAccountStatus::Guest => { + 'login_link: { + let now = now_milli(); + + match &guest_login_link { + Some((link, ts)) if now - *ts < 15_000 => { + writeln!(msg, "login: {}", link).unwrap(); + } + _ => { + let Ok(session) = api.login_guest().await else { + writeln!(msg, "Failed to create guest login link").unwrap(); + break 'login_link; + }; + + let link = format!("https://playit.gg/login/guest-account/{}", session.session_key); + writeln!(msg, "login: {}", link).unwrap(); + + guest_login_link = Some((link, now_milli())); + } + } + } + } + AgentAccountStatus::EmailNotVerified => { + writeln!(msg, "Email not verified https://playit.gg/account/settings/account/verify-email").unwrap(); + } + AgentAccountStatus::AccountDeleteScheduled => { + writeln!(msg, "Account scheduled for delete: https://playit.gg/account/settings/account/delete-account").unwrap(); + } + AgentAccountStatus::Banned => { + writeln!(msg, "Account banned: https://playit.gg/account").unwrap(); + } + AgentAccountStatus::HasMessage => { + writeln!(msg, "You have a message: https://playit.gg/account").unwrap(); + } + AgentAccountStatus::Ready => {} + } + + writeln!(msg, "\nTUNNELS").unwrap(); - if account_tunnels.tunnels.len() == 0 { - let agent = &agents.agents[0]; - let agent_id = match agent.agent_type { + if agent_data.tunnels.len() == 0 && agent_data.pending.len() == 0 { + let agent_id = match agent_data.agent_type { AgentType::Default => "default".to_string(), - AgentType::Assignable => agent.id.to_string(), - AgentType::SelfManaged => agent.id.to_string(), + AgentType::Assignable => agent_data.agent_id.to_string(), + AgentType::SelfManaged => agent_data.agent_id.to_string(), }; writeln!(msg, "Add tunnels here: https://playit.gg/account/agents/{}", agent_id).unwrap(); - } - else { - for tunnel in &account_tunnels.tunnels { - let mut alloc_port = None; - - let src = match &tunnel.alloc { - AccountTunnelAllocation::Pending => "pending".to_string(), - AccountTunnelAllocation::Disabled(_) => format!("action required https://playit.gg/account/tunnel/{}", tunnel.id), - AccountTunnelAllocation::Allocated(alloc) => { - alloc_port = Some(alloc.port_start); - alloc.assigned_srv.clone().unwrap_or_else(|| format!("{}:{}", alloc.assigned_domain, alloc.port_start)) - } + } else { + for tunnel in &agent_data.tunnels { + let addr = tunnel.custom_domain.as_ref().unwrap_or(&tunnel.assigned_domain); + let src = match tunnel.tunnel_type.as_ref().map(|v| v.as_str()) { + Some("minecraft-java") => addr.clone(), + _ => format!("{}:{}", addr, tunnel.port.from), }; - let dst = match &tunnel.origin { - TunnelOrigin::Agent(agent) => format!("{}:{}", agent.local_ip, agent.local_port.or(alloc_port).map(|v| v.to_string()).unwrap_or("?".to_string())), - TunnelOrigin::Default(agent) => format!("{}:{}", agent.local_ip, agent.local_port.or(alloc_port).map(|v| v.to_string()).unwrap_or("?".to_string())), - TunnelOrigin::Managed(_) => "managed".to_string(), - }; + let dst = format!("{}:{}", tunnel.local_ip, tunnel.local_port); + + if let Some(disabled) = tunnel.disabled { + writeln!(msg, "{} => {} (disabled)", src, dst).unwrap(); + if disabled == AgentTunnelDisabled::BySystem { + writeln!(msg, "\tsee: https://playit.gg/account/tunnels/{}", tunnel.id).unwrap(); + } + } else if let Some(tunnel_type) = &tunnel.tunnel_type { + writeln!(msg, "{} => {} ({})", src, dst, tunnel_type).unwrap(); + } else { + writeln!(msg, "{} => {} (proto: {:?}, port count: {})", src, dst, tunnel.proto, tunnel.port.to - tunnel.port.from).unwrap(); + } + } - writeln!(msg, "{} => {}", src, dst).unwrap(); + for tunnel in &agent_data.pending { + if tunnel.is_disabled { + writeln!(msg, "tunnel pending (disabled): https://playit.gg/account/tunnels/{}", tunnel.id).unwrap(); + } else { + writeln!(msg, "tunnel pending: https://playit.gg/account/tunnels/{}", tunnel.id).unwrap(); + } } } - lookup.update(account_tunnels).await; + lookup.update(agent_data.tunnels).await; ui.write_screen(msg); } @@ -173,45 +205,22 @@ impl AddressLookup for LocalLookup { } impl LocalLookup { - pub async fn update(&self, data: AccountTunnels) { + pub async fn update(&self, tunnels: Vec) { let mut entries: Vec = vec![]; - for tunnel in data.tunnels { - match tunnel.alloc { - AccountTunnelAllocation::Allocated(allocated) => { - let ip = match allocated.tunnel_ip { - IpAddr::V6(ip) => ip, - _ => continue, - }; - - let local_addr = match tunnel.origin { - TunnelOrigin::Default(def) => SocketAddr::new( - def.local_ip, - def.local_port.unwrap_or(allocated.port_start), - ), - TunnelOrigin::Agent(def) => SocketAddr::new( - def.local_ip, - def.local_port.unwrap_or(allocated.port_start), - ), - _ => continue, - }; - - let address = allocated.assigned_srv.unwrap_or(format!( - "{}:{}", - allocated.assigned_domain, allocated.port_start - )); - - entries.push(TunnelEntry { - pub_address: address, - match_ip: MatchIp::new(ip), - port_type: tunnel.port_type, - from_port: allocated.port_start, - to_port: allocated.port_end, - local_start_address: local_addr, - }); - } - _ => continue, - } + for tunnel in tunnels { + entries.push(TunnelEntry { + pub_address: if tunnel.tunnel_type.as_ref().map(|v| v.eq("minecraft-java")).unwrap_or(false) { + tunnel.custom_domain.unwrap_or(tunnel.assigned_domain) + } else { + format!("{}:{}", tunnel.custom_domain.unwrap_or(tunnel.assigned_domain), tunnel.port.from) + }, + match_ip: MatchIp { ip_number: tunnel.ip_num, region_id: if tunnel.region_num == 0 { None } else { Some(tunnel.region_num) } }, + port_type: tunnel.proto, + from_port: tunnel.port.from, + to_port: tunnel.port.to, + local_start_address: SocketAddr::new(tunnel.local_ip, tunnel.local_port), + }); } let mut value = self.data.lock().unwrap(); diff --git a/packages/agent_cli/src/main.rs b/packages/agent_cli/src/main.rs index 416671b..c4e2198 100644 --- a/packages/agent_cli/src/main.rs +++ b/packages/agent_cli/src/main.rs @@ -11,9 +11,8 @@ use rand::Rng; use uuid::Uuid; use autorun::autorun; -use playit_agent_core::api::api::{AccountTunnel, AccountTunnelAllocation, AgentType, ApiError, ApiErrorNoFail, ApiResponseError, AssignedManagedCreate, ClaimSetupResponse, PortType, ReqClaimExchange, ReqClaimSetup, ReqTunnelsCreate, ReqTunnelsList, TunnelAllocated, TunnelOriginCreate, TunnelType}; +use playit_agent_core::api::api::*; use playit_agent_core::api::http_client::HttpClientError; -use playit_agent_core::api::ip_resource::IpResource; use playit_agent_core::api::PlayitApi; use playit_agent_core::network::address_lookup::{AddressLookup, AddressValue}; use playit_agent_core::tunnel::setup::SetupError; @@ -21,6 +20,7 @@ use playit_agent_core::tunnel_runner::TunnelRunner; use playit_agent_core::utils::now_milli; use playit_secret::PlayitSecret; +use crate::match_ip::MatchIp; use crate::ui::{UI, UISettings}; pub const API_BASE: &'static str = "https://api.playit.gg"; @@ -36,7 +36,8 @@ async fn main() -> Result { // tracing_subscriber::fmt().try_init().unwrap(); let matches = cli().get_matches(); - let secret = PlayitSecret::from_args(&matches).await; + let mut secret = PlayitSecret::from_args(&matches).await; + let _ = secret.with_default_path().await; let mut ui = UI::new(UISettings { auto_answer: None, @@ -53,7 +54,7 @@ async fn main() -> Result { Some(("account", m)) => match m.subcommand() { Some(("login-url", _)) => { let api = secret.create_api().await?; - let session = api.login_create_guest().await?; + let session = api.login_guest().await?; println!("https://playit.gg/login/guest-account/{}", session.session_key) } // Some(("status", _)) => { @@ -112,19 +113,17 @@ async fn main() -> Result { let exact = m.get_flag("exact"); let ignore_name = m.get_flag("ignore_name"); - let tunnel = tunnels_prepare( + let tunnel_id = tunnels_prepare( &api, name, tunnel_type, port_type, port_count, exact, ignore_name, ).await?; - println!("{}", tunnel.id); + println!("{}", tunnel_id); } Some(("list", _)) => { let api = secret.create_api().await?; - let tunnels = api.tunnels_list(ReqTunnelsList { tunnel_id: None, agent_id: None }).await?; - for tunnel in tunnels.tunnels { - println!("{}", serde_json::to_string(&tunnel).unwrap()); - } + let response = api.tunnels_list_json(ReqTunnelsList { tunnel_id: None, agent_id: None }).await?; + println!("{}", serde_json::to_string_pretty(&response).unwrap()); } _ => return Err(CliError::NotImplemented.into()) } @@ -133,7 +132,7 @@ async fn main() -> Result { let secret_key = secret.get().await?; let api = PlayitApi::create(API_BASE.to_string(), Some(secret_key.clone())); - let tunnels = api.tunnels_list(ReqTunnelsList { tunnel_id: None, agent_id: None }).await?; + let tunnels = api.agents_rundata().await?; let mut tunnel_lookup = HashMap::new(); let mut tunnel_found = HashSet::new(); @@ -165,9 +164,12 @@ async fn main() -> Result { match tunnel_lookup.remove(&tunnel_id) { Some(tunnel) => { - if let Some(over) = MappingOverride::new(tunnel, local_addr) { - mapping_overrides.push(over); - } + mapping_overrides.push(MappingOverride { + match_ip: MatchIp { ip_number: tunnel.ip_num, region_id: if tunnel.region_num == 0 { None } else { Some(tunnel.region_num) } }, + port: tunnel.port, + proto: tunnel.proto, + local_addr, + }); } None => { return if tunnel_found.contains(&tunnel_id) { @@ -182,7 +184,7 @@ async fn main() -> Result { let tunnel = TunnelRunner::new( API_BASE.to_string(), secret_key, - Arc::new(LookupWithOverrides(mapping_overrides)) + Arc::new(LookupWithOverrides(mapping_overrides)), ).await?; tunnel.run().await; @@ -282,28 +284,75 @@ pub async fn claim_exchange(ui: &mut UI, claim_code: &str, agent_type: AgentType Ok(secret_key) } -pub async fn tunnels_prepare(api: &PlayitApi, name: Option, tunnel_type: Option, port_type: PortType, port_count: u16, exact: bool, ignore_name: bool) -> Result { - let tunnels = api.tunnels_list(ReqTunnelsList { tunnel_id: None, agent_id: None }).await?; +struct TunnelOption { + id: Uuid, + name: Option, + proto: PortType, + port_count: u16, + tunnel_type: Option, + public_address: Option, +} - let mut options = Vec::new(); - for tunnel in tunnels.tunnels { - let tunnel_port_count = match &tunnel.alloc { - AccountTunnelAllocation::Allocated(alloc) => alloc.port_end - alloc.port_start, - _ => continue, - }; +struct TunnelAlloc { + address: String, + port: u16, +} +pub async fn tunnels_prepare(api: &PlayitApi, name: Option, tunnel_type: Option, port_type: PortType, port_count: u16, exact: bool, ignore_name: bool) -> Result { + let tunnel_type_str = tunnel_type.clone().map(|v| format!("{:?}", v)); + let data = api.agents_rundata().await?; + + let options = data.tunnels.into_iter().map(|v| { + let is_minecraft = v.tunnel_type.as_ref().map(|v| v.eq("minecraft-java")).unwrap_or(false); + + TunnelOption { + id: v.id, + name: v.name, + proto: v.proto, + port_count: v.port.to - v.port.from, + tunnel_type: v.tunnel_type, + public_address: Some({ + let name = v.custom_domain.unwrap_or(v.assigned_domain); + let address = if is_minecraft { + name + } else { + format!("{}:{}", name, v.port.from) + }; + + TunnelAlloc { + address, + port: v.port.from, + } + }), + } + }); + + let options = options.chain(data.pending.into_iter().map(|v| { + TunnelOption { + id: v.id, + name: v.name, + proto: v.proto, + port_count: v.port_count, + tunnel_type: v.tunnel_type, + public_address: None, + } + })); + + let mut options = options.filter(|tunnel| { if exact { - if (ignore_name || tunnel.name.eq(&name)) && tunnel.port_type == port_type && port_count == tunnel_port_count && tunnel.tunnel_type == tunnel_type { - options.push(tunnel); + if (ignore_name || tunnel.name.eq(&name)) && tunnel.proto == port_type && port_count == tunnel.port_count && tunnel.tunnel_type == tunnel_type_str { + true } else { - continue; + false } } else { - if (tunnel.port_type == PortType::Both || tunnel.port_type == port_type) && port_count <= tunnel_port_count && tunnel.tunnel_type == tunnel_type { - options.push(tunnel); + if (tunnel.proto == PortType::Both || tunnel.proto == port_type) && port_count <= tunnel.port_count && tunnel.tunnel_type == tunnel_type_str { + true + } else { + false } } - } + }).collect::>(); /* rank options by how much they match */ options.sort_by_key(|option| { @@ -319,7 +368,7 @@ pub async fn tunnels_prepare(api: &PlayitApi, name: Option, tunnel_type: } } - if option.port_type == port_type { + if option.proto == port_type { points += 200; } @@ -329,17 +378,11 @@ pub async fn tunnels_prepare(api: &PlayitApi, name: Option, tunnel_type: points += ((port_count as i32) - (option.port_count as i32)) * 10; } - points += match option.alloc { - AccountTunnelAllocation::Pending => -10, - AccountTunnelAllocation::Disabled(_) => -40, - AccountTunnelAllocation::Allocated(_) => 0, - }; - points }); if let Some(found_tunnel) = options.pop() { - return Ok(found_tunnel); + return Ok(found_tunnel.id); } let created = api.tunnels_create(ReqTunnelsCreate { @@ -353,54 +396,28 @@ pub async fn tunnels_prepare(api: &PlayitApi, name: Option, tunnel_type: firewall_id: None, }).await?; - let tunnels = api.tunnels_list(ReqTunnelsList { tunnel_id: None, agent_id: None }).await?; - for tunnel in tunnels.tunnels { - if tunnel.id == created.id { - return Ok(tunnel); - } - } - - Err(CliError::ResourceNotFoundAfterCreate(created.id)) + Ok(created.id) } -pub struct MappingOverride { - tunnel: AccountTunnel, - alloc: TunnelAllocated, - ip_resource: IpResource, +struct MappingOverride { + match_ip: MatchIp, + proto: PortType, + port: PortRange, local_addr: SocketAddr, } -impl MappingOverride { - pub fn new(tunnel: AccountTunnel, local_addr: SocketAddr) -> Option { - let alloc = match &tunnel.alloc { - AccountTunnelAllocation::Allocated(alloc) => alloc.clone(), - _ => return None, - }; - - let ip_resource = IpResource::from_ip(alloc.tunnel_ip); - Some(MappingOverride { - tunnel, - alloc, - ip_resource, - local_addr, - }) - } -} - pub struct LookupWithOverrides(Vec); impl AddressLookup for LookupWithOverrides { type Value = SocketAddr; fn lookup(&self, ip: IpAddr, port: u16, proto: PortType) -> Option> { - let resource = IpResource::from_ip(ip); - for over in &self.0 { - if over.tunnel.port_type == proto && over.ip_resource == resource { + if over.proto == proto && over.match_ip.matches(ip) { return Some(AddressValue { value: over.local_addr, - from_port: over.alloc.port_start, - to_port: over.alloc.port_end, + from_port: over.port.from, + to_port: over.port.to, }); } } diff --git a/packages/agent_cli/src/playit_secret.rs b/packages/agent_cli/src/playit_secret.rs index 855b7b4..6740b56 100644 --- a/packages/agent_cli/src/playit_secret.rs +++ b/packages/agent_cli/src/playit_secret.rs @@ -2,7 +2,7 @@ use std::time::Duration; use clap::ArgMatches; use playit_agent_core::api::{ - api::{ApiErrorNoFail, ApiResponseError, AuthError, ReqTunnelsList, AgentType}, + api::*, PlayitApi, }; use serde::{Deserialize, Serialize}; @@ -70,17 +70,11 @@ impl PlayitSecret { tokio::time::sleep(Duration::from_secs(1)).await; loop { - match api - .tunnels_list(ReqTunnelsList { - tunnel_id: None, - agent_id: None, - }) - .await - { - Ok(tunnels) => { + match api.agents_rundata().await { + Ok(data) => { ui.write_screen(format!( "secret key valid, agent has {} tunnels", - tunnels.tunnels.len() + data.tunnels.len() )); tokio::time::sleep(Duration::from_secs(3)).await; break; @@ -89,9 +83,7 @@ impl PlayitSecret { ui.write_error("Failed to load data from api\nretrying in 3 seconds", error); tokio::time::sleep(Duration::from_secs(3)).await; } - Err(ApiErrorNoFail::ApiError(ApiResponseError::Auth( - AuthError::InvalidAgentKey, - ))) => { + Err(ApiErrorNoFail::ApiError(ApiResponseError::Auth(AuthError::InvalidAgentKey))) => { if !self.path.is_some() { return Err(CliError::InvalidSecret); } @@ -128,7 +120,7 @@ impl PlayitSecret { } let claim_code = claim_generate(); - let secret = claim_exchange(ui, &claim_code, AgentType::Assignable ,0).await?; + let secret = claim_exchange(ui, &claim_code, AgentType::Assignable, 0).await?; { let mut lock = self.secret.write().await; @@ -179,6 +171,7 @@ impl PlayitSecret { } let file_path = self.path.as_ref().ok_or(CliError::MissingSecret)?; + tracing::info!(%file_path, "loading secret"); let mut lock = self.secret.write().await; diff --git a/packages/agent_core/src/api/api.rs b/packages/agent_core/src/api/api.rs index 84320d3..3bf5ced 100644 --- a/packages/agent_core/src/api/api.rs +++ b/packages/agent_core/src/api/api.rs @@ -27,39 +27,6 @@ impl PlayitApiClient { pub async fn tunnels_delete(&self, req: ReqTunnelsDelete) -> Result<(), ApiError> { Self::unwrap(self.client.call("/tunnels/delete", req).await) } - pub async fn tunnels_list(&self, req: ReqTunnelsList) -> Result> { - Self::unwrap_no_fail(self.client.call("/tunnels/list", req).await) - } - pub async fn tunnels_update(&self, req: ReqTunnelsUpdate) -> Result<(), ApiError> { - Self::unwrap(self.client.call("/tunnels/update", req).await) - } - pub async fn tunnels_firewall_assign(&self, req: ReqTunnelsFirewallAssign) -> Result<(), ApiError> { - Self::unwrap(self.client.call("/tunnels/firewall/assign", req).await) - } - pub async fn agents_list(&self) -> Result> { - Self::unwrap_no_fail(self.client.call("/agents/list", ReqAgentsList {}).await) - } - pub async fn agents_delete(&self, req: ReqAgentsDelete) -> Result<(), ApiError> { - Self::unwrap(self.client.call("/agents/delete", req).await) - } - pub async fn agents_rename(&self, req: ReqAgentsRename) -> Result<(), ApiError> { - Self::unwrap(self.client.call("/agents/rename", req).await) - } - pub async fn allocations_list(&self, req: ReqAllocationsList) -> Result> { - Self::unwrap_no_fail(self.client.call("/allocations/list", req).await) - } - pub async fn tunnels_rename(&self, req: ReqTunnelsRename) -> Result<(), ApiError> { - Self::unwrap(self.client.call("/tunnels/rename", req).await) - } - pub async fn firewalls_list(&self) -> Result> { - Self::unwrap_no_fail(self.client.call("/firewalls/list", ReqFirewallsList {}).await) - } - pub async fn firewalls_create(&self, req: ReqFirewallsCreate) -> Result> { - Self::unwrap(self.client.call("/firewalls/create", req).await) - } - pub async fn firewalls_update(&self, req: ReqFirewallsUpdate) -> Result<(), ApiError> { - Self::unwrap(self.client.call("/firewalls/update", req).await) - } pub async fn claim_details(&self, req: ReqClaimDetails) -> Result> { Self::unwrap(self.client.call("/claim/details", req).await) } @@ -78,12 +45,18 @@ impl PlayitApiClient { pub async fn proto_register(&self, req: ReqProtoRegister) -> Result> { Self::unwrap_no_fail(self.client.call("/proto/register", req).await) } - pub async fn login_create_guest(&self) -> Result> { - Self::unwrap(self.client.call("/login/create/guest", ReqLoginCreateGuest {}).await) + pub async fn login_guest(&self) -> Result> { + Self::unwrap(self.client.call("/login/guest", ReqLoginGuest {}).await) } pub async fn agents_routing_get(&self, req: ReqAgentsRoutingGet) -> Result> { Self::unwrap(self.client.call("/agents/routing/get", req).await) } + pub async fn agents_rundata(&self) -> Result> { + Self::unwrap_no_fail(self.client.call("/agents/rundata", ReqAgentsRundata {}).await) + } + pub async fn tunnels_list_json(&self, req: ReqTunnelsList) -> Result> { + Self::unwrap_no_fail(self.client.call("/tunnels/list", req).await) + } } #[derive(serde::Serialize, serde::Deserialize, Debug)] @@ -345,224 +318,16 @@ pub enum DeleteError { } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqTunnelsList { - pub tunnel_id: Option, - pub agent_id: Option, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AccountTunnels { - pub tcp_alloc: AllocatedPorts, - pub udp_alloc: AllocatedPorts, - pub tunnels: Vec, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AllocatedPorts { - pub allowed: u32, - pub claimed: u32, - pub desired: u32, -} - - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AccountTunnel { - pub id: uuid::Uuid, - pub tunnel_type: Option, - pub created_at: chrono::DateTime, - pub name: Option, - pub port_type: PortType, - pub port_count: u16, - pub alloc: AccountTunnelAllocation, - pub origin: TunnelOrigin, - pub domain: Option, - pub firewall_id: Option, - pub ratelimit: Ratelimit, - pub active: bool, - pub region: Option, -} - - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "status", content = "data")] -pub enum AccountTunnelAllocation { - #[serde(rename = "pending")] - Pending, - #[serde(rename = "disabled")] - Disabled(TunnelDisabled), - #[serde(rename = "allocated")] - Allocated(TunnelAllocated), -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct TunnelDisabled { - pub reason: TunnelDisabledReason, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum TunnelDisabledReason { - OverPortLimit, - RegionRequiresPremium, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct TunnelAllocated { - pub id: uuid::Uuid, - pub ip_hostname: String, - pub static_ip4: Option, - pub assigned_domain: String, - pub assigned_srv: Option, - pub tunnel_ip: std::net::IpAddr, - pub port_start: u16, - pub port_end: u16, - pub assignment: TunnelAssignment, - pub ip_type: IpType, - pub region: AllocationRegion, -} - - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "type", content = "subscription")] -pub enum TunnelAssignment { - #[serde(rename = "dedicated-ip")] - DedicatedIp(SubscriptionId), - #[serde(rename = "shared-ip")] - SharedIp, - #[serde(rename = "dedicated-port")] - DedicatedPort(SubscriptionId), -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct SubscriptionId { - pub sub_id: uuid::Uuid, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum IpType { - #[serde(rename = "both")] - Both, - #[serde(rename = "ip4")] - Ip4, - #[serde(rename = "ip6")] - Ip6, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "type", content = "data")] -pub enum TunnelOrigin { - #[serde(rename = "default")] - Default(AssignedDefault), - #[serde(rename = "agent")] - Agent(AssignedAgent), - #[serde(rename = "managed")] - Managed(AssignedManaged), -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AssignedDefault { - pub local_ip: std::net::IpAddr, - pub local_port: Option, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AssignedAgent { - pub agent_id: uuid::Uuid, - pub agent_name: String, - pub local_ip: std::net::IpAddr, - pub local_port: Option, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AssignedManaged { - pub agent_id: uuid::Uuid, - pub agent_name: String, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct TunnelDomain { - pub id: uuid::Uuid, - pub name: String, - pub is_external: bool, - pub parent: Option, - pub source: TunnelDomainSource, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum TunnelDomainSource { - #[serde(rename = "from-ip")] - FromIp, - #[serde(rename = "from-tunnel")] - FromTunnel, - #[serde(rename = "from-agent-ip")] - FromAgentIp, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct Ratelimit { - pub bytes_per_second: Option, - pub packets_per_second: Option, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqTunnelsUpdate { - pub tunnel_id: uuid::Uuid, - pub local_ip: std::net::IpAddr, - pub local_port: Option, - pub agent_id: Option, - pub enabled: bool, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum UpdateError { - ChangingAgentIdNotAllowed, - TunnelNotFound, -} - -impl std::fmt::Display for UpdateError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for UpdateError { -} -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqTunnelsFirewallAssign { - pub tunnel_id: uuid::Uuid, - pub firewall_id: Option, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum TunnelsFirewallAssignError { - TunnelNotFound, - InvalidFirewallId, -} - -impl std::fmt::Display for TunnelsFirewallAssignError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for TunnelsFirewallAssignError { -} -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqAgentsList { -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct Agents { - pub agents: Vec, +pub struct ReqClaimDetails { + pub code: String, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct Agent { - pub id: uuid::Uuid, +pub struct AgentClaimDetails { pub name: String, - pub created_at: chrono::DateTime, - pub version: Option, + pub remote_ip: std::net::IpAddr, pub agent_type: AgentType, - pub details: AgentStatus, + pub version: String, } #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] @@ -575,258 +340,6 @@ pub enum AgentType { SelfManaged, } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "state", content = "data")] -pub enum AgentStatus { - #[serde(rename = "disabled-above-limit")] - DisabledAboveLimit, - #[serde(rename = "disabled-by-user")] - DisabledByUser, - #[serde(rename = "approval-needed")] - ApprovalNeeded, - #[serde(rename = "connected")] - Connected(AgentConnectedDetails), - #[serde(rename = "offline")] - Offline, - #[serde(rename = "unknown")] - Unknown, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AgentConnectedDetails { - pub tunnel_server_id: u64, - pub data_center_id: u32, - pub data_center_name: String, - pub agent_version: AgentVersion, - pub client_addr: std::net::SocketAddr, - pub tunnel_addr: std::net::SocketAddr, - pub activity_latest_epoch_ms: u64, - pub activity_start_epoch_ms: u64, - pub tunnel_latency_ms: u32, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AgentVersion { - pub platform: Platform, - pub version: String, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum Platform { - #[serde(rename = "linux")] - Linux, - #[serde(rename = "freebsd")] - Freebsd, - #[serde(rename = "windows")] - Windows, - #[serde(rename = "macos")] - Macos, - #[serde(rename = "android")] - Android, - #[serde(rename = "ios")] - Ios, - #[serde(rename = "minecraft-plugin")] - MinecraftPlugin, - #[serde(rename = "unknown")] - Unknown, -} - - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqAgentsDelete { - pub agent_id: uuid::Uuid, - pub tunnels_strategy: DeleteAgentTunnelStrategy, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "type", content = "details")] -pub enum DeleteAgentTunnelStrategy { - #[serde(rename = "require_empty")] - RequireEmpty, - #[serde(rename = "delete_tunnels")] - DeleteTunnels, - #[serde(rename = "move_to_agent")] - MoveToAgent(TunnelStrategyMoveToAgent), -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct TunnelStrategyMoveToAgent { - pub agent_id: Option, - pub disable_tunnels: bool, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum AgentsDeleteError { - AgentNotFound, - AgentNotAuthorized, - TunnelStrategyNotAllowed, - MoveToAgentNotFound, - AgentHasExistingTunnels, -} - -impl std::fmt::Display for AgentsDeleteError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for AgentsDeleteError { -} -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqAgentsRename { - pub agent_id: uuid::Uuid, - pub name: String, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum AgentRenameError { - AgentNotFound, - InvalidName, - InvalidAgentId, -} - -impl std::fmt::Display for AgentRenameError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for AgentRenameError { -} -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqAllocationsList { - pub alloc_id: Option, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AccountAllocations { - pub ports: Vec, - pub ips: Vec, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct DedicatedPortAllocation { - pub alloc_id: uuid::Uuid, - pub ip_hostname: String, - pub port: u16, - pub port_count: u16, - pub port_type: PortType, - pub sub_id: uuid::Uuid, - pub region: AllocationRegion, - pub tunnel_id: Option, - pub ip_type: IpType, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct DedicatedIpAllocation { - pub ip_hostname: String, - pub sub_id: Option, - pub region: AllocationRegion, - pub ip_type: IpType, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqTunnelsRename { - pub tunnel_id: uuid::Uuid, - pub name: String, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum TunnelRenameError { - TunnelNotFound, - NameTooLong, -} - -impl std::fmt::Display for TunnelRenameError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for TunnelRenameError { -} -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqFirewallsList { -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct Firewalls { - pub max_firewalls: u32, - pub max_rules: u32, - pub firewalls: Vec, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct Firewall { - pub id: uuid::Uuid, - pub name: String, - pub description: Option, - pub created_at: chrono::DateTime, - pub updated_at: chrono::DateTime, - pub registered_at: Option>, - pub rules: String, - pub rule_count: u32, - pub tunnels_assigned_count: u32, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqFirewallsCreate { - pub name: String, - pub description: Option, - pub rules: String, - pub tunnel_id: Option, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum FirewallsCreateError { - TooManyFirewalls, - TooManyRules, - InvalidRules, - InvalidTunnelId, -} - -impl std::fmt::Display for FirewallsCreateError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for FirewallsCreateError { -} -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqFirewallsUpdate { - pub firewall_id: uuid::Uuid, - pub rules: String, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum FirewallsUpdateError { - TooManyRules, - InvalidRules, - FirewallNotFound, -} - -impl std::fmt::Display for FirewallsUpdateError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for FirewallsUpdateError { -} -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqClaimDetails { - pub code: String, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AgentClaimDetails { - pub name: String, - pub remote_ip: std::net::IpAddr, - pub agent_type: AgentType, - pub version: String, -} - #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] pub enum ClaimDetailsError { AlreadyClaimed, @@ -970,13 +483,40 @@ pub struct PlayitAgentVersion { pub details_website: Option, } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentVersion { + pub platform: Platform, + pub version: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] +pub enum Platform { + #[serde(rename = "linux")] + Linux, + #[serde(rename = "freebsd")] + Freebsd, + #[serde(rename = "windows")] + Windows, + #[serde(rename = "macos")] + Macos, + #[serde(rename = "android")] + Android, + #[serde(rename = "ios")] + Ios, + #[serde(rename = "minecraft-plugin")] + MinecraftPlugin, + #[serde(rename = "unknown")] + Unknown, +} + + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct SignedAgentKey { pub key: String, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqLoginCreateGuest { +pub struct ReqLoginGuest { } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] @@ -995,6 +535,8 @@ pub struct WebAuth { pub admin_id: Option, } + + #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] pub enum AccountStatus { #[serde(rename = "guest")] @@ -1022,8 +564,8 @@ pub struct SignedEpoch { } #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum LoginCreateGuestError { - Blocked, +pub enum GuestLoginError { + AccountIsNotGuest, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] @@ -1039,6 +581,7 @@ pub struct AgentRouting { } + #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] pub enum AgentRoutingGetError { MissingAgentId, @@ -1054,4 +597,77 @@ impl std::fmt::Display for AgentRoutingGetError { impl std::error::Error for AgentRoutingGetError { } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqAgentsRundata { +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentRunData { + pub agent_id: uuid::Uuid, + pub agent_type: AgentType, + pub account_status: AgentAccountStatus, + pub tunnels: Vec, + pub pending: Vec, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] +pub enum AgentAccountStatus { + #[serde(rename = "account-delete-scheduled")] + AccountDeleteScheduled, + #[serde(rename = "banned")] + Banned, + #[serde(rename = "has-message")] + HasMessage, + #[serde(rename = "email-not-verified")] + EmailNotVerified, + #[serde(rename = "guest")] + Guest, + #[serde(rename = "ready")] + Ready, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentTunnel { + pub id: uuid::Uuid, + pub name: Option, + pub ip_num: u64, + pub region_num: u16, + pub port: PortRange, + pub proto: PortType, + pub local_ip: std::net::IpAddr, + pub local_port: u16, + pub tunnel_type: Option, + pub assigned_domain: String, + pub custom_domain: Option, + pub disabled: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct PortRange { + pub from: u16, + pub to: u16, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] +pub enum AgentTunnelDisabled { + ByUser, + BySystem, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentPendingTunnel { + pub id: uuid::Uuid, + pub name: Option, + pub proto: PortType, + pub port_count: u16, + pub tunnel_type: Option, + pub is_disabled: bool, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqTunnelsList { + pub tunnel_id: Option, + pub agent_id: Option, +} + diff --git a/packages/agent_core/src/api/mod.rs b/packages/agent_core/src/api/mod.rs index e4e1c01..41db48d 100644 --- a/packages/agent_core/src/api/mod.rs +++ b/packages/agent_core/src/api/mod.rs @@ -1,5 +1,6 @@ -use crate::api::api::PlayitApiClient; -use crate::api::http_client::HttpClient; +use serde::Serialize; +use crate::api::api::{ApiResult, PlayitApiClient, PlayitHttpClient}; +use crate::api::http_client::{HttpClient, HttpClientError}; pub mod api; pub mod http_client;