use crate::resources::_base::{put_opt, vars};
use crate::types::{Delivery, Destination, HealthConfig, ListResult, OAuth2Config, RetryPolicy};
use crate::HivehookError;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
const FRAGMENT: &str = "id name url signingSecret status type typeConfig timeoutMs rateLimitRps retryPolicy { maxAttempts initialDelay maxDelay backoffFactor } headers authType oauth2Config { tokenUrl clientId clientSecret scopes audience } mtlsCert mtlsKey deliveryMode pollApiKeyPrefix pollApiKey ordered blockedDeliveryId healthScore disabledReason healthConfig { windowHours disableBelow } outputFormat createdAt";
const POLL_FRAGMENT: &str = "id eventId subscriptionId destinationId status attempts maxAttempts nextAttemptAt createdAt";
#[non_exhaustive]
#[derive(Debug, Default, Clone)]
pub struct ListDestinationsOptions {
pub status: Option<String>,
pub search: Option<String>,
pub limit: Option<i32>,
pub offset: Option<i32>,
pub after: Option<String>,
pub first: Option<i32>,
}
#[non_exhaustive]
#[derive(Debug, Default, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateDestinationInput {
pub name: String,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "type")]
pub type_: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub type_config: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout_ms: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rate_limit_rps: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub retry_policy: Option<RetryPolicy>,
#[serde(skip_serializing_if = "Option::is_none")]
pub auth_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub oauth2_config: Option<OAuth2Config>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mtls_cert: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mtls_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub delivery_mode: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ordered: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub health_config: Option<HealthConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output_format: Option<String>,
}
#[non_exhaustive]
#[derive(Debug, Default, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateDestinationInput {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "type")]
pub type_: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub type_config: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout_ms: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rate_limit_rps: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<HashMap<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub retry_policy: Option<RetryPolicy>,
#[serde(skip_serializing_if = "Option::is_none")]
pub auth_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub oauth2_config: Option<OAuth2Config>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mtls_cert: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mtls_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub delivery_mode: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ordered: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub health_config: Option<HealthConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output_format: Option<String>,
}
#[derive(Deserialize)]
struct ListData {
destinations: ListResult<Destination>,
}
#[derive(Deserialize)]
struct GetData {
destination: Option<Destination>,
}
#[derive(Deserialize)]
struct CreateData {
#[serde(rename = "createDestination")]
create_destination: Destination,
}
#[derive(Deserialize)]
struct UpdateData {
#[serde(rename = "updateDestination")]
update_destination: Destination,
}
#[derive(Deserialize)]
struct DeleteData {
#[serde(rename = "deleteDestination")]
delete_destination: bool,
}
#[derive(Deserialize)]
struct RotateData {
#[serde(rename = "rotateDestinationSecret")]
rotate_destination_secret: Destination,
}
#[derive(Deserialize)]
struct PollData {
#[serde(rename = "pollDeliveries")]
poll_deliveries: ListResult<Delivery>,
}
#[derive(Deserialize)]
struct AckData {
#[serde(rename = "ackDeliveries")]
ack_deliveries: i32,
}
#[derive(Deserialize)]
struct RegeneratePollKeyData {
#[serde(rename = "regeneratePollApiKey")]
regenerate_poll_api_key: Destination,
}
#[derive(Deserialize)]
struct SkipDlqData {
#[serde(rename = "skipDLQEntry")]
skip_dlq_entry: bool,
}
#[cfg(feature = "blocking")]
pub struct DestinationService<'a> {
pub(crate) transport: &'a crate::transport::BlockingGraphQLTransport,
}
#[cfg(feature = "blocking")]
impl<'a> DestinationService<'a> {
pub fn list(
&self,
options: ListDestinationsOptions,
) -> Result<ListResult<Destination>, HivehookError> {
let query = format!(
r#"query($status: DestinationStatus, $search: String, $limit: Int, $offset: Int, $after: String, $first: Int) {{
destinations(status: $status, search: $search, limit: $limit, offset: $offset, after: $after, first: $first) {{
nodes {{ {FRAGMENT} }}
pageInfo {{ total limit offset endCursor hasNextPage }}
}}
}}"#
);
let mut v = vars();
put_opt(&mut v, "status", options.status);
put_opt(&mut v, "search", options.search);
put_opt(&mut v, "limit", options.limit);
put_opt(&mut v, "offset", options.offset);
put_opt(&mut v, "after", options.after);
put_opt(&mut v, "first", options.first);
let data: ListData = self.transport.execute(&query, Some(v))?;
Ok(data.destinations)
}
pub fn get(&self, id: &str) -> Result<Option<Destination>, HivehookError> {
let query = format!("query($id: UUID!) {{ destination(id: $id) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
let data: GetData = self.transport.execute(&query, Some(v))?;
Ok(data.destination)
}
pub fn create(
&self,
input: CreateDestinationInput,
) -> Result<Destination, HivehookError> {
let query = format!("mutation($input: CreateDestinationInput!) {{ createDestination(input: $input) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("input".into(), serde_json::to_value(input)?);
let data: CreateData = self.transport.execute(&query, Some(v))?;
Ok(data.create_destination)
}
pub fn update(
&self,
id: &str,
input: UpdateDestinationInput,
) -> Result<Destination, HivehookError> {
let query = format!("mutation($id: UUID!, $input: UpdateDestinationInput!) {{ updateDestination(id: $id, input: $input) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
v.insert("input".into(), serde_json::to_value(input)?);
let data: UpdateData = self.transport.execute(&query, Some(v))?;
Ok(data.update_destination)
}
pub fn delete(&self, id: &str) -> Result<bool, HivehookError> {
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
let data: DeleteData = self.transport.execute(
"mutation($id: UUID!) { deleteDestination(id: $id) }",
Some(v),
)?;
Ok(data.delete_destination)
}
pub fn rotate_secret(&self, id: &str) -> Result<Destination, HivehookError> {
let query = format!("mutation($id: UUID!) {{ rotateDestinationSecret(id: $id) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
let data: RotateData = self.transport.execute(&query, Some(v))?;
Ok(data.rotate_destination_secret)
}
pub fn poll_deliveries(
&self,
destination_id: &str,
cursor: Option<String>,
limit: Option<i32>,
) -> Result<ListResult<Delivery>, HivehookError> {
let query = format!(
r#"query($destinationId: UUID!, $cursor: String, $limit: Int) {{
pollDeliveries(destinationId: $destinationId, cursor: $cursor, limit: $limit) {{
nodes {{ {POLL_FRAGMENT} }}
pageInfo {{ total limit offset endCursor hasNextPage }}
}}
}}"#
);
let mut v = vars();
v.insert("destinationId".into(), Value::String(destination_id.into()));
put_opt(&mut v, "cursor", cursor);
put_opt(&mut v, "limit", limit);
let data: PollData = self.transport.execute(&query, Some(v))?;
Ok(data.poll_deliveries)
}
pub fn ack_deliveries(
&self,
destination_id: &str,
delivery_ids: &[String],
) -> Result<i32, HivehookError> {
let mut v = vars();
v.insert("destinationId".into(), Value::String(destination_id.into()));
v.insert("deliveryIds".into(), serde_json::to_value(delivery_ids)?);
let data: AckData = self.transport.execute(
"mutation($destinationId: UUID!, $deliveryIds: [UUID!]!) { ackDeliveries(destinationId: $destinationId, deliveryIds: $deliveryIds) }",
Some(v),
)?;
Ok(data.ack_deliveries)
}
pub fn regenerate_poll_api_key(
&self,
destination_id: &str,
) -> Result<Destination, HivehookError> {
let query = format!("mutation($destinationId: UUID!) {{ regeneratePollApiKey(destinationId: $destinationId) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("destinationId".into(), Value::String(destination_id.into()));
let data: RegeneratePollKeyData = self.transport.execute(&query, Some(v))?;
Ok(data.regenerate_poll_api_key)
}
pub fn skip_dlq_entry(&self, id: &str) -> Result<bool, HivehookError> {
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
let data: SkipDlqData = self
.transport
.execute("mutation($id: UUID!) { skipDLQEntry(id: $id) }", Some(v))?;
Ok(data.skip_dlq_entry)
}
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub struct AsyncDestinationService<'a> {
pub(crate) transport: &'a crate::transport::AsyncGraphQLTransport,
}
#[cfg(feature = "async")]
impl<'a> AsyncDestinationService<'a> {
pub async fn list(
&self,
options: ListDestinationsOptions,
) -> Result<ListResult<Destination>, HivehookError> {
let query = format!(
r#"query($status: DestinationStatus, $search: String, $limit: Int, $offset: Int, $after: String, $first: Int) {{
destinations(status: $status, search: $search, limit: $limit, offset: $offset, after: $after, first: $first) {{
nodes {{ {FRAGMENT} }}
pageInfo {{ total limit offset endCursor hasNextPage }}
}}
}}"#
);
let mut v = vars();
put_opt(&mut v, "status", options.status);
put_opt(&mut v, "search", options.search);
put_opt(&mut v, "limit", options.limit);
put_opt(&mut v, "offset", options.offset);
put_opt(&mut v, "after", options.after);
put_opt(&mut v, "first", options.first);
let data: ListData = self.transport.execute(&query, Some(v)).await?;
Ok(data.destinations)
}
pub async fn get(&self, id: &str) -> Result<Option<Destination>, HivehookError> {
let query = format!("query($id: UUID!) {{ destination(id: $id) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
let data: GetData = self.transport.execute(&query, Some(v)).await?;
Ok(data.destination)
}
pub async fn create(
&self,
input: CreateDestinationInput,
) -> Result<Destination, HivehookError> {
let query = format!("mutation($input: CreateDestinationInput!) {{ createDestination(input: $input) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("input".into(), serde_json::to_value(input)?);
let data: CreateData = self.transport.execute(&query, Some(v)).await?;
Ok(data.create_destination)
}
pub async fn update(
&self,
id: &str,
input: UpdateDestinationInput,
) -> Result<Destination, HivehookError> {
let query = format!("mutation($id: UUID!, $input: UpdateDestinationInput!) {{ updateDestination(id: $id, input: $input) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
v.insert("input".into(), serde_json::to_value(input)?);
let data: UpdateData = self.transport.execute(&query, Some(v)).await?;
Ok(data.update_destination)
}
pub async fn delete(&self, id: &str) -> Result<bool, HivehookError> {
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
let data: DeleteData = self
.transport
.execute(
"mutation($id: UUID!) { deleteDestination(id: $id) }",
Some(v),
)
.await?;
Ok(data.delete_destination)
}
pub async fn rotate_secret(&self, id: &str) -> Result<Destination, HivehookError> {
let query = format!("mutation($id: UUID!) {{ rotateDestinationSecret(id: $id) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
let data: RotateData = self.transport.execute(&query, Some(v)).await?;
Ok(data.rotate_destination_secret)
}
pub async fn poll_deliveries(
&self,
destination_id: &str,
cursor: Option<String>,
limit: Option<i32>,
) -> Result<ListResult<Delivery>, HivehookError> {
let query = format!(
r#"query($destinationId: UUID!, $cursor: String, $limit: Int) {{
pollDeliveries(destinationId: $destinationId, cursor: $cursor, limit: $limit) {{
nodes {{ {POLL_FRAGMENT} }}
pageInfo {{ total limit offset endCursor hasNextPage }}
}}
}}"#
);
let mut v = vars();
v.insert("destinationId".into(), Value::String(destination_id.into()));
put_opt(&mut v, "cursor", cursor);
put_opt(&mut v, "limit", limit);
let data: PollData = self.transport.execute(&query, Some(v)).await?;
Ok(data.poll_deliveries)
}
pub async fn ack_deliveries(
&self,
destination_id: &str,
delivery_ids: &[String],
) -> Result<i32, HivehookError> {
let mut v = vars();
v.insert("destinationId".into(), Value::String(destination_id.into()));
v.insert("deliveryIds".into(), serde_json::to_value(delivery_ids)?);
let data: AckData = self.transport.execute(
"mutation($destinationId: UUID!, $deliveryIds: [UUID!]!) { ackDeliveries(destinationId: $destinationId, deliveryIds: $deliveryIds) }",
Some(v),
).await?;
Ok(data.ack_deliveries)
}
pub async fn regenerate_poll_api_key(
&self,
destination_id: &str,
) -> Result<Destination, HivehookError> {
let query = format!("mutation($destinationId: UUID!) {{ regeneratePollApiKey(destinationId: $destinationId) {{ {FRAGMENT} }} }}");
let mut v = vars();
v.insert("destinationId".into(), Value::String(destination_id.into()));
let data: RegeneratePollKeyData = self.transport.execute(&query, Some(v)).await?;
Ok(data.regenerate_poll_api_key)
}
pub async fn skip_dlq_entry(&self, id: &str) -> Result<bool, HivehookError> {
let mut v = vars();
v.insert("id".into(), Value::String(id.into()));
let data: SkipDlqData = self
.transport
.execute("mutation($id: UUID!) { skipDLQEntry(id: $id) }", Some(v))
.await?;
Ok(data.skip_dlq_entry)
}
}