warpgate_api/
host_funcs.rs1use crate::virtual_path::VirtualPath;
2use crate::{AnyResult, api_struct, api_unit_enum};
3use rustc_hash::FxHashMap;
4use serde::de::DeserializeOwned;
5
6api_unit_enum!(
7 pub enum HostLogTarget {
9 Stderr,
11 Stdout,
12 Debug,
14 Error,
15 Trace,
16 Warn,
17 #[default]
18 Tracing,
19 }
20);
21
22api_struct!(
23 #[serde(default)]
25 pub struct HostLogInput {
26 pub data: FxHashMap<String, serde_json::Value>,
27 pub message: String,
28 pub target: HostLogTarget,
29 }
30);
31
32impl HostLogInput {
33 pub fn new(message: impl AsRef<str>) -> Self {
35 Self {
36 message: message.as_ref().to_owned(),
37 ..Default::default()
38 }
39 }
40}
41
42impl From<&str> for HostLogInput {
43 fn from(message: &str) -> Self {
44 HostLogInput::new(message)
45 }
46}
47
48impl From<String> for HostLogInput {
49 fn from(message: String) -> Self {
50 HostLogInput::new(message)
51 }
52}
53
54api_struct!(
55 #[serde(default)]
57 pub struct ExecCommandInput {
58 pub command: String,
61
62 #[serde(skip_serializing_if = "Vec::is_empty")]
64 pub args: Vec<String>,
65
66 #[serde(skip_serializing_if = "FxHashMap::is_empty")]
68 pub env: FxHashMap<String, String>,
69
70 #[doc(hidden)]
72 pub set_executable: bool,
73
74 pub stream: bool,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub working_dir: Option<VirtualPath>,
80 }
81);
82
83impl ExecCommandInput {
84 pub fn new<C, I, V>(command: C, args: I) -> ExecCommandInput
86 where
87 C: AsRef<str>,
88 I: IntoIterator<Item = V>,
89 V: AsRef<str>,
90 {
91 let mut input = Self::pipe(command, args);
92 input.stream = true;
93 input
94 }
95
96 pub fn pipe<C, I, V>(command: C, args: I) -> ExecCommandInput
98 where
99 C: AsRef<str>,
100 I: IntoIterator<Item = V>,
101 V: AsRef<str>,
102 {
103 ExecCommandInput {
104 command: command.as_ref().to_string(),
105 args: args.into_iter().map(|a| a.as_ref().to_owned()).collect(),
106 ..ExecCommandInput::default()
107 }
108 }
109
110 pub fn inherit<C, I, V>(command: C, args: I) -> ExecCommandInput
112 where
113 C: AsRef<str>,
114 I: IntoIterator<Item = V>,
115 V: AsRef<str>,
116 {
117 Self::new(command, args)
118 }
119}
120
121api_struct!(
122 #[serde(default)]
124 pub struct ExecCommandOutput {
125 pub command: String,
126 pub exit_code: i32,
127 pub stderr: String,
128 pub stdout: String,
129 }
130);
131
132impl ExecCommandOutput {
133 pub fn get_output(&self) -> String {
134 let mut out = String::new();
135 out.push_str(self.stdout.trim());
136
137 if !self.stderr.is_empty() {
138 if !out.is_empty() {
139 out.push(' ');
140 }
141
142 out.push_str(self.stderr.trim());
143 }
144
145 out
146 }
147}
148
149api_struct!(
150 pub struct SendRequestInput {
152 pub url: String,
154
155 #[serde(default, skip_serializing_if = "FxHashMap::is_empty")]
157 pub headers: FxHashMap<String, String>,
158 }
159);
160
161impl SendRequestInput {
162 pub fn new(url: impl AsRef<str>) -> Self {
164 Self {
165 url: url.as_ref().to_owned(),
166 ..Default::default()
167 }
168 }
169}
170
171impl From<&str> for SendRequestInput {
172 fn from(url: &str) -> Self {
173 SendRequestInput::new(url)
174 }
175}
176
177impl From<String> for SendRequestInput {
178 fn from(url: String) -> Self {
179 SendRequestInput::new(url)
180 }
181}
182
183api_struct!(
184 pub struct SendRequestOutput {
186 pub body: Vec<u8>,
187 pub body_length: u64,
188 pub body_offset: u64,
189 pub status: u16,
190 }
191);
192
193impl SendRequestOutput {
194 pub fn json<T: DeserializeOwned>(self) -> AnyResult<T> {
196 Ok(serde_json::from_slice(&self.body)?)
197 }
198
199 pub fn text(self) -> AnyResult<String> {
201 Ok(String::from_utf8(self.body)?)
202 }
203}