blueprint_core/job/
call.rs

1use super::id::JobId;
2use crate::extensions::Extensions;
3use crate::metadata::{MetadataMap, MetadataValue};
4use bytes::Bytes;
5
6/// Representation of a job call event
7///
8/// These events come from [Producers], which may be listening for on-chain events
9/// (e.g. [`TangleProducer`]), or simply waiting for a timer to end (e.g. [`CronJob`]).
10///
11/// A `JobCall` consists of two parts: a header and a body.
12///
13/// ## Header
14///
15/// The header is a [`Parts`] containing the [`JobId`] and any metadata associated with the call.
16/// This metadata is used by argument extractors, see the [extract] module for more information.
17///
18/// ## Body
19///
20/// The body will typically contain the arguments associated with the job call, in a producer-specific format.
21/// For example, the [`TangleProducer`] will produce `JobCall`s with a body compatible with
22/// the [`TangleArg`] extractors.
23///
24/// [`CronJob`]: https://docs.rs/blueprint_sdk/latest/blueprint_sdk/producers/struct.CronJob.html
25/// [`TangleProducer`]: https://docs.rs/blueprint_sdk/latest/blueprint_sdk/tangle/producer/struct.TangleProducer.html
26/// [`TangleArg`]: https://docs.rs/blueprint_sdk/latest/blueprint_sdk/tangle/extract/struct.TangleArg.html
27/// [Producers]: https://docs.rs/blueprint_sdk/latest/blueprint_sdk/producers/index.html
28/// [extract]: https://docs.rs/blueprint_sdk/latest/blueprint_sdk/extract/index.html
29#[derive(Clone, Debug)]
30pub struct JobCall<T = Bytes> {
31    head: Parts,
32    body: T,
33}
34
35impl<T: Default> Default for JobCall<T> {
36    fn default() -> Self {
37        Self {
38            head: Parts::default(),
39            body: T::default(),
40        }
41    }
42}
43
44/// The metadata associated with a [`JobCall`]
45///
46/// This metadata is used by argument extractors, see the [extract] module for more information.
47#[derive(Clone, Debug)]
48#[non_exhaustive]
49pub struct Parts {
50    /// The Job ID
51    pub job_id: JobId,
52    /// Any metadata that was included in the job call
53    pub metadata: MetadataMap<MetadataValue>,
54    /// The job call extensions
55    pub extensions: Extensions,
56}
57
58impl Parts {
59    /// Create a new `Parts` with the given `job_id`
60    pub fn new<J: Into<JobId>>(job_id: J) -> Self {
61        Self {
62            job_id: job_id.into(),
63            metadata: MetadataMap::new(),
64            extensions: Extensions::new(),
65        }
66    }
67
68    /// Set the metadata to a pre-defined [`MetadataMap`]
69    pub fn with_metadata(mut self, metadata: MetadataMap<MetadataValue>) -> Self {
70        self.metadata = metadata;
71        self
72    }
73
74    /// Set the extensions to a pre-defined [`Extensions`]
75    pub fn with_extensions(mut self, extensions: Extensions) -> Self {
76        self.extensions = extensions;
77        self
78    }
79}
80
81impl Default for Parts {
82    fn default() -> Self {
83        Self {
84            job_id: JobId::ZERO,
85            metadata: MetadataMap::new(),
86            extensions: Extensions::new(),
87        }
88    }
89}
90
91impl<T> JobCall<T> {
92    /// Create an empty `JobCall`
93    ///
94    /// This is useful for producers such as [`CronJob`], where the intention is to simply trigger a
95    /// job with no extra arguments.
96    ///
97    /// [`CronJob`]: https://docs.rs/blueprint_sdk/latest/blueprint_sdk/producers/struct.CronJob.html
98    pub fn empty() -> Self
99    where
100        T: Default,
101    {
102        Self {
103            head: Parts::new(JobId::ZERO),
104            body: Default::default(),
105        }
106    }
107
108    /// Create a new `JobCall` with the given `job_id` and `body`
109    ///
110    /// # Examples
111    ///
112    /// ```rust
113    /// use blueprint_sdk::JobCall;
114    ///
115    /// const MY_JOB_ID: u8 = 0;
116    ///
117    /// let call = JobCall::new(MY_JOB_ID, ());
118    /// assert_eq!(call.job_id(), MY_JOB_ID.into());
119    /// ```
120    pub fn new<J: Into<JobId>>(job_id: J, body: T) -> Self {
121        Self {
122            head: Parts::new(job_id),
123            body,
124        }
125    }
126
127    /// Create a new `JobCall` with a pre-defined `parts` and `body`
128    ///
129    /// # Examples
130    ///
131    /// ```rust
132    /// use blueprint_sdk::JobCall;
133    /// use blueprint_sdk::job::call::Parts;
134    ///
135    /// const MY_JOB_ID: u8 = 0;
136    /// let parts = Parts::new(MY_JOB_ID);
137    ///
138    /// let call = JobCall::from_parts(parts, ());
139    /// assert_eq!(call.job_id(), MY_JOB_ID.into());
140    /// ```
141    pub fn from_parts(parts: Parts, body: T) -> Self {
142        Self { head: parts, body }
143    }
144
145    /// Get the job id of this `JobCall`
146    pub fn job_id(&self) -> JobId {
147        self.head.job_id
148    }
149
150    /// Get a mutable reference to the job id of this `JobCall`
151    pub fn job_id_mut(&mut self) -> &mut JobId {
152        &mut self.head.job_id
153    }
154
155    /// Get a reference to the call metadata
156    pub fn metadata(&self) -> &MetadataMap<MetadataValue> {
157        &self.head.metadata
158    }
159
160    /// Get a mutable reference to the call metadata
161    pub fn metadata_mut(&mut self) -> &mut MetadataMap<MetadataValue> {
162        &mut self.head.metadata
163    }
164
165    /// Get a reference to the call extensions
166    pub fn extensions(&self) -> &Extensions {
167        &self.head.extensions
168    }
169
170    /// Get a mutable reference to the call extensions
171    pub fn extensions_mut(&mut self) -> &mut Extensions {
172        &mut self.head.extensions
173    }
174
175    /// Get a reference to the body
176    pub fn body(&self) -> &T {
177        &self.body
178    }
179
180    /// Consume the `JobCall` and return the body
181    pub fn into_body(self) -> T {
182        self.body
183    }
184
185    pub fn into_parts(self) -> (Parts, T) {
186        (self.head, self.body)
187    }
188
189    /// Takes a closure and applies it to the body
190    ///
191    /// # Examples
192    ///
193    /// ```rust
194    /// use blueprint_sdk::job::call::JobCall;
195    ///
196    /// let call = JobCall::new(0, ());
197    /// let new_call = call.map(|_| "Hello!");
198    /// assert_eq!(*new_call.body(), "Hello!");
199    pub fn map<F, U>(self, f: F) -> JobCall<U>
200    where
201        F: FnOnce(T) -> U,
202    {
203        JobCall {
204            head: self.head,
205            body: f(self.body),
206        }
207    }
208}