diff --git a/Cargo.lock b/Cargo.lock index 977af9e..6eb7e74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1085,7 +1085,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "playit-agent-core" -version = "0.20.1" +version = "0.17.0" dependencies = [ "byteorder", "chrono", @@ -1123,9 +1123,10 @@ dependencies = [ [[package]] name = "playit-api-client" -version = "0.1.2" +version = "0.2.0" dependencies = [ "byteorder", + "chrono", "reqwest", "rustls", "serde", @@ -1138,7 +1139,7 @@ dependencies = [ [[package]] name = "playit-cli" -version = "0.16.5" +version = "0.17.0" dependencies = [ "clap", "crossterm", @@ -1162,24 +1163,6 @@ dependencies = [ "winres", ] -[[package]] -name = "playit-ping-monitor" -version = "0.1.0" -dependencies = [ - "dirs", - "hex", - "message-encoding", - "playit-agent-proto", - "playit-api-client", - "rand", - "serde", - "tokio", - "toml 0.9.8", - "tracing", - "tracing-appender", - "tracing-subscriber", -] - [[package]] name = "portable-atomic" version = "1.11.1" diff --git a/Cargo.toml b/Cargo.toml index 63e45c1..18f1b94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,11 +4,11 @@ members = [ "packages/agent_core", "packages/agent_proto", "packages/api_client", - "packages/ping_monitor", ] +resolver = "3" [workspace.package] -version = "0.16.5" +version = "0.17.0" [workspace.dependencies] tokio = { version = "1.48", features = ["full"] } @@ -35,4 +35,3 @@ strip = "debuginfo" opt-level = "z" lto = true codegen-units = 1 - diff --git a/packages/agent_cli/Cargo.toml b/packages/agent_cli/Cargo.toml index 242c211..c475dca 100644 --- a/packages/agent_cli/Cargo.toml +++ b/packages/agent_cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "playit-cli" version.workspace = true -edition = "2021" +edition = "2024" authors = ["Patrick Lorio "] description = "Making it easy to play games with friends. Makes your server public" repository = "https://github.com/playit-cloud/playit-agent" @@ -28,9 +28,9 @@ serde_yaml = "0.9" crossterm = "0.28" dotenv = "0.15.0" -playit-agent-core = { path = "../agent_core", version = "0.20.1" } +playit-agent-core = { path = "../agent_core", version = "0.17.0" } playit-agent-proto = { path = "../agent_proto", version = "1.3.0" } -playit-api-client = { path = "../api_client", version = "0.1.2" } +playit-api-client = { path = "../api_client", version = "0.2.0" } # playit-ping-monitor = { path = "../ping_monitor" } [target.'cfg(windows)'.build-dependencies] diff --git a/packages/agent_cli/src/autorun.rs b/packages/agent_cli/src/autorun.rs index 1e91fcf..21a6b19 100644 --- a/packages/agent_cli/src/autorun.rs +++ b/packages/agent_cli/src/autorun.rs @@ -2,7 +2,7 @@ use std::{fmt::Write, net::SocketAddr, sync::Arc, time::Duration}; use playit_agent_core::{ network::{ - origin_lookup::{OriginLookup, OriginResource}, + origin_lookup::{OriginLookup, OriginResource, OriginTarget}, tcp::tcp_settings::TcpSettings, udp::udp_settings::UdpSettings, }, @@ -13,7 +13,7 @@ use playit_agent_proto::PortProto; use playit_api_client::api::*; // use playit_ping_monitor::PingMonitor; -use crate::{playit_secret::PlayitSecret, ui::UI, CliError, API_BASE}; +use crate::{API_BASE, CliError, playit_secret::PlayitSecret, ui::UI}; pub async fn autorun(ui: &mut UI, mut secret: PlayitSecret) -> Result<(), CliError> { let secret_code = secret.ensure_valid(ui).await?.get_or_setup(ui).await?; @@ -35,7 +35,7 @@ pub async fn autorun(ui: &mut UI, mut secret: PlayitSecret) -> Result<(), CliErr let lookup = Arc::new(OriginLookup::default()); lookup - .update_from_run_data(&api.agents_rundata().await?) + .update_from_run_data(&api.v1_agents_rundata().await?) .await; let mut error_count = 0; @@ -75,8 +75,8 @@ pub async fn autorun(ui: &mut UI, mut secret: PlayitSecret) -> Result<(), CliErr loop { tokio::time::sleep(Duration::from_secs(3)).await; - let account_tunnels_res = api.agents_rundata().await; - let agent_data = match account_tunnels_res { + let account_tunnels_res = api.v1_agents_rundata().await; + let mut agent_data = match account_tunnels_res { Ok(v) => v, Err(error) => { ui.write_error("Failed to load latest tunnels", error).await; @@ -94,8 +94,8 @@ pub async fn autorun(ui: &mut UI, mut secret: PlayitSecret) -> Result<(), CliErr agent_data.tunnels.len() ); - match agent_data.account_status { - AgentAccountStatus::Guest => 'login_link: { + match agent_data.permissions.account_status { + AccountStatus::Guest => 'login_link: { let now = now_milli(); match &guest_login_link { @@ -118,105 +118,64 @@ pub async fn autorun(ui: &mut UI, mut secret: PlayitSecret) -> Result<(), CliErr } } } - AgentAccountStatus::EmailNotVerified => { + AccountStatus::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::AgentOverLimit => { - writeln!(msg, "Too many agents: https://playit.gg/account/agents").unwrap(); - } - AgentAccountStatus::AgentDisabled => { - writeln!( - msg, - "Account disabled: https://playit.gg/account/agents/{}", - agent_data.agent_id - ) - .unwrap(); + AccountStatus::Verified => {} + } + + agent_data.notices.sort_by_key(|n| n.priority); + + for notice in &agent_data.notices { + writeln!(msg, "[{:?}] {}", notice.priority, notice.message).unwrap(); + if let Some(link) = ¬ice.resolve_link { + writeln!(msg, "{link}").unwrap(); } - AgentAccountStatus::Ready => {} } writeln!(msg, "\nTUNNELS").unwrap(); if agent_data.tunnels.is_empty() && agent_data.pending.is_empty() { - let agent_id = match agent_data.agent_type { - AgentType::Default => "default".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 + agent_data.agent_id ) .unwrap(); } 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_deref() { - Some("minecraft-java") => addr.clone(), - _ => format!("{}:{}", addr, tunnel.port.from), + let Some(origin) = OriginResource::from_agent_tunnel(&tunnel) else { + continue; }; - 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(); + if let Some(reason) = &tunnel.disabled_reason { + writeln!(msg, "{} => (disabled {reason})", tunnel.display_address).unwrap(); + continue; } + + let dst = match origin.target { + OriginTarget::Https { + ip, + http_port, + https_port, + } => format!("{ip} (http: {http_port}, https: {https_port})"), + OriginTarget::Port { ip, port } => SocketAddr::new(ip, port).to_string(), + }; + + writeln!(msg, "{} => {}", tunnel.display_address, 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(); - } + writeln!( + msg, + "tunnel ({}): https://playit.gg/account/tunnels/{}", + tunnel.status_msg, tunnel.id + ) + .unwrap(); } } diff --git a/packages/agent_cli/src/main.rs b/packages/agent_cli/src/main.rs index 8cb33b9..429a595 100644 --- a/packages/agent_cli/src/main.rs +++ b/packages/agent_cli/src/main.rs @@ -3,10 +3,9 @@ use std::fmt::{Display, Formatter}; use std::sync::LazyLock; use std::time::Duration; -use clap::{arg, Command}; -use playit_agent_core::agent_control::platform::get_platform; -use playit_agent_core::agent_control::version::register_version; -use playit_agent_core::PROTOCOL_VERSION; +use clap::{Command, arg}; +use playit_agent_core::agent_control::platform::current_platform; +use playit_agent_core::agent_control::version::{help_register_version, register_platform}; use rand::Rng; use uuid::Uuid; @@ -14,11 +13,11 @@ use autorun::autorun; use playit_agent_core::agent_control::errors::SetupError; use playit_agent_core::utils::now_milli; use playit_api_client::http_client::HttpClientError; -use playit_api_client::{api::*, PlayitApi}; +use playit_api_client::{PlayitApi, api::*}; use playit_secret::PlayitSecret; use crate::signal_handle::get_signal_handle; -use crate::ui::{UISettings, UI}; +use crate::ui::{UI, UISettings}; pub static API_BASE: LazyLock = LazyLock::new(|| dotenv::var("API_BASE").unwrap_or("https://api.playit.gg".to_string())); @@ -38,19 +37,15 @@ async fn main() -> Result { let platform = if matches.get_flag("platform_docker") { Platform::Docker } else { - get_platform() + current_platform() }; - register_version(PlayitAgentVersion { - version: AgentVersion { - platform, - version: env!("CARGO_PKG_VERSION").to_string(), - has_expired: false, - }, - official: true, - details_website: None, - proto_version: PROTOCOL_VERSION, - }); + register_platform(platform); + + help_register_version( + env!("CARGO_PKG_VERSION"), + "308943e8-faef-4835-a2ba-270351f72aa3", + ); } let mut secret = PlayitSecret::from_args(&matches).await; @@ -78,7 +73,7 @@ async fn main() -> Result { (true, None) => { let (non_blocking, guard) = tracing_appender::non_blocking(std::io::stdout()); tracing_subscriber::fmt() - .with_ansi(get_platform() == Platform::Linux) + .with_ansi(current_platform() == Platform::Linux) .with_writer(non_blocking) .init(); Some(guard) @@ -169,45 +164,11 @@ async fn main() -> Result { .expect("invalid wait value"); let secret_key = - claim_exchange(&mut ui, claim_code, AgentType::SelfManaged, wait).await?; + claim_exchange(&mut ui, claim_code, ClaimAgentType::SelfManaged, wait).await?; ui.write_screen(secret_key).await; } _ => return Err(CliError::NotImplemented), }, - Some(("tunnels", m)) => match m.subcommand() { - Some(("prepare", m)) => { - unimplemented!() - // let api = secret.create_api().await?; - - // let name = m.get_one::("NAME").cloned(); - // let tunnel_type: Option = m.get_one::("TUNNEL_TYPE") - // .and_then(|v| serde_json::from_str(&format!("{:?}", v)).ok()); - // let port_type = serde_json::from_str::(&format!("{:?}", m.get_one::("PORT_TYPE").expect("required"))) - // .map_err(|_| CliError::InvalidPortType)?; - // let port_count = m.get_one::("PORT_COUNT").expect("required") - // .parse::().map_err(|_| CliError::InvalidPortCount)?; - // let exact = m.get_flag("exact"); - // let ignore_name = m.get_flag("ignore_name"); - - // let tunnel_id = tunnels_prepare( - // &api, name, tunnel_type, port_type, - // port_count, exact, ignore_name, - // ).await?; - - // println!("{}", tunnel_id); - } - Some(("list", _)) => { - let api = secret.create_api().await?; - 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), - }, _ => return Err(CliError::NotImplemented), } @@ -216,7 +177,7 @@ async fn main() -> Result { pub fn claim_generate() -> String { let mut buffer = [0u8; 5]; - rand::thread_rng().fill(&mut buffer); + rand::rng().fill(&mut buffer); hex::encode(&buffer) } @@ -231,7 +192,7 @@ pub fn claim_url(code: &str) -> Result { pub async fn claim_exchange( ui: &mut UI, claim_code: &str, - agent_type: AgentType, + agent_type: ClaimAgentType, wait_sec: u32, ) -> Result { let api = PlayitApi::create(API_BASE.to_string(), None); diff --git a/packages/agent_cli/src/playit_secret.rs b/packages/agent_cli/src/playit_secret.rs index 7c97dde..1de0fdf 100644 --- a/packages/agent_cli/src/playit_secret.rs +++ b/packages/agent_cli/src/playit_secret.rs @@ -1,11 +1,11 @@ use std::time::Duration; use clap::ArgMatches; -use playit_api_client::{api::*, PlayitApi}; +use playit_api_client::{PlayitApi, api::*}; use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; -use crate::{claim_exchange, claim_generate, ui::UI, CliError, API_BASE}; +use crate::{API_BASE, CliError, claim_exchange, claim_generate, ui::UI}; pub struct PlayitSecret { secret: RwLock>, @@ -145,7 +145,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, ClaimAgentType::Assignable, 0).await?; { let mut lock = self.secret.write().await; diff --git a/packages/agent_core/Cargo.toml b/packages/agent_core/Cargo.toml index e5b7ce5..b8f3d2d 100644 --- a/packages/agent_core/Cargo.toml +++ b/packages/agent_core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "playit-agent-core" -version = "0.20.1" -edition = "2021" +version.workspace = true +edition = "2024" description = "Contains the logic to create a playit.gg agent" license = "BSD-2-Clause" repository = "https://github.com/playit-cloud/playit-agent" @@ -24,7 +24,7 @@ futures-util = { workspace = true } message-encoding = { workspace = true } playit-agent-proto = { path = "../agent_proto", version = "1.3.0" } -playit-api-client = { path = "../api_client", version = "0.1.2" } +playit-api-client = { path = "../api_client", version = "0.2.0" } governor = "0.10.0" crossbeam = "0.8.4" diff --git a/packages/agent_core/src/agent_control/mod.rs b/packages/agent_core/src/agent_control/mod.rs index d6c41c3..462ab9b 100644 --- a/packages/agent_core/src/agent_control/mod.rs +++ b/packages/agent_core/src/agent_control/mod.rs @@ -1,7 +1,7 @@ use std::{ future::Future, net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, - sync::{atomic::AtomicUsize, Arc}, + sync::{Arc, atomic::AtomicUsize}, task::Poll, }; @@ -12,11 +12,11 @@ use version::get_version; pub use playit_api_client::api::SignedAgentKey; use playit_api_client::{ - api::{ReqAgentsRoutingGet, ReqProtoRegister}, PlayitApi, + api::{ReqAgentsRoutingGet, ReqProtoRegister}, }; -use crate::utils::error_helper::ErrorHelper; +use crate::{agent_control::platform::current_platform, utils::error_helper::ErrorHelper}; pub mod errors; @@ -243,9 +243,12 @@ impl AuthResource for AuthApi { let res = self .client .proto_register(ReqProtoRegister { - agent_version: get_version(), + agent_version: None, client_addr: pong.client_addr, tunnel_addr: pong.tunnel_addr, + proto_version: 2, + version: get_version(), + platform: current_platform(), }) .await .with_error(|error| tracing::error!(?error, "failed to sign and register"))?; diff --git a/packages/agent_core/src/agent_control/platform.rs b/packages/agent_core/src/agent_control/platform.rs index d5fe956..4b5f3d2 100644 --- a/packages/agent_core/src/agent_control/platform.rs +++ b/packages/agent_core/src/agent_control/platform.rs @@ -1,6 +1,6 @@ use playit_api_client::api::Platform; -pub fn get_platform() -> Platform { +pub fn current_platform() -> Platform { #[cfg(target_os = "windows")] return Platform::Windows; diff --git a/packages/agent_core/src/agent_control/version.rs b/packages/agent_core/src/agent_control/version.rs index bac36d3..472ed36 100644 --- a/packages/agent_core/src/agent_control/version.rs +++ b/packages/agent_core/src/agent_control/version.rs @@ -1,28 +1,50 @@ use std::sync::OnceLock; -use playit_api_client::api::{AgentVersion, PlayitAgentVersion}; +use playit_api_client::api::{AgentVersion, Platform}; +use std::str::FromStr; +use uuid::Uuid; -use crate::PROTOCOL_VERSION; +use crate::agent_control; -use super::platform::get_platform; +pub static AGENT_VERSION: OnceLock = OnceLock::new(); +pub static PLATFORM: OnceLock = OnceLock::new(); -pub static AGENT_VERSION: OnceLock = OnceLock::new(); +pub fn get_platform() -> Platform { + PLATFORM + .get_or_init(|| agent_control::current_platform()) + .clone() +} -pub fn register_version(version: PlayitAgentVersion) { - AGENT_VERSION.get_or_init(|| version); +pub fn register_platform(platform: Platform) { + PLATFORM.get_or_init(|| platform); +} + +pub fn get_version() -> AgentVersion { + help_register_version( + env!("CARGO_PKG_VERSION"), + "308943e8-faef-4835-a2ba-270351f72aa3", + ) } -pub fn get_version() -> PlayitAgentVersion { +pub fn help_register_version(v_str: &str, variant_id: &str) -> AgentVersion { AGENT_VERSION - .get_or_init(|| PlayitAgentVersion { - version: AgentVersion { - platform: get_platform(), - version: env!("CARGO_PKG_VERSION").to_string(), - has_expired: false, - }, - official: true, - details_website: None, - proto_version: PROTOCOL_VERSION, + .get_or_init(|| { + let mut parts = v_str.split("-").next().unwrap().split("."); + + let major = u32::from_str(parts.next().unwrap()).unwrap(); + let minor = u32::from_str(parts.next().unwrap()).unwrap(); + let patch = u32::from_str(parts.next().unwrap()).unwrap(); + + AgentVersion { + variant_id: Uuid::from_str(variant_id).expect("variant id must be UUID"), + version_major: major, + version_minor: minor, + version_patch: patch, + } }) .clone() } + +pub fn register_version(version: AgentVersion) { + AGENT_VERSION.get_or_init(|| version); +} diff --git a/packages/agent_core/src/network/origin_lookup.rs b/packages/agent_core/src/network/origin_lookup.rs index 29a6fac..649a625 100644 --- a/packages/agent_core/src/network/origin_lookup.rs +++ b/packages/agent_core/src/network/origin_lookup.rs @@ -1,7 +1,11 @@ -use std::{collections::HashMap, net::SocketAddr}; +use std::{ + collections::HashMap, + net::{IpAddr, SocketAddr}, + str::FromStr, +}; use playit_agent_proto::PortProto; -use playit_api_client::api::{AgentRunData, PortType, ProxyProtocol}; +use playit_api_client::api::{AgentRunDataV1, AgentTunnelV1, PortType, ProxyProtocol, TunnelType}; use tokio::sync::RwLock; #[derive(Default)] @@ -10,18 +14,13 @@ pub struct OriginLookup { } impl OriginLookup { - pub async fn update_from_run_data(&self, run_data: &AgentRunData) { - self.update(run_data.tunnels.iter().map(|tunn| OriginResource { - tunnel_id: tunn.internal_id, - proto: match tunn.proto { - PortType::Tcp => PortProto::Tcp, - PortType::Udp => PortProto::Udp, - PortType::Both => PortProto::Both, - }, - local_addr: SocketAddr::new(tunn.local_ip, tunn.local_port), - port_count: tunn.port.to - tunn.port.from, - proxy_protocol: tunn.proxy_protocol, - })) + pub async fn update_from_run_data(&self, run_data: &AgentRunDataV1) { + self.update( + run_data + .tunnels + .iter() + .filter_map(OriginResource::from_agent_tunnel), + ) .await; } @@ -88,22 +87,121 @@ struct Key { pub struct OriginResource { pub tunnel_id: u64, pub proto: PortProto, - pub local_addr: SocketAddr, + pub target: OriginTarget, pub port_count: u16, pub proxy_protocol: Option, } +#[derive(Debug, Clone)] +pub enum OriginTarget { + Https { + ip: IpAddr, + http_port: u16, + https_port: u16, + }, + Port { + ip: IpAddr, + port: u16, + }, +} + impl OriginResource { + pub fn from_agent_tunnel(tunn: &AgentTunnelV1) -> Option { + let tunnel_type = tunn + .tunnel_type + .clone() + .and_then(|v| serde_json::from_value::(serde_json::Value::String(v)).ok()); + + let proxy_protocol = tunn + .agent_config + .fields + .iter() + .find(|f| f.name.eq("proxy_protocol")) + .and_then(|v| { + serde_json::from_value::(serde_json::Value::String(v.value.clone())) + .ok() + }); + + let target = match tunnel_type { + Some(TunnelType::Https) => OriginTarget::Https { + ip: tunn + .agent_config + .fields + .iter() + .find(|f| f.name.eq("local_ip")) + .and_then(|v| IpAddr::from_str(&v.value).ok()) + .unwrap_or_else(|| "127.0.0.1".parse().unwrap()), + http_port: tunn + .agent_config + .fields + .iter() + .find(|f| f.name.eq("http_port")) + .and_then(|v| u16::from_str(&v.value).ok()) + .unwrap_or(80), + https_port: tunn + .agent_config + .fields + .iter() + .find(|f| f.name.eq("https_port")) + .and_then(|v| u16::from_str(&v.value).ok()) + .unwrap_or(443), + }, + _ => OriginTarget::Port { + ip: tunn + .agent_config + .fields + .iter() + .find(|f| f.name.eq("local_ip")) + .and_then(|v| IpAddr::from_str(&v.value).ok()) + .unwrap_or_else(|| "127.0.0.1".parse().unwrap()), + port: tunn + .agent_config + .fields + .iter() + .find(|f| f.name.eq("local_port")) + .and_then(|v| u16::from_str(&v.value).ok())?, + }, + }; + + Some(OriginResource { + tunnel_id: tunn.internal_id, + proto: match tunn.port_type { + PortType::Tcp => PortProto::Tcp, + PortType::Udp => PortProto::Udp, + PortType::Both => PortProto::Both, + }, + target, + port_count: tunn.port_count, + proxy_protocol, + }) + } + pub fn resolve_local(&self, port_offset: u16) -> Option { - if port_offset == 0 { - Some(self.local_addr) - } else if port_offset < self.port_count { - Some(SocketAddr::new( - self.local_addr.ip(), - self.local_addr.port() + port_offset, - )) - } else { - None + match &self.target { + OriginTarget::Https { + ip, + http_port, + https_port, + } => { + if port_offset == 0 { + Some(SocketAddr::new(*ip, *http_port)) + } else if port_offset == 1 { + Some(SocketAddr::new(*ip, *https_port)) + } else { + None + } + } + OriginTarget::Port { ip, port } => { + if self.port_count == 0 { + return Some(SocketAddr::new(*ip, *port)); + } + + if self.port_count <= port_offset { + return None; + } + + Some(SocketAddr::new(*ip, *port + port_offset)) + } } } } diff --git a/packages/agent_core/src/network/udp/udp_clients.rs b/packages/agent_core/src/network/udp/udp_clients.rs index f909d3f..d375c52 100644 --- a/packages/agent_core/src/network/udp/udp_clients.rs +++ b/packages/agent_core/src/network/udp/udp_clients.rs @@ -1,5 +1,5 @@ use std::{ - collections::{hash_map, HashMap}, + collections::{HashMap, hash_map}, net::{IpAddr, SocketAddr, SocketAddrV4}, num::NonZeroU32, sync::Arc, @@ -10,11 +10,13 @@ use playit_api_client::api::ProxyProtocol; use slab::Slab; use tokio::{ net::UdpSocket, - sync::mpsc::{channel, Receiver}, + sync::mpsc::{Receiver, channel}, }; use crate::network::{ - lan_address::LanAddress, origin_lookup::OriginLookup, proxy_protocol::ProxyProtocolHeader, + lan_address::LanAddress, + origin_lookup::{OriginLookup, OriginTarget}, + proxy_protocol::ProxyProtocolHeader, }; use playit_agent_proto::udp_proto::UdpFlow; @@ -140,17 +142,25 @@ impl UdpClients { return None; }; - if tunnel.local_addr.ip() != IpAddr::V4(*source.ip()) { + let OriginTarget::Port { + ip: local_ip, + port: port_start, + } = tunnel.target + else { + return None; + }; + + if local_ip != IpAddr::V4(*source.ip()) { udp_errors().origin_reject_addr_differ.inc(); return None; } - if source.port() < tunnel.local_addr.port() { + if source.port() < port_start { udp_errors().origin_reject_port_too_low.inc(); return None; } - let port_offset = source.port() - tunnel.local_addr.port(); + let port_offset = source.port() - port_start; if tunnel.port_count <= port_offset { udp_errors().origin_reject_port_too_high.inc(); return None; @@ -195,16 +205,19 @@ impl UdpClients { tunnel_id: extension.tunnel_id.get(), }; - let target_addr = if extension.port_offset == 0 { - let SocketAddr::V4(addr) = origin.local_addr else { - return; - }; - addr - } else { - let IpAddr::V4(ip) = origin.local_addr.ip() else { + let OriginTarget::Port { + ip: local_ip, + port: port_start, + } = origin.target + else { + return; + }; + + let target_addr = { + let IpAddr::V4(ip) = local_ip else { return; }; - SocketAddrV4::new(ip, origin.local_addr.port() + extension.port_offset) + SocketAddrV4::new(ip, port_start + extension.port_offset) }; match self.virtual_client_lookup.entry(key) { @@ -229,8 +242,7 @@ impl UdpClients { return; } - let special_lan = - origin.local_addr.ip().is_loopback() && origin.proxy_protocol.is_none(); + let special_lan = local_ip.is_loopback() && origin.proxy_protocol.is_none(); let socket = match v.key().create_socket(special_lan).await { Ok(socket) => Arc::new(socket), diff --git a/packages/api_client/Cargo.toml b/packages/api_client/Cargo.toml index 7db9c15..c7f81bd 100644 --- a/packages/api_client/Cargo.toml +++ b/packages/api_client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "playit-api-client" -version = "0.1.2" -edition = "2021" +version = "0.2.0" +edition = "2024" description = "Contains the logic to create a playit.gg agent" license = "BSD-2-Clause" repository = "https://github.com/playit-cloud/playit-agent" @@ -15,6 +15,7 @@ serde_json = { workspace = true } serde = { workspace = true } uuid = { workspace = true } byteorder = { workspace = true } +chrono = { workspace = true } # use rustls with "ring" and not "aws-lc-rs", having trouble cross compiling "aws-lc-rs" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "gzip"] } diff --git a/packages/api_client/src/api.rs b/packages/api_client/src/api.rs index 92cc87e..5e16bf5 100644 --- a/packages/api_client/src/api.rs +++ b/packages/api_client/src/api.rs @@ -1,220 +1,329 @@ +#![cfg_attr(rustfmt, rustfmt_skip)] impl PlayitApiClient { - pub fn new(client: C) -> Self { - PlayitApiClient { client } - } - pub fn get_client(&self) -> &C { - &self.client - } - fn unwrap(res: Result, C::Error>) -> Result> { - match res { - Ok(ApiResult::Success(v)) => Ok(v), - Ok(ApiResult::Fail(fail)) => Err(ApiError::Fail(fail)), - Ok(ApiResult::Error(error)) => Err(ApiError::ApiError(error)), - Err(error) => Err(ApiError::ClientError(error)), - } - } - fn unwrap_no_fail( - res: Result, C::Error>, - ) -> Result> { - match res { - Ok(ApiResult::Success(v)) => Ok(v), - Ok(ApiResult::Fail(_)) => panic!(), - Ok(ApiResult::Error(error)) => Err(ApiErrorNoFail::ApiError(error)), - Err(error) => Err(ApiErrorNoFail::ClientError(error)), - } - } - #[track_caller] - pub fn tunnels_create( - &self, - req: ReqTunnelsCreate, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/tunnels/create", req).await) } - } - #[track_caller] - pub fn tunnels_delete( - &self, - req: ReqTunnelsDelete, - ) -> impl std::future::Future>> + '_ { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/tunnels/delete", req).await) } - } - #[track_caller] - pub fn claim_details( - &self, - req: ReqClaimDetails, - ) -> impl std::future::Future< - Output = Result>, - > + '_ { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/claim/details", req).await) } - } - #[track_caller] - pub fn claim_setup( - &self, - req: ReqClaimSetup, - ) -> impl std::future::Future< - Output = Result>, - > + '_ { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/claim/setup", req).await) } - } - #[track_caller] - pub fn claim_exchange( - &self, - req: ReqClaimExchange, - ) -> impl std::future::Future< - Output = Result>, - > + '_ { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/claim/exchange", req).await) } - } - #[track_caller] - pub fn claim_accept( - &self, - req: ReqClaimAccept, - ) -> impl std::future::Future>> - + '_ { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/claim/accept", req).await) } - } - #[track_caller] - pub fn claim_reject( - &self, - req: ReqClaimReject, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/claim/reject", req).await) } - } - #[track_caller] - pub fn proto_register( - &self, - req: ReqProtoRegister, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { Self::unwrap_no_fail(self.client.call(caller, "/proto/register", req).await) } - } - #[track_caller] - pub fn login_guest( - &self, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { - Self::unwrap( - self.client - .call(caller, "/login/guest", ReqLoginGuest {}) - .await, - ) - } - } - #[track_caller] - pub fn agents_routing_get( - &self, - req: ReqAgentsRoutingGet, - ) -> impl std::future::Future< - Output = Result>, - > + '_ { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/agents/routing/get", req).await) } - } - #[track_caller] - pub fn agents_rundata( - &self, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { - Self::unwrap_no_fail( - self.client - .call(caller, "/agents/rundata", ReqAgentsRundata {}) - .await, - ) - } - } - #[track_caller] - pub fn ping_submit( - &self, - req: ReqPingSubmit, - ) -> impl std::future::Future>> + '_ { - let caller = std::panic::Location::caller(); - async { Self::unwrap_no_fail(self.client.call(caller, "/ping/submit", req).await) } - } - #[track_caller] - pub fn ping_get( - &self, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { Self::unwrap_no_fail(self.client.call(caller, "/ping/get", ReqPingGet {}).await) } - } - #[track_caller] - pub fn tunnels_list_json( - &self, - req: ReqTunnelsList, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { Self::unwrap_no_fail(self.client.call(caller, "/tunnels/list", req).await) } - } - #[track_caller] - pub fn agents_list_json( - &self, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { - Self::unwrap_no_fail( - self.client - .call(caller, "/agents/list", ReqAgentsList {}) - .await, - ) - } - } - #[track_caller] - pub fn query_region( - &self, - req: ReqQueryRegion, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/query/region", req).await) } - } - #[track_caller] - pub fn tunnels_update( - &self, - req: ReqTunnelsUpdate, - ) -> impl std::future::Future>> + '_ { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/tunnels/update", req).await) } - } - #[track_caller] - pub fn tunnels_firewall_assign( - &self, - req: ReqTunnelsFirewallAssign, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { - Self::unwrap( - self.client - .call(caller, "/tunnels/firewall/assign", req) - .await, - ) - } - } - #[track_caller] - pub fn tunnels_proxy_set( - &self, - req: ReqTunnelsProxySet, - ) -> impl std::future::Future>> + '_ - { - let caller = std::panic::Location::caller(); - async { Self::unwrap(self.client.call(caller, "/tunnels/proxy/set", req).await) } - } + pub fn new(client: C) -> Self { + PlayitApiClient { client } + } + pub fn get_client(&self) -> &C { + &self.client + } + fn unwrap(res: Result, C::Error>) -> Result> { + match res { + Ok(ApiResult::Success(v)) => Ok(v), + Ok(ApiResult::Fail(fail)) => Err(ApiError::Fail(fail)), + Ok(ApiResult::Error(error)) => Err(ApiError::ApiError(error)), + Err(error) => Err(ApiError::ClientError(error)), + } + } + fn unwrap_no_fail(res: Result, C::Error>) -> Result> { + match res { + Ok(ApiResult::Success(v)) => Ok(v), + Ok(ApiResult::Fail(_)) => panic!(), + Ok(ApiResult::Error(error)) => Err(ApiErrorNoFail::ApiError(error)), + Err(error) => Err(ApiErrorNoFail::ClientError(error)), + } + } + #[track_caller] + pub fn v1_tunnels_list(&self) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/v1/tunnels/list", ReqTunnelsListV1 {}).await) + } + } + #[track_caller] + pub fn v1_tunnels_create(&self, req: ReqTunnelsCreateV1) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/v1/tunnels/create", req).await) + } + } + #[track_caller] + pub fn v1_schemas_get(&self, req: ReqSchemasGetV1) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/v1/schemas/get", req).await) + } + } + #[track_caller] + pub fn v1_tunnels_config(&self, req: ReqTunnelsConfigV1) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/v1/tunnels/config", req).await) + } + } + #[track_caller] + pub fn v1_tunnels_propset(&self, req: ReqTunnelsPropset) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/v1/tunnels/propset", req).await) + } + } + #[track_caller] + pub fn v1_agents_rundata(&self) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/v1/agents/rundata", ReqAgentsRundataV1 {}).await) + } + } + #[track_caller] + pub fn info_pops(&self) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/info/pops", ReqInfoPops {}).await) + } + } + #[track_caller] + pub fn login_signin(&self, req: ReqLoginSignin) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/login/signin", req).await) + } + } + #[track_caller] + pub fn login_clearcookie(&self) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/login/clearcookie", ReqLoginClearcookie {}).await) + } + } + #[track_caller] + pub fn login_create_guest(&self) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/login/create/guest", ReqLoginCreateGuest {}).await) + } + } + #[track_caller] + pub fn login_guest(&self) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/login/guest", ReqLoginGuest {}).await) + } + } + #[track_caller] + pub fn login_reset_password(&self, req: ReqLoginResetPassword) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/login/reset/password", req).await) + } + } + #[track_caller] + pub fn login_reset_send(&self, req: ReqLoginResetSend) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/login/reset/send", req).await) + } + } + #[track_caller] + pub fn tunnels_create(&self, req: ReqTunnelsCreate) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/tunnels/create", req).await) + } + } + #[track_caller] + pub fn tunnels_list(&self, req: ReqTunnelsList) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/tunnels/list", req).await) + } + } + #[track_caller] + pub fn tunnels_update(&self, req: ReqTunnelsUpdate) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/tunnels/update", req).await) + } + } + #[track_caller] + pub fn tunnels_delete(&self, req: ReqTunnelsDelete) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/tunnels/delete", req).await) + } + } + #[track_caller] + pub fn tunnels_rename(&self, req: ReqTunnelsRename) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/tunnels/rename", req).await) + } + } + #[track_caller] + pub fn tunnels_firewall_assign(&self, req: ReqTunnelsFirewallAssign) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/tunnels/firewall/assign", req).await) + } + } + #[track_caller] + pub fn tunnels_ratelimit(&self, req: ReqTunnelsRatelimit) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/tunnels/ratelimit", req).await) + } + } + #[track_caller] + pub fn tunnels_enable(&self, req: ReqTunnelsEnable) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/tunnels/enable", req).await) + } + } + #[track_caller] + pub fn tunnels_proxy_set(&self, req: ReqTunnelsProxySet) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/tunnels/proxy/set", req).await) + } + } + #[track_caller] + pub fn claim_setup(&self, req: ReqClaimSetup) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/claim/setup", req).await) + } + } + #[track_caller] + pub fn claim_exchange(&self, req: ReqClaimExchange) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/claim/exchange", req).await) + } + } + #[track_caller] + pub fn agents_rename(&self, req: ReqAgentsRename) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/agents/rename", req).await) + } + } + #[track_caller] + pub fn agents_routing_set(&self, req: ReqAgentsRoutingSet) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/agents/routing/set", req).await) + } + } + #[track_caller] + pub fn agents_routing_get(&self, req: ReqAgentsRoutingGet) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/agents/routing/get", req).await) + } + } + #[track_caller] + pub fn agents_rundata(&self) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/agents/rundata", ReqAgentsRundata {}).await) + } + } + #[track_caller] + pub fn domains_list(&self) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/domains/list", ReqDomainsList {}).await) + } + } + #[track_caller] + pub fn shop_prices(&self) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/shop/prices", ReqShopPrices {}).await) + } + } + #[track_caller] + pub fn shop_availability_custom_domain(&self, req: ReqShopAvailabilityCustomDomain) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap_no_fail(self.client.call(caller, "/shop/availability/custom_domain", req).await) + } + } + #[track_caller] + pub fn proto_register(&self, req: ReqProtoRegister) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/proto/register", req).await) + } + } + #[track_caller] + pub fn charge_get(&self, req: ReqChargeGet) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/charge/get", req).await) + } + } + #[track_caller] + pub fn charge_refund(&self, req: ReqChargeRefund) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/charge/refund", req).await) + } + } + #[track_caller] + pub fn query_region(&self, req: ReqQueryRegion) -> impl std::future::Future>> + '_ { + let caller = std::panic::Location::caller(); + async { + Self::unwrap(self.client.call(caller, "/query/region", req).await) + } + } +} +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "type", content = "message")] +pub enum ApiResponseError { + #[serde(rename = "validation")] + Validation(String), + #[serde(rename = "path-not-found")] + PathNotFound(PathNotFound), + #[serde(rename = "auth")] + Auth(AuthError), + #[serde(rename = "internal")] + Internal(ApiInternalError), +} + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct PathNotFound { + pub path: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum AuthError { + AuthRequired, + InvalidHeader, + InvalidSignature, + InvalidTimestamp, + InvalidApiKey, + InvalidAgentKey, + SessionExpired, + InvalidAuthType, + ScopeNotAllowed, + NoLongerValid, + GuestAccountNotAllowed, + EmailMustBeVerified, + AccountDoesNotExist, + AdminOnly, + InvalidToken, + TotpRequred, + NotAllowedWithReadOnly, + DefaultAgentBlocked, + AgentNotSelfManaged, + SelfManagedAgentCanOnlyAffectSelf, + AccountNotAuthorized, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ApiInternalError { + pub trace_id: String, +} + +impl std::fmt::Display for ApiResponseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for ApiResponseError { } #[derive(serde::Serialize, serde::Deserialize, Debug)] @@ -241,7 +350,9 @@ impl std::fmt::Display for ApiError std::error::Error for ApiError {} +impl std::error::Error for ApiError { +} + #[derive(Debug, serde::Serialize)] pub enum ApiErrorNoFail { @@ -255,21 +366,15 @@ impl std::fmt::Display for ApiErrorNoFail { } } -impl std::error::Error for ApiErrorNoFail {} +impl std::error::Error for ApiErrorNoFail { +} + + pub trait PlayitHttpClient { type Error; - fn call< - Req: serde::Serialize + std::marker::Send, - Res: serde::de::DeserializeOwned, - Err: serde::de::DeserializeOwned, - >( - &self, - caller: &'static std::panic::Location<'static>, - path: &str, - req: Req, - ) -> impl std::future::Future, Self::Error>>; + fn call(&self, caller: &'static std::panic::Location<'static>, path: &str, req: Req) -> impl std::future::Future, Self::Error>>; } #[derive(Clone)] @@ -278,736 +383,1775 @@ pub struct PlayitApiClient { } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "type", content = "message")] -pub enum ApiResponseError { - #[serde(rename = "validation")] - Validation(String), - #[serde(rename = "path-not-found")] - PathNotFound(PathNotFound), - #[serde(rename = "auth")] - Auth(AuthError), - #[serde(rename = "internal")] - Internal(ApiInternalError), +pub struct ReqTunnelsListV1 { } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct PathNotFound { - pub path: String, +pub struct AccountTunnelsV1 { + pub tunnels: Vec, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum AuthError { - AuthRequired, - InvalidHeader, - InvalidSignature, - InvalidTimestamp, - InvalidApiKey, - InvalidAgentKey, - SessionExpired, - InvalidAuthType, - ScopeNotAllowed, - NoLongerValid, - GuestAccountNotAllowed, - EmailMustBeVerified, - AccountDoesNotExist, - AdminOnly, - InvalidToken, - TotpRequred, - NotAllowedWithReadOnly, - AgentNotSelfManaged, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AccountTunnelV1 { + pub id: uuid::Uuid, + pub created_at: chrono::DateTime, + pub name: Option, + pub user_enabled: bool, + pub offline_reasons: Option>, + pub tunnel_type: Option, + pub port_type: PortType, + pub port_count: u16, + pub firewall_id: Option, + pub props: AccountTunnelProps, + pub origin: AccountTunnelOrigin, + pub port_allocation_requests: Vec, + pub public_allocations: Vec, + pub connect_addresses: Vec, +} + + + + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum AccountTunnelOfflineReason { + OriginNotSet, + AgentDisabled, + AgentOverLimit, + TunnelDisabled, + PublicAllocationMissing, + PublicAllocationPending, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum TunnelType { + #[serde(rename = "minecraft-java")] + MinecraftJava, + #[serde(rename = "minecraft-bedrock")] + MinecraftBedrock, + #[serde(rename = "valheim")] + Valheim, + #[serde(rename = "terraria")] + Terraria, + #[serde(rename = "starbound")] + Starbound, + #[serde(rename = "rust")] + Rust, + #[serde(rename = "7days")] + Num7days, + #[serde(rename = "unturned")] + Unturned, + #[serde(rename = "https")] + Https, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum PortType { + #[serde(rename = "tcp")] + Tcp, + #[serde(rename = "udp")] + Udp, + #[serde(rename = "both")] + Both, +} + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AccountTunnelProps { + pub hostname_verify_level: HostnameVerifyLevel, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum HostnameVerifyLevel { + None, + NoRawIp, + NoAutoName, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ApiInternalError { - pub trace_id: String, +#[serde(tag = "type", content = "details")] +pub enum AccountTunnelOrigin { + #[serde(rename = "not-set")] + NotSet(TunnelOriginNotSet), + #[serde(rename = "agent")] + Agent(TunnelToAgent), } -impl std::fmt::Display for ApiResponseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct TunnelOriginNotSet { + pub agent_config: Option, } -impl std::error::Error for ApiResponseError {} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqTunnelsCreate { - pub name: Option, - pub tunnel_type: Option, - pub port_type: PortType, - pub port_count: u16, - pub origin: TunnelOriginCreate, - pub enabled: bool, - pub alloc: Option, - pub firewall_id: Option, - pub proxy_protocol: Option, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum TunnelType { - #[serde(rename = "minecraft-java")] - MinecraftJava, - #[serde(rename = "minecraft-bedrock")] - MinecraftBedrock, - #[serde(rename = "valheim")] - Valheim, - #[serde(rename = "terraria")] - Terraria, - #[serde(rename = "starbound")] - Starbound, - #[serde(rename = "rust")] - Rust, - #[serde(rename = "7days")] - Num7days, - #[serde(rename = "unturned")] - Unturned, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum PortType { - #[serde(rename = "tcp")] - Tcp, - #[serde(rename = "udp")] - Udp, - #[serde(rename = "both")] - Both, +pub struct HasAgentConfig { + pub config_schema_id: uuid::Uuid, + pub config_data: AgentTunnelConfig, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "type", content = "data")] -pub enum TunnelOriginCreate { - #[serde(rename = "default")] - Default(AssignedDefaultCreate), - #[serde(rename = "agent")] - Agent(AssignedAgentCreate), - #[serde(rename = "managed")] - Managed(AssignedManagedCreate), +pub struct AgentTunnelConfig { + pub fields: Vec, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AssignedDefaultCreate { - pub local_ip: std::net::IpAddr, - pub local_port: Option, +pub struct AgentTunnelAttr { + pub name: String, + pub value: String, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AssignedAgentCreate { - pub agent_id: uuid::Uuid, - pub local_ip: std::net::IpAddr, - pub local_port: Option, +pub struct TunnelToAgent { + pub agent_id: uuid::Uuid, + pub name: String, + pub config_schema_id: uuid::Uuid, + pub config_data: AgentTunnelConfig, + pub config_invalid: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AssignedManagedCreate { - pub agent_id: Option, +pub struct InvalidTunnelConfig { + pub agent_schema_id: uuid::Uuid, + pub current_schema: AgentTunnelSchema, + pub target_schema: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "type", content = "details")] -pub enum TunnelCreateUseAllocation { - #[serde(rename = "dedicated-ip")] - DedicatedIp(UseAllocDedicatedIp), - #[serde(rename = "port-allocation")] - PortAllocation(UseAllocPortAlloc), - #[serde(rename = "region")] - Region(UseRegion), +pub struct AgentTunnelSchema { + pub fields: std::collections::HashMap, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct UseAllocDedicatedIp { - pub ip_hostname: String, - pub port: Option, +pub struct AgentTunnelSchemaField { + pub label: Option, + pub description: Option, + pub value_type: AgentTunnelAttrType, + pub allow_null: bool, + pub default_value: Option, + pub variants: Option>, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum AgentTunnelAttrType { + Ip, + Ip4, + Ip6, + SockAddr, + SockAddr4, + SockAddr6, + Port, + U64, + I64, + Boolean, + String, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct UseAllocPortAlloc { - pub alloc_id: uuid::Uuid, +pub struct PortAllocationRequest { + pub id: uuid::Uuid, + pub status: PortAllocationStatus, + pub region: PlayitNetwork, + pub public_port: Option, + pub public_ip: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum PortAllocationStatus { + Pending, + RanOutOfPorts, + PublicPortNotAvailable, + NoPortsAvailableOnIp, + AccountPortLimitReached, + #[serde(rename = "Other#catch_all")] + OtherCatchAll, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum PlayitNetwork { + #[serde(rename = "global")] + Global, + #[serde(rename = "north-america")] + NorthAmerica, + #[serde(rename = "europe")] + Europe, + #[serde(rename = "asia")] + Asia, + #[serde(rename = "india")] + India, + #[serde(rename = "south-america")] + SouthAmerica, + #[serde(rename = "chile")] + Chile, + #[serde(rename = "seattle-washington")] + SeattleWashington, + #[serde(rename = "los-angeles-california")] + LosAngelesCalifornia, + #[serde(rename = "denver-colorado")] + DenverColorado, + #[serde(rename = "dallas-texas")] + DallasTexas, + #[serde(rename = "chicago-illinois")] + ChicagoIllinois, + #[serde(rename = "new-york")] + NewYork, + #[serde(rename = "_NaReserved1")] + NaReserved1, + #[serde(rename = "_NaReserved2")] + NaReserved2, + #[serde(rename = "united-kingdom")] + UnitedKingdom, + #[serde(rename = "germany")] + Germany, + #[serde(rename = "sweden")] + Sweden, + #[serde(rename = "poland")] + Poland, + #[serde(rename = "romania")] + Romania, + #[serde(rename = "_Test")] + Test, + #[serde(rename = "japan")] + Japan, + #[serde(rename = "australia")] + Australia, } + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct UseRegion { - pub region: AllocationRegion, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum AllocationRegion { - #[serde(rename = "smart-global")] - SmartGlobal, - #[serde(rename = "global")] - Global, - #[serde(rename = "north-america")] - NorthAmerica, - #[serde(rename = "europe")] - Europe, - #[serde(rename = "asia")] - Asia, - #[serde(rename = "india")] - India, - #[serde(rename = "south-america")] - SouthAmerica, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum ProxyProtocol { - #[serde(rename = "proxy-protocol-v1")] - ProxyProtocolV1, - #[serde(rename = "proxy-protocol-v2")] - ProxyProtocolV2, +#[serde(tag = "type", content = "details")] +pub enum PublicAllocation { + #[serde(rename = "PortAllocation")] + PortAllocation(PortAllocation), + #[serde(rename = "HostnameRouting")] + HostnameRouting(HostnameRouting), } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ObjectId { - pub id: uuid::Uuid, +pub struct PortAllocation { + pub alloc_id: uuid::Uuid, + pub ip_region: PlayitNetwork, + pub ip_hostname: String, + pub auto_domain: String, + pub ip: std::net::IpAddr, + pub port: u16, + pub port_count: u16, + pub port_type: PortType, + pub expire_notice: Option, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum TunnelCreateError { - AgentIdRequired, - AgentNotFound, - InvalidAgentId, - DedicatedIpNotFound, - DedicatedIpPortNotAvailable, - DedicatedIpNotEnoughSpace, - PortAllocNotFound, - InvalidIpHostname, - ManagedMissingAgentId, - InvalidPortCount, - RequiresVerifiedAccount, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ExpireNotice { + pub disable_at: chrono::DateTime, + pub remove_at: chrono::DateTime, + pub reason: DisabledReason, } -impl std::fmt::Display for TunnelCreateError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum DisabledReason { + #[serde(rename = "requires-premium")] + RequiresPremium, + #[serde(rename = "over-port-limit")] + OverPortLimit, } -impl std::error::Error for TunnelCreateError {} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqTunnelsDelete { - pub tunnel_id: uuid::Uuid, +pub struct HostnameRouting { + pub id: Option, + pub hostname: String, + pub routing_type: HostnameRoutingType, + pub region: PlayitNetwork, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum DeleteError { - TunnelNotFound, +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum HostnameRoutingType { + #[serde(rename = "https")] + Https, + #[serde(rename = "minecraft-java")] + MinecraftJava, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqClaimDetails { - pub code: String, +#[serde(tag = "type", content = "value")] +pub enum ConnectAddress { + #[serde(rename = "addr4")] + Addr4(ConnectAddr4), + #[serde(rename = "addr6")] + Addr6(ConnectAddr6), + #[serde(rename = "ip4")] + Ip4(ConnectIp4), + #[serde(rename = "ip6")] + Ip6(ConnectIp6), + #[serde(rename = "auto")] + Auto(ConnectAutoName), + #[serde(rename = "domain")] + Domain(ConnectDomain), } #[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, +pub struct ConnectAddr4 { + pub address: std::net::SocketAddrV4, + pub source: ConnectAddressSource, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum AgentType { - #[serde(rename = "default")] - Default, - #[serde(rename = "assignable")] - Assignable, - #[serde(rename = "self-managed")] - SelfManaged, + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "resource", content = "id")] +pub enum ConnectAddressSource { + #[serde(rename = "port-allocation")] + PortAllocation(uuid::Uuid), + #[serde(rename = "hostname-routing")] + HostnameRouting(uuid::Uuid), } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum ClaimDetailsError { - AlreadyClaimed, - AlreadyRejected, - ClaimExpired, - DifferentOwner, - WaitingForAgent, - InvalidCode, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ConnectAddr6 { + pub address: std::net::SocketAddrV6, + pub source: ConnectAddressSource, } -impl std::fmt::Display for ClaimDetailsError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ConnectIp4 { + pub address: std::net::Ipv4Addr, + pub default_port: u16, + pub source: ConnectAddressSource, } -impl std::error::Error for ClaimDetailsError {} + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqClaimSetup { - pub code: String, - pub agent_type: AgentType, - pub version: String, +pub struct ConnectIp6 { + pub address: std::net::Ipv6Addr, + pub default_port: u16, + pub source: ConnectAddressSource, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum ClaimSetupResponse { - WaitingForUserVisit, - WaitingForUser, - UserAccepted, - UserRejected, + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ConnectAutoName { + pub address: String, + pub source: ConnectAddressSource, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum ClaimSetupError { - InvalidCode, - CodeExpired, - VersionTextTooLong, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ConnectDomain { + pub id: uuid::Uuid, + pub domain: String, + pub address: String, + pub mode: DomainMode, + pub source: ConnectAddressSource, } -impl std::fmt::Display for ClaimSetupError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum DomainMode { + Ip, + Srv, + SrvAndIp, + Hostname, } -impl std::error::Error for ClaimSetupError {} + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqClaimExchange { - pub code: String, +pub struct ReqTunnelsCreateV1 { + pub ports: TunnelPortDetails, + pub origin: AccountTunnelOriginCreate, + pub enabled: bool, + pub alloc: Option, + pub name: Option, + pub firewall_id: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AgentSecretKey { - pub secret_key: String, +#[serde(tag = "type", content = "details")] +pub enum TunnelPortDetails { + #[serde(rename = "tunnel-type")] + TunnelType(TunnelType), + #[serde(rename = "custom-tcp")] + CustomTcp(u16), + #[serde(rename = "custom-udp")] + CustomUdp(u16), + #[serde(rename = "custom-both")] + CustomBoth(u16), } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum ClaimExchangeError { - CodeNotFound, - CodeExpired, - UserRejected, - NotAccepted, - NotSetup, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "type", content = "data")] +pub enum AccountTunnelOriginCreate { + #[serde(rename = "agent")] + Agent(AgentOrigin), } -impl std::fmt::Display for ClaimExchangeError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentOrigin { + pub agent_id: Option, + pub config: AgentTunnelConfig, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "type", content = "details")] +pub enum CreateTunnelAllocationRequest { + #[serde(rename = "hostname")] + Hostname(UseHostname), + #[serde(rename = "dedicated-ip")] + DedicatedIp(UseAllocDedicatedIp), + #[serde(rename = "shared-ip")] + SharedIp(UseAllocSharedIp), + #[serde(rename = "region")] + Region(UseAllocRegion), + #[serde(rename = "port-allocation")] + PortAllocation(uuid::Uuid), } -impl std::error::Error for ClaimExchangeError {} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqClaimAccept { - pub code: String, - pub name: String, - pub agent_type: AgentType, +pub struct UseHostname { + pub hostname_id: uuid::Uuid, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AgentAccepted { - pub agent_id: uuid::Uuid, +pub struct UseAllocDedicatedIp { + pub ip_hostname: String, + pub port: Option, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum ClaimAcceptError { - InvalidCode, - AgentNotReady, - CodeNotFound, - InvalidAgentType, - ClaimAlreadyAccepted, - ClaimRejected, - CodeExpired, - InvalidName, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct UseAllocSharedIp { + pub ip_hostname: String, + pub port: Option, } -impl std::fmt::Display for ClaimAcceptError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct UseAllocRegion { + pub region: PlayitNetwork, + pub port: Option, } -impl std::error::Error for ClaimAcceptError {} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqClaimReject { - pub code: String, +pub struct ObjectId { + pub id: uuid::Uuid, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum TunnelCreateErrorV1 { + AgentNotFound, + InvalidAgentId, + DedicatedIpNotFound, + PortAllocNotFound, + InvalidIpHostname, + InvalidPortCount, + RequiresVerifiedAccount, + RegionNotSupported, + InvalidTunnelConfig, + FirewallNotFound, + TunnelNameIsNotAscii, + TunnelNameTooLong, + PortAllocDoesNotMatchPortDetails, + RegionRequiresPlayitPremium, + PortAllocCurrentlyAssigned, + PublicPortRequiresPlayitPremium, + AgentVersionTooOld, + RequiresPlayitPremium, + AllocRequestNotSupportedByPorts, + InvalidHostnameId, + HostnameHasTunnelTypeTarget, +} + +impl std::fmt::Display for TunnelCreateErrorV1 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for TunnelCreateErrorV1 { +} +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqSchemasGetV1 { + pub id: uuid::Uuid, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum ClaimRejectError { - InvalidCode, - CodeNotFound, - ClaimAccepted, - ClaimAlreadyRejected, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct SchemaData { + pub id: uuid::Uuid, + pub details: AgentSchema, } -impl std::fmt::Display for ClaimRejectError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentSchema { + pub default_schema: Option, + pub schemas: Vec, + pub only_explicit_schemas: bool, } -impl std::error::Error for ClaimRejectError {} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqProtoRegister { - pub agent_version: PlayitAgentVersion, - pub client_addr: std::net::SocketAddr, - pub tunnel_addr: std::net::SocketAddr, +pub struct AgentSchemaForTunnelType { + pub tunnel_type: AgentSchemaTunnelType, + pub schema: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct PlayitAgentVersion { - pub version: AgentVersion, - pub official: bool, - pub details_website: Option, - pub proto_version: u64, +#[serde(tag = "name", content = "details")] +pub enum AgentSchemaTunnelType { + #[serde(rename = "custom-tcp")] + CustomTcp(AgentTunnelTypeSupportedPorts), + #[serde(rename = "custom-udp")] + CustomUdp(AgentTunnelTypeSupportedPorts), + #[serde(rename = "custom-both")] + CustomBoth(AgentTunnelTypeSupportedPorts), + #[serde(rename = "tunnel-type")] + TunnelType(TunnelType), } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AgentVersion { - pub platform: Platform, - pub version: String, - pub has_expired: bool, +pub struct AgentTunnelTypeSupportedPorts { + pub min: u16, + pub max: u16, } -#[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 = "docker")] - Docker, - #[serde(rename = "minecraft-plugin")] - MinecraftPlugin, - #[serde(rename = "unknown")] - Unknown, +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum SchemaGetError { + SchemaNotFound, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct SignedAgentKey { - pub key: String, +pub struct ReqTunnelsConfigV1 { + pub tunnel_id: uuid::Uuid, + pub new_agent_id: Option, + pub new_config: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqLoginGuest {} +#[serde(tag = "error", content = "details")] +pub enum TunnelConfigError { + #[serde(rename = "TunnelNotFound")] + TunnelNotFound, + #[serde(rename = "AgentNotFound")] + AgentNotFound, + #[serde(rename = "AgentVersionUnknown")] + AgentVersionUnknown, + #[serde(rename = "CannotConfigTunnelWithoutAgent")] + CannotConfigTunnelWithoutAgent, + #[serde(rename = "SelfManagedAgentCannotReassignTunnel")] + SelfManagedAgentCannotReassignTunnel, + #[serde(rename = "InvalidConfig")] + InvalidConfig(AgentSchemaValidationError), + #[serde(rename = "ConfigNotCompatibleWithAgent")] + ConfigNotCompatibleWithAgent, + #[serde(rename = "NothingToUpdate")] + NothingToUpdate, +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct WebSession { - pub session_key: String, - pub auth: WebAuthToken, +#[serde(tag = "error", content = "field")] +pub enum AgentSchemaValidationError { + #[serde(rename = "NoSchemaFound")] + NoSchemaFound, + #[serde(rename = "TooManyFields")] + TooManyFields, + #[serde(rename = "TunnelTypeNotSupported")] + TunnelTypeNotSupported(AgentTunnelPortAllocTypeDetails), + #[serde(rename = "UnknownField")] + UnknownField(String), + #[serde(rename = "MissingRequiredField")] + MissingRequiredField(String), + #[serde(rename = "InvalidValueForType")] + InvalidValueForType(String), + #[serde(rename = "ValueNotInVariants")] + ValueNotInVariants(String), } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct WebAuthToken { - pub update_version: u32, - pub account_id: u64, - pub timestamp: u64, - pub account_status: AccountStatus, - pub totp_status: TotpStatus, - pub admin_id: Option, - pub read_only: bool, +pub struct AgentTunnelPortAllocTypeDetails { + pub tunnel_type: Option, + pub port_type: PortType, + pub port_count: u16, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum AccountStatus { - #[serde(rename = "guest")] - Guest, - #[serde(rename = "email-not-verified")] - EmailNotVerified, - #[serde(rename = "verified")] - Verified, +impl std::fmt::Display for TunnelConfigError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } } +impl std::error::Error for TunnelConfigError { +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -#[serde(tag = "status")] -pub enum TotpStatus { - #[serde(rename = "required")] - Required, - #[serde(rename = "not-setup")] - NotSetup, - #[serde(rename = "signed")] - Signed(SignedEpoch), +pub struct ReqTunnelsPropset { + pub tunnel_id: uuid::Uuid, + pub details: PropsetDetails, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct SignedEpoch { - pub epoch_sec: u32, +#[serde(tag = "type", content = "value")] +pub enum PropsetDetails { + #[serde(rename = "hostname_verify_level")] + HostnameVerifyLevel(HostnameVerifyLevel), } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum GuestLoginError { - AccountIsNotGuest, +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum TunnelProxyPropSetError { + RequiresPermium, + TunnelNotFound, + PropertyValueNotSupportedForTunnelType, +} + +impl std::fmt::Display for TunnelProxyPropSetError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } } +impl std::error::Error for TunnelProxyPropSetError { +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqAgentsRoutingGet { - pub agent_id: Option, +pub struct ReqAgentsRundataV1 { } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AgentRouting { - pub agent_id: uuid::Uuid, - pub targets4: Vec, - pub targets6: Vec, - pub disable_ip6: bool, +pub struct AgentRunDataV1 { + pub agent_id: uuid::Uuid, + pub tunnels: Vec, + pub pending: Vec, + pub notices: Vec, + pub permissions: AgentPermissions, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum AgentRoutingGetError { - MissingAgentId, - InvalidAgentId, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentTunnelV1 { + pub id: uuid::Uuid, + pub internal_id: u64, + pub name: String, + pub display_address: String, + pub port_type: PortType, + pub port_count: u16, + pub tunnel_type: Option, + pub tunnel_type_display: String, + pub agent_config: AgentTunnelConfig, + pub disabled_reason: Option>, } -impl std::fmt::Display for AgentRoutingGetError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentPendingTunnelV1 { + pub id: uuid::Uuid, + pub name: String, + pub tunnel_type: Option, + pub tunnel_type_display: String, + pub port_type: PortType, + pub port_count: u16, + pub status_msg: String, } -impl std::error::Error for AgentRoutingGetError {} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqAgentsRundata {} +pub struct AgentNotice { + pub priority: AgentNoticePriority, + pub message: std::borrow::Cow<'static,str>, + pub resolve_link: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum AgentNoticePriority { + Critical, + High, + Low, +} #[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, - pub account_features: AccountFeatures, +pub struct AgentPermissions { + pub is_self_managed: bool, + pub has_premium: bool, + pub account_status: AccountStatus, } -#[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, - #[serde(rename = "agent-over-limit")] - AgentOverLimit, - #[serde(rename = "agent-disabled")] - AgentDisabled, +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum AccountStatus { + #[serde(rename = "guest")] + Guest, + #[serde(rename = "email-not-verified")] + EmailNotVerified, + #[serde(rename = "verified")] + Verified, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AgentTunnel { - pub id: uuid::Uuid, - pub internal_id: u64, - 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, - pub proxy_protocol: Option, +pub struct ReqInfoPops { } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct PortRange { - pub from: u16, - pub to: u16, +pub struct PlayitPops { + pub pops: Vec, + pub regions: Vec, } -#[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 Pop { + pub pop: PlayitPop, + pub name: String, + pub region: PlayitNetwork, + pub online: bool, + pub ip4_premium: bool, } +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum PlayitPop { + Any, + #[serde(rename = "USLosAngeles")] + UsLosAngeles, + #[serde(rename = "USSeattle")] + UsSeattle, + #[serde(rename = "USDallas")] + UsDallas, + #[serde(rename = "USMiami")] + UsMiami, + #[serde(rename = "USChicago")] + UsChicago, + #[serde(rename = "USNewJersey")] + UsNewJersey, + CanadaToronto, + Mexico, + BrazilSaoPaulo, + Spain, + London, + Germany, + Poland, + Sweden, + IndiaDelhi, + IndiaMumbai, + IndiaBangalore, + Singapore, + Tokyo, + Sydney, + SantiagoChile, + Israel, + Romania, + #[serde(rename = "USNewYork")] + UsNewYork, + #[serde(rename = "USDenver")] + UsDenver, + Staging, +} + +pub type ReqLoginSignin = LoginCredentials; + #[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, - pub region_num: u16, +pub struct LoginCredentials { + pub email: String, + pub password: String, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct AccountFeatures { - pub regional_tunnels: bool, +pub struct WebSession { + pub session_key: String, + pub auth: WebAuthToken, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqPingSubmit { - pub results: Vec, +pub struct WebAuthToken { + pub update_version: u32, + pub account_id: u64, + pub timestamp: u64, + pub account_status: AccountStatus, + pub totp_status: TotpStatus, + pub admin_id: Option, + pub admin_review_id: Option, + pub read_only: bool, + pub show_admin: bool, } + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct PingExperimentResult { - pub id: u64, - pub target: PingTarget, - pub samples: Vec, +#[serde(tag = "status")] +pub enum TotpStatus { + #[serde(rename = "required")] + Required, + #[serde(rename = "not-setup")] + NotSetup, + #[serde(rename = "signed")] + Signed(SignedEpoch), } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct PingTarget { - pub ip: std::net::IpAddr, - pub port: u16, +pub struct SignedEpoch { + pub epoch_sec: u32, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum SigninFail { + IncorrectCredentials, + AccountBanned, } +impl std::fmt::Display for SigninFail { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for SigninFail { +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct PingSample { - pub tunnel_server_id: u64, - pub dc_id: u64, - pub server_ts: u64, - pub latency: u64, - pub count: u16, - pub num: u16, +pub struct ReqLoginClearcookie { } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqPingGet {} +pub struct ClearWebSession { +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct PingExperiments { - pub experiments: Vec, +pub struct ReqLoginCreateGuest { +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum LoginCreateGuestError { + Blocked, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct PingExperimentDetails { - pub id: u64, - pub test_interval: u64, - pub ping_interval: u64, - pub samples: u64, - pub targets: std::borrow::Cow<'static, [PingTarget]>, +pub struct ReqLoginGuest { +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum GuestLoginError { + AccountIsNotGuest, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqTunnelsList { - pub tunnel_id: Option, - pub agent_id: Option, +pub struct ReqLoginResetPassword { + pub email: String, + pub reset_code: String, + pub new_password: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum PasswordResetError { + ResetCodeExpired, + InvalidResetCode, + InvalidNewPassword, } +impl std::fmt::Display for PasswordResetError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for PasswordResetError { +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqAgentsList {} +pub struct ReqLoginResetSend { + pub email: String, +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqQueryRegion { - pub limit_region: Option, +pub struct ReqTunnelsCreate { + pub name: Option, + pub tunnel_type: Option, + pub port_type: PortType, + pub port_count: u16, + pub origin: TunnelOriginCreate, + pub enabled: bool, + pub alloc: Option, + pub firewall_id: Option, + pub proxy_protocol: Option, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum PlayitRegion { - GlobalAnycast, - NorthAmerica, - Europe, - Asia, - India, - SouthAmerica, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "type", content = "data")] +pub enum TunnelOriginCreate { + #[serde(rename = "default")] + Default(AssignedDefaultCreate), + #[serde(rename = "agent")] + Agent(AssignedAgentCreate), + #[serde(rename = "managed")] + Managed(AssignedManagedCreate), } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct QueryRegion { - pub region: PlayitRegion, - pub pop: PlayitPop, +pub struct AssignedDefaultCreate { + pub local_ip: std::net::IpAddr, + pub local_port: Option, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum PlayitPop { - Any, - #[serde(rename = "USLosAngeles")] - UsLosAngeles, - #[serde(rename = "USSeattle")] - UsSeattle, - #[serde(rename = "USDallas")] - UsDallas, - #[serde(rename = "USMiami")] - UsMiami, - #[serde(rename = "USChicago")] - UsChicago, - #[serde(rename = "USNewJersey")] - UsNewJersey, - CanadaToronto, - Mexico, - BrazilSaoPaulo, - Spain, - London, - Germany, - Poland, - Sweden, - IndiaDelhi, - IndiaMumbai, - IndiaBangalore, - Singapore, - Tokyo, - Sydney, - SantiagoChile, - Israel, - Romania, - #[serde(rename = "USNewYork")] - UsNewYork, - #[serde(rename = "USDenver")] - UsDenver, -} - -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum QueryRegionError { - FailedToDetermineLocation, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AssignedAgentCreate { + pub agent_id: uuid::Uuid, + pub local_ip: std::net::IpAddr, + pub local_port: 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, +pub struct AssignedManagedCreate { + pub agent_id: Option, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum UpdateError { - ChangingAgentIdNotAllowed, - TunnelNotFound, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "type", content = "details")] +pub enum TunnelCreateUseAllocation { + #[serde(rename = "dedicated-ip")] + DedicatedIp(UseAllocDedicatedIp), + #[serde(rename = "port-allocation")] + PortAllocation(UseAllocPortAlloc), + #[serde(rename = "region")] + Region(UseRegion), } -impl std::fmt::Display for UpdateError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct UseAllocPortAlloc { + pub alloc_id: uuid::Uuid, } -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, +pub struct UseRegion { + pub region: PlayitNetwork, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum TunnelsFirewallAssignError { - TunnelNotFound, - InvalidFirewallId, +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum ProxyProtocol { + #[serde(rename = "proxy-protocol-v1")] + ProxyProtocolV1, + #[serde(rename = "proxy-protocol-v2")] + ProxyProtocolV2, } -impl std::fmt::Display for TunnelsFirewallAssignError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum TunnelCreateError { + DefaultAgentNotSupported, + AgentNotFound, + InvalidAgentId, + AgentVersionTooOld, + DedicatedIpNotFound, + DedicatedIpPortNotAvailable, + DedicatedIpNotEnoughSpace, + PortAllocNotFound, + InvalidIpHostname, + ManagedMissingAgentId, + InvalidPortCount, + RequiresVerifiedAccount, + InvalidTunnelName, + FirewallNotFound, + AllocInvalid, + InvalidOrigin, + RequiresPlayitPremium, + Other, } -impl std::error::Error for TunnelsFirewallAssignError {} +impl std::fmt::Display for TunnelCreateError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for TunnelCreateError { +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ReqTunnelsProxySet { - pub tunnel_id: uuid::Uuid, - pub proxy_protocol: Option, +pub struct ReqTunnelsList { + pub tunnel_id: Option, + pub agent_id: Option, } -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum TunnelProxySetError { - TunnelNotFound, +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AccountTunnels { + pub tunnels: Vec, + pub tcp_alloc: AllocatedPorts, + pub udp_alloc: AllocatedPorts, } + +#[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: Option, + pub domain: Option, + pub firewall_id: Option, + pub ratelimit: Ratelimit, + pub active: bool, + pub disabled_reason: Option, + pub region: Option, + pub expire_notice: Option, + pub proxy_protocol: Option, + pub hostname_verify_level: HostnameVerifyLevel, + pub agent_over_limit: bool, +} + +#[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: TunnelOfflineReason, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum TunnelOfflineReason { + #[serde(rename = "requires-premium")] + RequiresPremium, + #[serde(rename = "over-port-limit")] + OverPortLimit, + #[serde(rename = "ip-used-in-gre")] + IpUsedInGre, + #[serde(rename = "public-port-not-available")] + PublicPortNotAvailable, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct TunnelAllocated { + pub id: uuid::Uuid, + pub ip_hostname: String, + pub static_ip4: Option, + pub static_ip6: std::net::Ipv6Addr, + 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: PlayitNetwork, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "type", content = "subscription")] +pub enum TunnelAssignment { + #[serde(rename = "dedicated-ip")] + DedicatedIp(TunnelDedicatedIp), + #[serde(rename = "shared-ip")] + SharedIp, + #[serde(rename = "dedicated-port")] + DedicatedPort(SubscriptionId), +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct TunnelDedicatedIp { + pub sub_id: uuid::Uuid, + pub region: PlayitNetwork, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct SubscriptionId { + pub sub_id: uuid::Uuid, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, 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 = "agent")] + Agent(AssignedAgent), + #[serde(rename = "managed")] + Managed(AssignedManaged), +} + +#[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, +} + +#[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 AllocatedPorts { + pub allowed: u32, + pub claimed: u32, + pub desired: u32, +} + +#[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, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum UpdateError { + ChangingAgentIdNotAllowed, + TunnelNotFound, + CannotUpdateLocalAddressForUnassignedTunnel, + InvalidAgentId, + AddressOrProxyProtoNotSupportedByAgent, +} + +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 ReqTunnelsDelete { + pub tunnel_id: uuid::Uuid, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum DeleteError { + TunnelNotFound, +} + +#[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, PartialOrd, Ord, 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 ReqTunnelsFirewallAssign { + pub tunnel_id: uuid::Uuid, + pub firewall_id: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, 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 ReqTunnelsRatelimit { + pub tunnel_id: uuid::Uuid, + pub bytes_per_second: Option, + pub packets_per_second: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum TunnelRatelimitError { + TunnelNotFound, + InvalidRatelimit, + PlayitPremiumRequired, +} + +impl std::fmt::Display for TunnelRatelimitError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for TunnelRatelimitError { +} +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqTunnelsEnable { + pub tunnel_id: uuid::Uuid, + pub enabled: bool, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum TunnelEnableError { + TunnelNotFound, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqTunnelsProxySet { + pub tunnel_id: uuid::Uuid, + pub proxy_protocol: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum TunnelProxySetError { + TunnelNotFound, + ProxyProtocolNotSupportedByAgent, +} + +impl std::fmt::Display for TunnelProxySetError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for TunnelProxySetError { +} +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqClaimSetup { + pub code: String, + pub agent_type: ClaimAgentType, + pub version: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum ClaimAgentType { + #[serde(rename = "assignable")] + Assignable, + #[serde(rename = "self-managed")] + SelfManaged, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum ClaimSetupResponse { + WaitingForUserVisit, + WaitingForUser, + UserAccepted, + UserRejected, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum ClaimSetupError { + InvalidCode, + CodeExpired, + VersionTextTooLong, +} + +impl std::fmt::Display for ClaimSetupError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for ClaimSetupError { +} +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqClaimExchange { + pub code: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentSecretKey { + pub secret_key: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum ClaimExchangeError { + CodeNotFound, + CodeExpired, + UserRejected, + NotAccepted, + NotSetup, +} + +impl std::fmt::Display for ClaimExchangeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for ClaimExchangeError { +} +#[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, PartialOrd, Ord, 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 ReqAgentsRoutingSet { + pub agent_id: uuid::Uuid, + pub routing: AgentRoutingTarget, + pub disable_ip6: bool, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "type", content = "details")] +pub enum AgentRoutingTarget { + #[serde(rename = "Automatic")] + Automatic, + #[serde(rename = "Pop")] + Pop(PlayitPop), + #[serde(rename = "Region")] + Region(PlayitNetwork), +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum AgentRoutingSetError { + RequiresPremium, + AgentNotFound, + InvalidAgentId, +} + +impl std::fmt::Display for AgentRoutingSetError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for AgentRoutingSetError { +} +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqAgentsRoutingGet { + pub agent_id: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentRouting { + pub agent_id: uuid::Uuid, + pub targets4: Vec, + pub targets6: Vec, + pub disable_ip6: bool, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum AgentRoutingGetError { + MissingAgentId, + InvalidAgentId, +} + +impl std::fmt::Display for AgentRoutingGetError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +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, + pub account_features: AccountFeatures, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum AgentType { + #[serde(rename = "default")] + Default, + #[serde(rename = "assignable")] + Assignable, + #[serde(rename = "self-managed")] + SelfManaged, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, 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, + #[serde(rename = "agent-over-limit")] + AgentOverLimit, + #[serde(rename = "agent-disabled")] + AgentDisabled, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentTunnel { + pub id: uuid::Uuid, + pub internal_id: u64, + 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, + pub proxy_protocol: Option, + pub agent_config: AgentTunnelConfig, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct PortRange { + pub from: u16, + pub to: u16, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, 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, + pub region_num: u16, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AccountFeatures { + pub regional_tunnels: bool, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqDomainsList { +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct Domains { + pub domains: Vec, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct Domain { + pub id: uuid::Uuid, + pub name: String, + pub is_external: bool, + pub parent: Option, + pub sub_id: uuid::Uuid, + pub target: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "type", content = "details")] +pub enum DomainTarget { + #[serde(rename = "ip-address")] + IpAddress(DomainTargetIp), + #[serde(rename = "tunnel")] + Tunnel(DomainTargetTunnel), + #[serde(rename = "external-cname")] + ExternalCname(DomainTargetExternalCName), +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct DomainTargetIp { + pub ip_address: std::net::IpAddr, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct DomainTargetTunnel { + pub tunnel_id: uuid::Uuid, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct DomainTargetExternalCName { + pub cname: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqShopPrices { +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ShopPrices { + pub custom_domain: ShopPrice, + pub dedicated_ip: std::collections::HashMap, + pub playit_premium: ShopPrice, + pub ports_both: ShopPrice, + pub ports_tcp: ShopPrice, + pub ports_udp: ShopPrice, + pub dedicated_port_global: ShopPrice, + pub dedicated_port_regional: ShopPrice, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ShopPrice { + pub monthly: Option, + pub yearly: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqShopAvailabilityCustomDomain { + pub name: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct IsAvailable { + pub is_available: bool, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqProtoRegister { + pub agent_version: Option, + pub proto_version: u64, + pub version: AgentVersion, + pub platform: Platform, + pub client_addr: std::net::SocketAddr, + pub tunnel_addr: std::net::SocketAddr, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct PlayitAgentVersion { + pub version: AgentVersionOld, + pub proto_version: u64, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentVersionOld { + pub platform: Platform, + pub version: String, + pub has_expired: bool, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, 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 = "docker")] + Docker, + #[serde(rename = "minecraft-plugin")] + MinecraftPlugin, + #[serde(rename = "unknown")] + Unknown, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct AgentVersion { + pub variant_id: uuid::Uuid, + pub version_major: u32, + pub version_minor: u32, + pub version_patch: u32, +} + + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct SignedAgentKey { + pub key: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum ProtoRegisterError { + UnknownPlayitVersion, + DisabledByUser, + AgentDisabledOverLimit, + AccountBanned, +} + +impl std::fmt::Display for ProtoRegisterError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for ProtoRegisterError { +} +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqChargeGet { + pub reference_code: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ChargeDetails { + pub reference_code: String, + pub created_at: chrono::DateTime, + pub invoice_type: InvoiceType, + pub invoice_status: InvoiceStatus, + pub total_cost: String, + pub items: Vec, + pub refund: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum InvoiceType { + Subscription, + StartSubscription, + StripeSubscription, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum InvoiceStatus { + #[serde(rename = "draft")] + Draft, + #[serde(rename = "open")] + Open, + #[serde(rename = "paid")] + Paid, + #[serde(rename = "void")] + Void, + #[serde(rename = "uncollectible")] + Uncollectible, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ChargeDetailsItem { + pub product: SubProductType, + pub months: u32, + pub total_cost: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum SubProductType { + #[serde(rename = "playit-premium")] + PlayitPremium, + #[serde(rename = "playit-premium-trial")] + PlayitPremiumTrial, + #[serde(rename = "dedicated-ip")] + DedicatedIp, + #[serde(rename = "udp-ports")] + UdpPorts, + #[serde(rename = "tcp-ports")] + TcpPorts, + #[serde(rename = "both-ports")] + BothPorts, + #[serde(rename = "custom-domain")] + CustomDomain, + #[serde(rename = "dedicated-port-alloc")] + DedicatedPortAlloc, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(tag = "type", content = "details")] +pub enum RefundStatus { + #[serde(rename = "Pending")] + Pending(PendingRefundRequest), + #[serde(rename = "Applied")] + Applied(RefundApplied), + #[serde(rename = "DisputeCreated")] + DisputeCreated(DisputeCreated), +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct PendingRefundRequest { + pub created_at: chrono::DateTime, + pub reason: RefundRequestReason, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum RefundRequestReason { + #[serde(rename = "fraud")] + Fraud, + #[serde(rename = "not-satisfied")] + NotSatisfied, + #[serde(rename = "issuer-fraud-warning")] + IssuerFraudWarning, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct RefundApplied { + pub created_at: chrono::DateTime, + pub refund_amount: String, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct DisputeCreated { + pub created_at: chrono::DateTime, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum ChargeGetError { + ChargeNotFound, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqChargeRefund { + pub reference_code: String, + pub reason: RefundRequestReason, + pub email: Option, + pub refund_message: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum ChargeRefundError { + ChargeNotFound, + MessageTooLarge, + UnauthorizedReason, +} + +impl std::fmt::Display for ChargeRefundError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl std::error::Error for ChargeRefundError { +} +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct ReqQueryRegion { + pub limit_region: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct QueryRegion { + pub region: PlayitNetwork, + pub pop: PlayitPop, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +pub enum QueryRegionError { + FailedToDetermineLocation, +} + diff --git a/packages/ping_monitor/Cargo.toml b/packages/ping_monitor/Cargo.toml deleted file mode 100644 index 80fa225..0000000 --- a/packages/ping_monitor/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "playit-ping-monitor" -version = "0.1.0" -edition = "2021" -description = "Runs ping experiments to the playit network to help us tune routing" -license = "BSD-2-Clause" -repository = "https://github.com/playit-cloud/playit-agent" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -tokio = { workspace = true } - -tracing = { workspace = true } -tracing-subscriber = { workspace = true } -tracing-appender = { workspace = true } - -message-encoding = { workspace = true } -rand = { workspace = true } - -serde = { workspace = true} -toml = { workspace = true } -hex = { workspace = true } -dirs = { workspace = true } - -playit-agent-proto = { path = "../agent_proto", version = "1.0.0" } -playit-api-client = { path = "../api_client", version = "0.1.0" } \ No newline at end of file