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}