actor_framework/
client.rs

1//! # Generic Client
2//!
3//! This module defines the generic client for communicating with actors.
4
5use crate::entity::ActorEntity;
6use crate::error::FrameworkError;
7use crate::message::ResourceRequest;
8use tokio::sync::{mpsc, oneshot};
9
10/// A type-safe client for interacting with a `ResourceActor`.
11#[derive(Clone)]
12/// ## ResourceClient
13///
14/// The `ResourceClient<T>` provides a type‑safe, async API for interacting with a `ResourceActor<T>`. It forwards CRUD + Action requests over a Tokio mpsc channel and returns results via oneshot channels. The client is cheap to clone and can be shared across tasks.
15///
16/// * **Cloneable** – holds only a sender, so cloning is inexpensive.
17/// * **Async API** – all methods return `Future`s that resolve to `Result<…, FrameworkError>`.
18/// * **Generic** – works with any entity that implements `ActorEntity`.
19pub struct ResourceClient<T: ActorEntity> {
20    sender: mpsc::Sender<ResourceRequest<T>>,
21}
22
23impl<T: ActorEntity> ResourceClient<T> {
24    pub fn new(sender: mpsc::Sender<ResourceRequest<T>>) -> Self {
25        Self { sender }
26    }
27
28    pub async fn create(&self, params: T::Create) -> Result<T::Id, FrameworkError> {
29        let (respond_to, response) = oneshot::channel();
30        self.sender
31            .send(ResourceRequest::Create { params, respond_to })
32            .await
33            .map_err(|_| FrameworkError::ActorClosed)?;
34        response.await.map_err(|_| FrameworkError::ActorDropped)?
35    }
36
37    pub async fn get(&self, id: T::Id) -> Result<Option<T>, FrameworkError> {
38        let (respond_to, response) = oneshot::channel();
39        self.sender
40            .send(ResourceRequest::Get { id, respond_to })
41            .await
42            .map_err(|_| FrameworkError::ActorClosed)?;
43        response.await.map_err(|_| FrameworkError::ActorDropped)?
44    }
45
46    pub async fn update(&self, id: T::Id, update: T::Update) -> Result<T, FrameworkError> {
47        let (respond_to, response) = oneshot::channel();
48        self.sender
49            .send(ResourceRequest::Update {
50                id,
51                update,
52                respond_to,
53            })
54            .await
55            .map_err(|_| FrameworkError::ActorClosed)?;
56        response.await.map_err(|_| FrameworkError::ActorDropped)?
57    }
58
59    #[allow(dead_code)]
60    pub async fn delete(&self, id: T::Id) -> Result<(), FrameworkError> {
61        let (respond_to, response) = oneshot::channel();
62        self.sender
63            .send(ResourceRequest::Delete { id, respond_to })
64            .await
65            .map_err(|_| FrameworkError::ActorClosed)?;
66        response.await.map_err(|_| FrameworkError::ActorDropped)?
67    }
68
69    pub async fn perform_action(
70        &self,
71        id: T::Id,
72        action: T::Action,
73    ) -> Result<T::ActionResult, FrameworkError> {
74        let (respond_to, response) = oneshot::channel();
75        self.sender
76            .send(ResourceRequest::Action {
77                id,
78                action,
79                respond_to,
80            })
81            .await
82            .map_err(|_| FrameworkError::ActorClosed)?;
83        response.await.map_err(|_| FrameworkError::ActorDropped)?
84    }
85}