zeebe_rs/
signal.rs

1use crate::{Client, ClientError, proto};
2use serde::Serialize;
3
4pub struct Initial;
5pub struct WithName;
6
7pub trait BroadcastSignalRequestState {}
8impl BroadcastSignalRequestState for Initial {}
9impl BroadcastSignalRequestState for WithName {}
10
11/// Request to broadcast a signal across the cluster
12///
13/// A signal can trigger multiple catching signal events in different process instances.
14/// Signal events are matched by name and tenant ID if multi-tenancy is enabled.
15///
16/// # Examples
17/// ```ignore
18/// client
19///     .broadcast_signal()
20///     .with_signal_name(String::from("Hello_Signal"))
21///     .send()
22///     .await?;
23/// ```
24#[derive(Debug, Clone)]
25pub struct BroadcastSignalRequest<T: BroadcastSignalRequestState> {
26    client: Client,
27    signal_name: String,
28    variables: serde_json::Value,
29    tenant_id: String,
30    _state: std::marker::PhantomData<T>,
31}
32
33impl<T: BroadcastSignalRequestState> BroadcastSignalRequest<T> {
34    pub(crate) fn new(client: Client) -> BroadcastSignalRequest<Initial> {
35        BroadcastSignalRequest {
36            client,
37            signal_name: String::new(),
38            variables: serde_json::Value::default(),
39            tenant_id: String::new(),
40            _state: std::marker::PhantomData,
41        }
42    }
43
44    fn transition<NewState: BroadcastSignalRequestState>(self) -> BroadcastSignalRequest<NewState> {
45        BroadcastSignalRequest {
46            client: self.client,
47            signal_name: self.signal_name,
48            variables: self.variables,
49            tenant_id: self.tenant_id,
50            _state: std::marker::PhantomData,
51        }
52    }
53}
54
55impl BroadcastSignalRequest<Initial> {
56    /// Sets the name of the signal to broadcast
57    ///
58    /// # Arguments
59    /// * `signal_name` - Name that will be matched with signal catch events
60    ///
61    /// # Returns
62    /// A `BroadcastSignalRequest` in the `WithName` state
63    pub fn with_signal_name(mut self, signal_name: String) -> BroadcastSignalRequest<WithName> {
64        self.signal_name = signal_name;
65        self.transition()
66    }
67}
68
69impl BroadcastSignalRequest<WithName> {
70    /// Sets variables that will be available to all triggered signal events
71    ///
72    /// # Arguments
73    /// * `data` - Variables as serializable type that will be converted to JSON
74    ///
75    /// # Returns
76    /// A `Result` containing the updated `BroadcastSignalRequest` or a `ClientError`
77    ///
78    /// # Notes
79    /// Must be a JSON object, e.g. `{ "a": 1, "b": 2 }`. Arrays like `[1, 2]` are not valid.
80    pub fn with_variables<T: Serialize>(mut self, data: T) -> Result<Self, ClientError> {
81        self.variables = serde_json::to_value(data)
82            .map_err(|e| ClientError::SerializationFailed { source: e })?;
83        Ok(self)
84    }
85
86    /// Sets the tenant ID that owns this signal
87    ///
88    /// # Arguments
89    /// * `tenant_id` - ID of tenant that owns the signal
90    ///
91    /// # Returns
92    /// The updated `BroadcastSignalRequest`
93    pub fn with_tenant_id(mut self, tenant_id: String) -> Self {
94        self.tenant_id = tenant_id;
95        self
96    }
97
98    /// Sends the broadcast signal request to the gateway
99    ///
100    /// # Returns
101    /// A `Result` containing the `BroadcastSignalResponse` or a `ClientError`
102    ///
103    /// # Errors
104    /// - `INVALID_ARGUMENT`: Missing signal name or invalid variables format
105    /// - `PERMISSION_DENIED`: Not authorized for tenant
106    pub async fn send(mut self) -> Result<BroadcastSignalResponse, ClientError> {
107        let res = self
108            .client
109            .gateway_client
110            .broadcast_signal(proto::BroadcastSignalRequest {
111                signal_name: self.signal_name,
112                variables: self.variables.to_string(),
113                tenant_id: self.tenant_id,
114            })
115            .await?;
116
117        Ok(res.into_inner().into())
118    }
119}
120
121/// Response from broadcasting a signal
122///
123/// Contains:
124/// - Key uniquely identifying this signal broadcast
125/// - Tenant ID that owns the signal
126#[derive(Debug, Clone)]
127pub struct BroadcastSignalResponse {
128    key: i64,
129    tenant_id: String,
130}
131
132impl From<proto::BroadcastSignalResponse> for BroadcastSignalResponse {
133    fn from(value: proto::BroadcastSignalResponse) -> BroadcastSignalResponse {
134        BroadcastSignalResponse {
135            key: value.key,
136            tenant_id: value.tenant_id,
137        }
138    }
139}
140
141impl BroadcastSignalResponse {
142    /// Returns the unique identifier for this signal broadcast operation
143    ///
144    /// # Returns
145    /// The unique identifier for this signal broadcast operation
146    pub fn key(&self) -> i64 {
147        self.key
148    }
149
150    /// Returns the ID of tenant that owns the signal
151    ///
152    /// # Returns
153    /// The ID of tenant that owns the signal, empty if multi-tenancy is disabled
154    pub fn tenant_id(&self) -> &str {
155        &self.tenant_id
156    }
157}