From 74f5337a91385c6843bb209c6869eb54574cb0ad Mon Sep 17 00:00:00 2001 From: "Jason T. Wong" Date: Thu, 16 May 2024 09:17:25 -0400 Subject: [PATCH] add tunnels --- src/api/mod.rs | 6 ++ src/api/tunnels.rs | 109 +++++++++++++++++++++++++ tests/fixtures/tunnels-create-201.json | 16 ++++ tests/fixtures/tunnels-update-200.json | 16 ++++ tests/tunnels.rs | 73 +++++++++++++++++ 5 files changed, 220 insertions(+) create mode 100644 src/api/tunnels.rs create mode 100644 tests/fixtures/tunnels-create-201.json create mode 100644 tests/fixtures/tunnels-update-200.json create mode 100644 tests/tunnels.rs diff --git a/src/api/mod.rs b/src/api/mod.rs index 97e8db8..a727e81 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -20,6 +20,7 @@ pub mod products; pub mod products_v2; pub mod releases; pub mod signing_keys; +pub mod tunnels; pub mod webhooks; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; @@ -51,6 +52,7 @@ pub use products_v2::ProductsV2Api; pub use releases::ReleasesApi; pub use reqwest::Body; pub use signing_keys::SigningKeysApi; +pub use tunnels::TunnelsApi; pub use users::UsersApi; pub use webhooks::WebhooksApi; @@ -423,6 +425,10 @@ impl Api { SigningKeysApi(self) } + pub fn tunnels(&self) -> TunnelsApi { + TunnelsApi(self) + } + pub fn users(&self) -> UsersApi { UsersApi(self) } diff --git a/src/api/tunnels.rs b/src/api/tunnels.rs new file mode 100644 index 0000000..c2114ca --- /dev/null +++ b/src/api/tunnels.rs @@ -0,0 +1,109 @@ +use reqwest::Method; +use serde::{Deserialize, Serialize}; + +use crate::{json_body, Api}; + +use super::Error; +use snafu::ResultExt; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Tunnel { + pub device_proxy_ip_address: String, + pub device_proxy_port: u16, + pub device_public_key: String, + pub device_tunnel_port: u16, + pub server_proxy_ip_address: String, + pub server_proxy_port: u16, + pub server_public_key: String, + pub server_tunnel_port: u16, + pub expires_at: String, + pub prn: String, + pub state: String, +} + +#[derive(Debug, Serialize)] +pub struct CreateTunnelParams { + pub device_prn: String, + pub ttl: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct CreateTunnelResponse { + pub tunnel: Tunnel, +} + +#[derive(Debug, Serialize)] +pub struct ListTunnelsParams { + pub limit: Option, + pub order: Option, + pub search: String, + pub page: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct ListTunnelsResponse { + pub tunnels: Vec, + pub next_page: Option, +} + +#[derive(Debug, Serialize)] +pub struct UpdateTunnelParams { + pub prn: String, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub state: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct UpdateTunnelResponse { + pub tunnel: Tunnel, +} + +pub struct TunnelsApi<'a>(pub &'a Api); + +impl<'a> TunnelsApi<'a> { + pub async fn create( + &'a self, + params: CreateTunnelParams, + ) -> Result, Error> { + self.0 + .execute(Method::POST, "/tunnels", Some(json_body!(¶ms))) + .await + } + + pub async fn list( + &'a self, + params: ListTunnelsParams, + ) -> Result, Error> { + let mut query_params = vec![("search".to_string(), params.search)]; + + if let Some(limit) = params.limit { + query_params.push(("limit".to_string(), limit.to_string())) + } + if let Some(order) = params.order { + query_params.push(("order".to_string(), order)) + } + + if let Some(page) = params.page { + query_params.push(("page".to_string(), page)) + } + self.0 + .execute_with_params(Method::GET, "/tunnels".to_string(), None, query_params) + .await + } + + pub async fn update( + &'a self, + params: UpdateTunnelParams, + ) -> Result, Error> { + let tunnel_prn: &String = ¶ms.prn; + + self.0 + .execute( + Method::PATCH, + format!("/tunnels/{tunnel_prn}"), + Some(json_body!(¶ms)), + ) + .await + } +} diff --git a/tests/fixtures/tunnels-create-201.json b/tests/fixtures/tunnels-create-201.json new file mode 100644 index 0000000..997e891 --- /dev/null +++ b/tests/fixtures/tunnels-create-201.json @@ -0,0 +1,16 @@ +{ + "tunnel": { + "device_proxy_ip_address": "10.0.1.1", + "device_proxy_port": 47539, + "device_public_key": "device_public_key", + "device_tunnel_port": 22, + "server_proxy_ip_address": "10.0.0.1", + "server_proxy_port": 49293, + "server_public_key": "server_public_Key", + "server_tunnel_ip_address": "3.82.23.99", + "server_tunnel_port": 47532, + "expires_at": "2001-01-01T00:00:00Z", + "prn": "prn", + "state": "requested" + } +} diff --git a/tests/fixtures/tunnels-update-200.json b/tests/fixtures/tunnels-update-200.json new file mode 100644 index 0000000..ab308b6 --- /dev/null +++ b/tests/fixtures/tunnels-update-200.json @@ -0,0 +1,16 @@ +{ + "tunnel": { + "device_proxy_ip_address": "10.0.1.1", + "device_proxy_port": 47539, + "device_public_key": "device_public_key", + "device_tunnel_port": 22, + "server_proxy_ip_address": "10.0.0.1", + "server_proxy_port": 49293, + "server_public_key": "server_public_Key", + "server_tunnel_ip_address": "3.82.23.99", + "server_tunnel_port": 47532, + "expires_at": "2001-01-01T00:00:00Z", + "prn": "prn", + "state": "closed" + } +} diff --git a/tests/tunnels.rs b/tests/tunnels.rs new file mode 100644 index 0000000..452ad31 --- /dev/null +++ b/tests/tunnels.rs @@ -0,0 +1,73 @@ +mod common; + +use common::API_KEY; +use mockito::{mock, server_url as mock_server_url}; + +use peridio_sdk::api::tunnels::{CreateTunnelParams, UpdateTunnelParams}; + +use peridio_sdk::api::Api; +use peridio_sdk::api::ApiOptions; + +#[tokio::test] +async fn create_tunnel() { + let device_prn = "device_prn"; + let ttl = 3600; + + let api = Api::new(ApiOptions { + api_key: API_KEY.into(), + endpoint: Some(mock_server_url()), + ca_bundle_path: None, + }); + + let m = mock("POST", &*format!("/tunnels")) + .with_status(201) + .with_header("content-type", "application/json") + .with_body_from_file("tests/fixtures/tunnels-create-201.json") + .create(); + + let params = CreateTunnelParams { + device_prn: device_prn.to_string(), + ttl: Some(ttl), + }; + + match api.tunnels().create(params).await.unwrap() { + Some(tunnel) => { + assert_eq!(tunnel.tunnel.expires_at, "2000-01-01T00:00:00Z"); + } + _ => panic!(), + } + + m.assert(); +} + +#[tokio::test] +async fn update_tunnel() { + let expected_state = "closed"; + let expected_prn = "1"; + + let api = Api::new(ApiOptions { + api_key: API_KEY.into(), + endpoint: Some(mock_server_url()), + ca_bundle_path: None, + }); + + let m = mock("PATCH", &*format!("/tunnels/{expected_prn}")) + .with_status(200) + .with_header("content-type", "application/json") + .with_body_from_file("tests/fixtures/tunnels-update-200.json") + .create(); + + let params = UpdateTunnelParams { + prn: expected_prn.to_string(), + state: Some(expected_state.to_string()), + }; + + match api.tunnels().update(params).await.unwrap() { + Some(tunnel) => { + assert_eq!(tunnel.tunnel.state, expected_state.to_string()); + } + _ => panic!(), + } + + m.assert(); +}