Skip to content
1 change: 1 addition & 0 deletions cloudflare/src/endpoints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod cfd_tunnel;
pub mod dns;
pub mod load_balancing;
pub mod r2;
pub mod warp_connector_tunnel;
pub mod workers;
pub mod workerskv;
pub mod zones;
43 changes: 43 additions & 0 deletions cloudflare/src/endpoints/warp_connector_tunnel/create_tunnel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use serde::Serialize;
use serde_with::serde_as;

use crate::framework::response::ApiSuccess;
use crate::{
endpoints::warp_connector_tunnel::data_structures::WarpConnectorTunnel,
framework::endpoint::{EndpointSpec, Method, RequestBody},
};

/// Create a Warp Connector tunnel
/// <https://developers.cloudflare.com/api/resources/zero_trust/subresources/tunnels/subresources/warp_connector/methods/create>
#[derive(Debug)]
pub struct CreateTunnel<'a> {
pub account_identifier: &'a str,
pub params: Params<'a>,
}

impl EndpointSpec for CreateTunnel<'_> {
type JsonResponse = WarpConnectorTunnel;
type ResponseType = ApiSuccess<Self::JsonResponse>;

fn method(&self) -> Method {
Method::POST
}
fn path(&self) -> String {
format!("accounts/{}/warp_connector", self.account_identifier)
}
#[inline]
fn body(&'_ self) -> Option<RequestBody<'_>> {
let body = serde_json::to_string(&self.params).unwrap();
Some(RequestBody::Json(body))
}
}

/// Params for creating a Warp Connector Tunnel
#[serde_as]
#[serde_with::skip_serializing_none]
#[derive(Serialize, Clone, Debug)]
pub struct Params<'a> {
/// The name for the Tunnel to be created. It must be unique within the account.
pub name: &'a str,
pub ha: bool,
}
153 changes: 153 additions & 0 deletions cloudflare/src/endpoints/warp_connector_tunnel/data_structures.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use chrono::{offset::Utc, DateTime};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::endpoints::cfd_tunnel::{ActiveConnection, TunnelStatusType};
use crate::framework::response::ApiResult;

/// A Warp Connector Tunnel.
///
/// Mirrors the JSON returned by the Cloudflare API when creating or fetching a
/// warp_connector tunnel, including its credentials file and connection token.
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct WarpConnectorTunnel {
pub id: Uuid,
pub account_tag: String,
pub created_at: DateTime<Utc>,
pub deleted_at: Option<DateTime<Utc>>,
pub name: String,
pub connections: Vec<ActiveConnection>,
pub conns_active_at: Option<DateTime<Utc>>,
pub conns_inactive_at: Option<DateTime<Utc>>,
pub tun_type: String,
pub metadata: serde_json::Value,
pub status: TunnelStatusType,
/// Present on create responses; absent on delete responses.
#[serde(flatten)]
pub credentials: Option<WarpConnectorCredentials>,
}

/// Credentials bundle returned only when a Warp Connector Tunnel is created.
///
/// Flattened into [`WarpConnectorTunnel`] so it inlines `credentials_file` and
/// `token` at the top level of the JSON.
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct WarpConnectorCredentials {
pub credentials_file: WarpConnectorCredentialsFile,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this really comes in the reply 🤔

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes it comes

pub token: String,
}

/// Credentials file contents for a Warp Connector Tunnel.
///
/// Field names follow the API's PascalCase convention.
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct WarpConnectorCredentialsFile {
#[serde(rename = "AccountTag")]
pub account_tag: String,
#[serde(rename = "TunnelID")]
pub tunnel_id: Uuid,
#[serde(rename = "TunnelName")]
pub tunnel_name: String,
#[serde(rename = "TunnelSecret")]
pub tunnel_secret: String,
}

impl ApiResult for WarpConnectorTunnel {}
impl ApiResult for Vec<WarpConnectorTunnel> {}

/// A Warp Connector client maintaining a connection to a Cloudflare data center.
///
/// Returned by both the connections list and the single-connector get endpoints.
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct WarpConnector {
pub id: Option<Uuid>,
pub arch: Option<String>,
pub conns: Option<Vec<WarpConnectorConn>>,
pub features: Option<Vec<String>>,
pub ha_status: Option<WarpConnectorHaStatus>,
pub run_at: Option<DateTime<Utc>>,
pub version: Option<String>,
}

