use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::client::{HeyoClient, HeyoClientOptions, RequestOptions};
use crate::commands::encode_path;
use crate::errors::HeyoError;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct NetworkInfo {
pub id: String,
pub account_id: String,
pub name: String,
pub is_default: bool,
#[serde(default)]
pub description: Option<String>,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct NetworkMember {
pub network_id: String,
pub sandbox_kind: String,
pub sandbox_ref: String,
#[serde(default)]
pub device_name: Option<String>,
pub registered_at: String,
#[serde(default)]
pub last_seen_at: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct NetworkCreateOptions {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct NetworkUpdateOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<Option<String>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum NetworkMemberKind {
Local,
Deployed,
}
impl NetworkMemberKind {
pub fn as_str(&self) -> &'static str {
match self {
NetworkMemberKind::Local => "local",
NetworkMemberKind::Deployed => "deployed",
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct NetworkMemberRegistration {
pub sandbox_kind: NetworkMemberKind,
pub sandbox_ref: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_name: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct NetworkService {
pub id: String,
pub network_id: String,
pub name: String,
pub address: String,
pub sandbox_kind: String,
pub sandbox_ref: String,
pub port: u16,
pub protocol: String,
pub status: String,
#[serde(default)]
pub connection_url: Option<String>,
#[serde(default)]
pub last_seen_at: Option<String>,
#[serde(default)]
pub transport: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ServiceRoute {
pub address: String,
pub transport: String,
pub connection_url: String,
}
#[derive(Deserialize)]
struct NetworksEnvelope {
#[serde(default)]
networks: Vec<NetworkInfo>,
}
#[derive(Deserialize)]
struct MembersEnvelope {
#[serde(default)]
members: Vec<NetworkMember>,
}
#[derive(Clone)]
pub struct Network {
info: NetworkInfo,
client: HeyoClient,
}
impl Network {
fn from_raw(client: HeyoClient, info: NetworkInfo) -> Self {
Self { info, client }
}
pub fn id(&self) -> &str {
&self.info.id
}
pub fn name(&self) -> &str {
&self.info.name
}
pub fn is_default(&self) -> bool {
self.info.is_default
}
pub fn info(&self) -> &NetworkInfo {
&self.info
}
pub fn client(&self) -> &HeyoClient {
&self.client
}
pub async fn create(
options: NetworkCreateOptions,
client_options: HeyoClientOptions,
) -> Result<Self, HeyoError> {
let client = HeyoClient::new(client_options)?;
let raw: NetworkInfo = client
.request(
Method::POST,
"/networks",
Some(&options),
RequestOptions::default(),
)
.await?;
Ok(Network::from_raw(client, raw))
}
pub async fn list(client_options: HeyoClientOptions) -> Result<Vec<NetworkInfo>, HeyoError> {
let client = HeyoClient::new(client_options)?;
let env: NetworksEnvelope = client
.request(Method::GET, "/networks", None::<&()>, RequestOptions::default())
.await?;
Ok(env.networks)
}
pub async fn get(id: &str, client_options: HeyoClientOptions) -> Result<Self, HeyoError> {
let client = HeyoClient::new(client_options)?;
let path = format!("/networks/{}", encode_path(id));
let raw: NetworkInfo = client
.request(Method::GET, &path, None::<&()>, RequestOptions::default())
.await?;
Ok(Network::from_raw(client, raw))
}
pub async fn default_for_me(
client_options: HeyoClientOptions,
) -> Result<Self, HeyoError> {
let client = HeyoClient::new(client_options)?;
let raw: NetworkInfo = client
.request(Method::GET, "/networks/me", None::<&()>, RequestOptions::default())
.await?;
Ok(Network::from_raw(client, raw))
}
pub async fn delete_by_id(
id: &str,
client_options: HeyoClientOptions,
) -> Result<(), HeyoError> {
let client = HeyoClient::new(client_options)?;
let path = format!("/networks/{}", encode_path(id));
client
.request::<serde_json::Value>(
Method::DELETE,
&path,
None::<&()>,
RequestOptions::default(),
)
.await?;
Ok(())
}
pub async fn delete(self) -> Result<(), HeyoError> {
let path = format!("/networks/{}", encode_path(&self.info.id));
self.client
.request::<serde_json::Value>(
Method::DELETE,
&path,
None::<&()>,
RequestOptions::default(),
)
.await?;
Ok(())
}
pub async fn update(&mut self, options: NetworkUpdateOptions) -> Result<(), HeyoError> {
let path = format!("/networks/{}", encode_path(&self.info.id));
let raw: NetworkInfo = self
.client
.request(Method::PATCH, &path, Some(&options), RequestOptions::default())
.await?;
self.info = raw;
Ok(())
}
pub async fn list_services(
client_options: HeyoClientOptions,
) -> Result<Vec<NetworkService>, HeyoError> {
let client = HeyoClient::new(client_options)?;
client
.request(
Method::GET,
"/networks/me/services",
None::<&()>,
RequestOptions::default(),
)
.await
}
pub async fn dial_service(
name: &str,
port: u16,
client_options: HeyoClientOptions,
) -> Result<ServiceRoute, HeyoError> {
let client = HeyoClient::new(client_options)?;
let path = format!(
"/networks/me/services/{}/{}/dial",
encode_path(name),
port
);
client
.request(Method::GET, &path, None::<&()>, RequestOptions::default())
.await
}
pub async fn list_members(&self) -> Result<Vec<NetworkMember>, HeyoError> {
let path = format!("/networks/{}/members", encode_path(&self.info.id));
let env: MembersEnvelope = self
.client
.request(Method::GET, &path, None::<&()>, RequestOptions::default())
.await?;
Ok(env.members)
}
pub async fn add_member(
&self,
registration: NetworkMemberRegistration,
) -> Result<NetworkMember, HeyoError> {
let path = format!("/networks/{}/members", encode_path(&self.info.id));
self.client
.request(
Method::POST,
&path,
Some(®istration),
RequestOptions::default(),
)
.await
}
pub async fn remove_member(
&self,
sandbox_kind: NetworkMemberKind,
sandbox_ref: &str,
) -> Result<(), HeyoError> {
let path = format!(
"/networks/{}/members/{}/{}",
encode_path(&self.info.id),
sandbox_kind.as_str(),
encode_path(sandbox_ref)
);
self.client
.request::<serde_json::Value>(
Method::DELETE,
&path,
None::<&()>,
RequestOptions::default(),
)
.await?;
Ok(())
}
}