use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::execution::{
ActionId, ApprovalRequirement, ExternalError, InvocationContext, OperationId,
};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct FacadeRequest {
pub operation_id: OperationId,
pub target: String,
pub input: Value,
}
pub use crate::{
ClientTask, InteractionKind, InteractionPreview, InteractionTone, PreviewDetail, PreviewValue,
};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct PreparedAction {
pub action_id: ActionId,
pub operation_id: OperationId,
pub preview: InteractionPreview,
#[serde(default)]
pub payload: Value,
pub revision: u64,
pub approval: ApprovalRequirement,
pub interaction_kind: InteractionKind,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct FacadeResult {
pub value: Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub continuation: Option<PreparedAction>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub context_invalidation: Option<crate::execution::ContextInvalidation>,
}
#[async_trait]
pub trait AppFacade: Send + Sync {
async fn invoke(
&self,
context: &InvocationContext,
request: FacadeRequest,
) -> Result<FacadeResult, ExternalError>;
async fn prepare(
&self,
context: &InvocationContext,
request: FacadeRequest,
) -> Result<PreparedAction, ExternalError>;
async fn commit(
&self,
context: &InvocationContext,
action: PreparedAction,
) -> Result<FacadeResult, ExternalError>;
async fn reject(
&self,
context: &InvocationContext,
action: PreparedAction,
) -> Result<(), ExternalError>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn typed_preview_rejects_incomplete_client_work() {
let mut preview = InteractionPreview::confirmation(
"integration.install",
"Integration required",
"Install it, then continue.",
);
preview.client_task = Some(ClientTask::InstallIntegrations {
integration_ids: Vec::new(),
});
assert!(!preview.is_valid());
preview.client_task = Some(ClientTask::InstallIntegrations {
integration_ids: vec!["matter".to_owned()],
});
assert!(preview.is_valid());
let encoded = serde_json::to_value(preview).expect("serializes");
assert_eq!(encoded["clientTask"]["type"], "install_integrations");
assert_eq!(encoded["clientTask"]["integrationIds"][0], "matter");
}
}