/// A single Warp Connector connection between a client and Cloudflare's edge.
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct WarpConnectorConn {
pub id: Option<Uuid>,
pub client_id: Option<Uuid>,
pub client_version: Option<String>,
pub colo_name: Option<String>,
pub opened_at: Option<DateTime<Utc>>,
pub origin_ip: Option<String>,
}

/// HA status reported by a Warp Connector client.
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[serde(rename_all = "lowercase")]
pub enum WarpConnectorHaStatus {
Offline,
Passive,
Active,
}

impl ApiResult for WarpConnector {}
impl ApiResult for Vec<WarpConnector> {}

/// HA configuration for a Warp Connector Tunnel.
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct WarpConnectorHaConfiguration {
/// Monotonically increasing configuration version, incremented on each PUT.
pub configuration_version: u64,
pub created_at: DateTime<Utc>,
pub ha_mode: WarpConnectorHaMode,
pub tunnel_id: Uuid,
/// Provider-specific configuration; present for `aws` and `local` modes.
#[serde(default)]
pub config: Option<WarpConnectorProviderConfiguration>,
pub updated_at: Option<DateTime<Utc>>,
}

/// HA mode for a Warp Connector tunnel.
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[serde(rename_all = "lowercase")]
pub enum WarpConnectorHaMode {
/// HA enabled but no provider configured yet.
None,
/// HA explicitly turned off.
Disabled,
/// AWS ENI move-based failover.
Aws,
/// Local VIP-based failover.
Local,
}

/// Provider-specific HA configuration payload, discriminated by shape.
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(untagged)]
pub enum WarpConnectorProviderConfiguration {
Aws(WarpConnectorAwsProviderConfiguration),
Local(WarpConnectorHaLocalProviderConfiguration),
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct WarpConnectorAwsProviderConfiguration {
/// Floating Network Resource ID — the secondary ENI moved between nodes
/// on failover.
pub fnr_id: String,
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct WarpConnectorHaLocalProviderConfiguration {
/// VIPs to assign on the CloudflareWARP interface.
pub vips: Vec<WarpConnectorVip>,
/// VIPs to clean up on demotion or version drift.
#[serde(skip_serializing_if = "Option::is_none")]
pub vips_previous: Option<Vec<WarpConnectorVip>>,
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct WarpConnectorVip {
/// Virtual IP address (IPv4 or IPv6).
pub address: String,
}

impl ApiResult for WarpConnectorHaConfiguration {}
39 changes: 39 additions & 0 deletions cloudflare/src/endpoints/warp_connector_tunnel/delete_tunnel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::endpoints::warp_connector_tunnel::data_structures::WarpConnectorTunnel;
use crate::framework::endpoint::{serialize_query, EndpointSpec, Method};
use crate::framework::response::ApiSuccess;
use serde::Serialize;

/// Delete a WARP Connector tunnel
/// <https://developers.cloudflare.com/api/resources/zero_trust/subresources/tunnels/subresources/warp_connector/methods/delete>
#[derive(Debug)]
pub struct DeleteTunnel<'a> {
pub account_identifier: &'a str,
pub tunnel_id: &'a str,
pub params: Params,
}

impl EndpointSpec for DeleteTunnel<'_> {
type JsonResponse = WarpConnectorTunnel;
type ResponseType = ApiSuccess<Self::JsonResponse>;

fn method(&self) -> Method {
Method::DELETE
}
fn path(&self) -> String {
format!(
"accounts/{}/warp_connector/{}",
self.account_identifier, self.tunnel_id
)
}
#[inline]
fn query(&self) -> Option<String> {
serialize_query(&self.params)
}
}

#[serde_with::skip_serializing_none]
#[derive(Serialize, Clone, Debug, Default)]
pub struct Params {
// should delete tunnel connections if any exists
pub cascade: bool,
}
28 changes: 28 additions & 0 deletions cloudflare/src/endpoints/warp_connector_tunnel/get_connector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::endpoints::warp_connector_tunnel::data_structures::WarpConnector;
use crate::framework::endpoint::{EndpointSpec, Method};
use crate::framework::response::ApiSuccess;

/// Fetch connector + connection details for a single Warp Connector client.
/// <https://developers.cloudflare.com/api/resources/zero_trust/subresources/tunnels/subresources/warp_connector/subresources/connectors/methods/get>
#[derive(Debug)]
pub struct GetConnector<'a> {
pub account_identifier: &'a str,
pub tunnel_id: &'a str,
pub connector_id: &'a str,
}

impl EndpointSpec for GetConnector<'_> {
type JsonResponse = WarpConnector;
type ResponseType = ApiSuccess<Self::JsonResponse>;

