use std::fmt::{Display, Formatter, Result as FmtResult};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use specta::Type;
use tokio::sync::oneshot;
use zeroize::Zeroizing;
use aves::bus::BusRpcContext;
use aves::utils::uuid::SpectaUuid;
use super::domain::MessagingDomain;
use super::types::{
ConnectionRecord, EditConnection, MessagingCredentials, MessagingError, MessagingSendReceipt,
MessagingSenderConfig, NewConnection, NormalizedMessage,
};
pub(super) struct MessagingRequest {
pub(super) payload: MessagingRequestPayload,
pub(super) reply_to: oneshot::Sender<Result<MessagingResponse, MessagingError>>,
}
#[aves::bus_requests(marker = MessagingDomain, context = BusRpcContext, root_error = MessagingError, domain_error = MessagingError)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MessagingRequestPayload {
#[operation(name = "startServer", kind = "mutation", response = SuccessOutput, response_variant = "Success")]
StartServer,
#[privileged(reason = "Enclave-owned messaging credential supply")]
SupplyCredential {
credential_id: SpectaUuid,
#[serde(skip, default = "empty_credentials")]
credentials: MessagingCredentials,
},
#[privileged(reason = "Enclave-owned messaging credential removal")]
RemoveCredential { credential_id: SpectaUuid },
#[operation(name = "listConnections", kind = "query", response = ConnectionsOutput, response_variant = "Connections")]
ListConnections,
#[operation(name = "createConnection", kind = "mutation", response = ConnectionOutput, response_variant = "Connection")]
CreateConnection { input: NewConnection },
#[operation(name = "updateConnection", kind = "mutation", response = ConnectionOutput, response_variant = "Connection")]
UpdateConnection { id: SpectaUuid, input: EditConnection },
#[operation(name = "deleteConnection", kind = "mutation", response = SuccessOutput, response_variant = "Success")]
DeleteConnection { connection_id: SpectaUuid },
#[operation(name = "setConnectionEnabled", kind = "mutation", response = SuccessOutput, response_variant = "Success")]
SetConnectionEnabled { connection_id: SpectaUuid, enabled: bool },
#[operation(name = "list", kind = "query", response = SubscriptionsOutput, response_variant = "Subscriptions")]
List,
#[operation(name = "send", kind = "mutation", response = SendOutput, response_variant = "Send")]
Send {
sender: MessagingSenderConfig,
message: NormalizedMessage,
},
#[operation(name = "sendMetadataSchema", kind = "query", response = SendMetadataSchemaOutput, response_variant = "SendMetadataSchema")]
SendMetadataSchema { listener_type: ListenerType },
#[operation(name = "stopServer", kind = "mutation", response = SuccessOutput, response_variant = "Success")]
StopServer,
}
#[aves::bus_responses]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MessagingResponse {
Connections { connections: Vec<ConnectionRecord> },
Connection { connection: ConnectionRecord },
Subscriptions {
subscriptions: Vec<SubscriptionRow>,
},
ChannelMessage {
body: String,
metadata: Value,
},
SubscriptionTrigger,
Success,
Send { receipt: MessagingSendReceipt },
SendMetadataSchema { schema: Value },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MessagingBroadcast {
Trigger,
ChannelMessage { body: String, metadata: Value },
}
#[derive(Debug, Clone, Serialize, Deserialize, Type, JsonSchema)]
pub struct SubscriptionRow {
pub id: SpectaUuid,
pub listener_type: ListenerType,
pub subscribed_channels: Option<Vec<String>>,
pub flow_id: SpectaUuid,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Type, JsonSchema, PartialEq, Eq, Hash)]
pub enum ListenerType {
Telegram,
Slack,
Email,
}
impl Display for ListenerType {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str(match self {
ListenerType::Telegram => "Telegram",
ListenerType::Slack => "Slack",
ListenerType::Email => "Email",
})
}
}
impl ListenerType {
pub(super) fn from_storage(value: &str) -> Option<Self> {
match value {
"Email" => Some(Self::Email),
"Slack" => Some(Self::Slack),
"Telegram" => Some(Self::Telegram),
_ => None,
}
}
}
fn empty_credentials() -> MessagingCredentials {
MessagingCredentials::Telegram {
token: Zeroizing::new(String::new()),
}
}