seda_sdk_rs/
process.rs

1//! Process management utilities for the SDK.
2//!
3//! This module provides functionality for handling program arguments, environment variables,
4//! and process termination with specific exit codes and results.
5//!
6//! # Examples
7//!
8//! ```no_run
9//! use seda_sdk_rs::process::Process;
10//!
11//! // Handle success case
12//! let result = vec![1, 2, 3];
13//! Process::success(&result);
14//!
15//! // Handle error case with message
16//! Process::exit_with_message(1, "Operation failed");
17//! ```
18
19use std::{
20    collections::BTreeMap,
21    env::{self},
22    process,
23};
24
25use crate::{
26    raw::{self},
27    vm_modes::{DR_REPLICATION_FACTOR_ENV_KEY, VM_MODE_DR, VM_MODE_ENV_KEY, VM_MODE_TALLY},
28};
29
30/// Utilities for managing process-level operations.
31pub struct Process;
32
33impl Process {
34    /// Returns a vector of command-line arguments passed to the program.
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// use seda_sdk_rs::process::Process;
40    ///
41    /// let args = Process::args();
42    /// // args[0] is the program name
43    /// // args[1] would be the first argument
44    /// ```
45    pub fn args() -> Vec<String> {
46        env::args().collect()
47    }
48
49    /// Returns a map of all environment variables.
50    ///
51    /// # Examples
52    ///
53    /// ```
54    /// use seda_sdk_rs::process::Process;
55    ///
56    /// std::env::set_var("TEST_VAR", "test_value");
57    ///
58    /// let env_vars = Process::envs();
59    /// assert!(env_vars.contains_key("TEST_VAR"));
60    /// for (key, value) in env_vars {
61    ///     println!("{}: {}", key, value);
62    /// }
63    /// ```
64    pub fn envs() -> BTreeMap<String, String> {
65        env::vars().collect()
66    }
67
68    /// Retrieves and decodes the data request inputs
69    ///
70    /// # Panics
71    ///
72    /// This function will panic if:
73    /// - There were no arguments passed to the program.
74    /// - The second argument (index 1) is not a valid hex string.
75    ///
76    /// # Examples
77    ///
78    /// ```no_run
79    /// use seda_sdk_rs::process::Process;
80    ///
81    /// let input_bytes = Process::get_inputs();
82    /// // Process the input bytes...
83    /// ```
84    pub fn get_inputs() -> Vec<u8> {
85        // 1 is inputs because 0 is name of the program
86        let args = Self::args();
87        let raw_input = args.get(1).expect("Arg at index 1 must best set");
88
89        hex::decode(raw_input).expect("Arg at index 1 is not a valid hex string")
90    }
91
92    /// Gets the VM mode from environment variables.
93    ///
94    /// # Panics
95    ///
96    /// This function will panic if the `VM_MODE` environment variable is not set.
97    /// Which should never happen in a properly configured environment.
98    fn get_vm_mode() -> String {
99        env::var(VM_MODE_ENV_KEY).expect("VM_MODE is not set in environment")
100    }
101
102    /// Checks if the current VM mode is set to tally mode.
103    ///
104    /// # Examples
105    ///
106    /// ```
107    /// use seda_sdk_rs::process::Process;
108    ///
109    /// std::env::set_var("VM_MODE", "tally");
110    /// if Process::is_tally_vm_mode() {
111    ///     // Handle tally mode specific logic
112    /// }
113    /// ```
114    pub fn is_tally_vm_mode() -> bool {
115        Self::get_vm_mode() == VM_MODE_TALLY
116    }
117
118    /// Checks if the current VM mode is set to DR mode.
119    ///
120    /// # Examples
121    ///
122    /// ```no_run
123    /// use seda_sdk_rs::process::Process;
124    ///
125    /// if Process::is_dr_vm_mode() {
126    ///     let replication = Process::replication_factor();
127    ///     // Handle DR mode specific logic
128    /// }
129    /// ```
130    pub fn is_dr_vm_mode() -> bool {
131        Self::get_vm_mode() == VM_MODE_DR
132    }
133
134    /// Exits the process successfully (code 0) with the given result.
135    ///
136    /// # Examples
137    ///
138    /// ```no_run
139    /// use seda_sdk_rs::process::Process;
140    ///
141    /// let result = vec![0x01, 0x02, 0x03];
142    /// Process::success(&result);
143    /// ```
144    pub fn success(result: &[u8]) -> ! {
145        Self::exit_with_result(0, result);
146    }
147
148    /// Exits the process with an error (code 1) and the given result.
149    ///
150    /// # Examples
151    ///
152    /// ```no_run
153    /// use seda_sdk_rs::process::Process;
154    ///
155    /// let error_data = vec![0xFF];
156    /// Process::error(&error_data);
157    /// ```
158    pub fn error(result: &[u8]) -> ! {
159        Self::exit_with_result(1, result);
160    }
161
162    /// Gets the replication factor for the data request
163    ///
164    /// # Panics
165    ///
166    /// This function will panic if:
167    /// - The `DR_REPLICATION_FACTOR_ENV_KEY` environment variable is not set.
168    /// - The value of `DR_REPLICATION_FACTOR_ENV_KEY` is not a valid `u16`.
169    ///
170    /// These conditions should never happen in a properly configured environment.
171    ///
172    /// # Examples
173    ///
174    /// ```no_run
175    /// use seda_sdk_rs::process::Process;
176    ///
177    /// if Process::is_dr_vm_mode() {
178    ///     let factor = Process::replication_factor();
179    ///     println!("Replication factor: {}", factor);
180    /// }
181    /// ```
182    pub fn replication_factor() -> u16 {
183        let variable = env::var(DR_REPLICATION_FACTOR_ENV_KEY)
184            .unwrap_or_else(|_| panic!("{DR_REPLICATION_FACTOR_ENV_KEY} is not set in environment"));
185
186        variable
187            .parse()
188            .unwrap_or_else(|_| panic!("{DR_REPLICATION_FACTOR_ENV_KEY} must be a valid u16"))
189    }
190
191    /// Exits the process with the given code and message.
192    ///
193    /// # Examples
194    ///
195    /// ```no_run
196    /// use seda_sdk_rs::process::Process;
197    ///
198    /// // Exit with an error message
199    /// Process::exit_with_message(1, "Operation failed: invalid input");
200    ///
201    /// // Exit with success message
202    /// Process::exit_with_message(0, "Operation completed successfully");
203    /// ```
204    pub fn exit_with_message(code: u8, message: &str) -> ! {
205        let message_encoded = message.as_bytes();
206        Self::exit_with_result(code, message_encoded);
207    }
208
209    /// Exits the process with the given code and result bytes.
210    ///
211    /// # Examples
212    ///
213    /// ```no_run
214    /// use seda_sdk_rs::process::Process;
215    ///
216    /// let result = vec![1, 2, 3, 4];
217    /// Process::exit_with_result(0, &result);
218    /// ```
219    pub fn exit_with_result(code: u8, result: &[u8]) -> ! {
220        unsafe { raw::execution_result(result.as_ptr(), result.len() as u32) };
221        process::exit(code.into());
222    }
223
224    /// Exits the process with the given code and an empty result.
225    ///
226    /// # Examples
227    ///
228    /// ```no_run
229    /// use seda_sdk_rs::process::Process;
230    ///
231    /// // Exit successfully with no result
232    /// Process::exit(0);
233    ///
234    /// // Exit with error code
235    /// Process::exit(1);
236    /// ```
237    pub fn exit(code: u8) -> ! {
238        Self::exit_with_result(code, &[]);
239    }
240}