fn method(&self) -> Method {
Method::GET
}

fn path(&self) -> String {
format!(
"accounts/{}/warp_connector/{}/connectors/{}",
self.account_identifier, self.tunnel_id, self.connector_id
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::endpoints::warp_connector_tunnel::data_structures::WarpConnectorHaConfiguration;
use crate::framework::endpoint::{EndpointSpec, Method};
use crate::framework::response::ApiSuccess;

/// Get the HA configuration for a Warp Connector Tunnel.
/// <https://developers.cloudflare.com/api/resources/zero_trust/subresources/tunnels/subresources/warp_connector/subresources/configurations/methods/get>
#[derive(Debug)]
pub struct GetHaConfiguration<'a> {
pub account_identifier: &'a str,
pub tunnel_id: &'a str,
}

impl EndpointSpec for GetHaConfiguration<'_> {
type JsonResponse = WarpConnectorHaConfiguration;
type ResponseType = ApiSuccess<Self::JsonResponse>;

fn method(&self) -> Method {
Method::GET
}

fn path(&self) -> String {
format!(
"accounts/{}/warp_connector/{}/configurations",
self.account_identifier, self.tunnel_id
)
}
}
37 changes: 37 additions & 0 deletions cloudflare/src/endpoints/warp_connector_tunnel/get_token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use serde::{Deserialize, Serialize};

use crate::framework::endpoint::{EndpointSpec, Method};
use crate::framework::response::{ApiResult, ApiSuccess};

/// Fetch the token used to authenticate a Warp Connector Tunnel.
/// <https://developers.cloudflare.com/api/resources/zero_trust/subresources/tunnels/subresources/warp_connector/methods/token_get>
#[derive(Debug)]
pub struct GetToken<'a> {
pub account_identifier: &'a str,
pub tunnel_id: &'a str,
}

impl EndpointSpec for GetToken<'_> {
type JsonResponse = WarpConnectorToken;
type ResponseType = ApiSuccess<Self::JsonResponse>;

fn method(&self) -> Method {
Method::GET
}

fn path(&self) -> String {
format!(
"accounts/{}/warp_connector/{}/token",
self.account_identifier, self.tunnel_id
)
}
}

/// Tunnel token returned by the API. The raw JSON value is a plain string
/// (e.g. `"eyJhIjoi…"`) but it is wrapped here so the crate's `ApiResult`
/// trait can be implemented without violating Rust's orphan rules.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct WarpConnectorToken(pub String);

impl ApiResult for WarpConnectorToken {}
27 changes: 27 additions & 0 deletions cloudflare/src/endpoints/warp_connector_tunnel/get_tunnel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::endpoints::warp_connector_tunnel::data_structures::WarpConnectorTunnel;
use crate::framework::endpoint::{EndpointSpec, Method};
use crate::framework::response::ApiSuccess;

/// Fetch a single Warp Connector Tunnel.
/// <https://developers.cloudflare.com/api/resources/zero_trust/subresources/tunnels/subresources/warp_connector/methods/get>
#[derive(Debug)]
pub struct GetTunnel<'a> {
pub account_identifier: &'a str,
pub tunnel_id: &'a str,
}

impl EndpointSpec for GetTunnel<'_> {
type JsonResponse = WarpConnectorTunnel;
type ResponseType = ApiSuccess<Self::JsonResponse>;

fn method(&self) -> Method {
Method::GET
}

fn path(&self) -> String {
format!(
"accounts/{}/warp_connector/{}",
self.account_identifier, self.tunnel_id
)
}
}
27 changes: 27 additions & 0 deletions cloudflare/src/endpoints/warp_connector_tunnel/list_connections.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::endpoints::warp_connector_tunnel::data_structures::WarpConnector;
use crate::framework::endpoint::{EndpointSpec, Method};
use crate::framework::response::ApiSuccess;

/// List active connections for a Warp Connector Tunnel.
/// <https://developers.cloudflare.com/api/resources/zero_trust/subresources/tunnels/subresources/warp_connector/subresources/connections/methods/list>
#[derive(Debug)]
pub struct ListConnections<'a> {
pub account_identifier: &'a str,
pub tunnel_id: &'a str,
}

impl EndpointSpec for ListConnections<'_> {
type JsonResponse = Vec<WarpConnector>;
type ResponseType = ApiSuccess<Self::JsonResponse>;

fn method(&self) -> Method {
Method::GET
}

fn path(&self) -> String {
format!(
"accounts/{}/warp_connector/{}/connections",
self.account_identifier, self.tunnel_id
)
}
}
Loading