1use crate::agent::{AgentWorkspace, PreparedAgentWorkspace};
6use crate::codec::runtime_provider::{
7 from_wire_hosted_app, from_wire_list_runtime_sessions_response,
8 from_wire_prepare_runtime_workspace_response, from_wire_runtime_session,
9 from_wire_runtime_support, to_wire_get_runtime_session_request,
10 to_wire_list_runtime_sessions_request, to_wire_prepare_runtime_workspace_request,
11 to_wire_remove_runtime_workspace_request, to_wire_start_hosted_app_request,
12 to_wire_start_runtime_session_request, to_wire_stop_runtime_session_request,
13};
14use crate::generated::v1;
15use crate::rpc_support::GestaltError;
16
17pub type RuntimeEgressMode = i32;
19
20pub mod runtime_egress_mode {
22 pub const RUNTIME_EGRESS_MODE_UNSPECIFIED: i32 = 0;
24 pub const RUNTIME_EGRESS_MODE_NONE: i32 = 1;
26 pub const RUNTIME_EGRESS_MODE_CIDR: i32 = 2;
28 pub const RUNTIME_EGRESS_MODE_HOSTNAME: i32 = 3;
30}
31
32#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct GetRuntimeSessionRequest {
36 pub session_id: String,
38}
39
40#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
42#[serde(rename_all = "camelCase")]
43pub struct HostedApp {
44 pub id: String,
46 pub session_id: String,
48 pub app_name: String,
50 pub dial_target: String,
52}
53
54#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
56#[serde(rename_all = "camelCase")]
57pub struct ListRuntimeSessionsRequest {
58 pub page_size: i32,
60 pub page_token: String,
62}
63
64#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
66#[serde(rename_all = "camelCase")]
67pub struct ListRuntimeSessionsResponse {
68 pub sessions: Vec<RuntimeSession>,
70 pub next_page_token: String,
72}
73
74#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
76#[serde(rename_all = "camelCase")]
77pub struct PrepareRuntimeWorkspaceRequest {
78 pub session_id: String,
80 pub agent_session_id: String,
86 pub workspace: Option<AgentWorkspace>,
88}
89
90#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct PrepareRuntimeWorkspaceResponse {
94 pub workspace: Option<PreparedAgentWorkspace>,
96}
97
98#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
100#[serde(rename_all = "camelCase")]
101pub struct RemoveRuntimeWorkspaceRequest {
102 pub session_id: String,
104 pub agent_session_id: String,
109}
110
111#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
113#[serde(rename_all = "camelCase")]
114pub struct RuntimeImagePullAuth {
115 pub docker_config_json: String,
117}
118
119#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct RuntimeSession {
123 pub id: String,
125 pub state: String,
127 pub metadata: std::collections::BTreeMap<String, String>,
129 pub lifecycle: Option<RuntimeSessionLifecycle>,
131 pub state_reason: String,
133 pub state_message: String,
135}
136
137#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
139#[serde(rename_all = "camelCase")]
140pub struct RuntimeSessionLifecycle {
141 #[serde(with = "crate::serde_time")]
142 pub started_at: Option<std::time::SystemTime>,
144 #[serde(with = "crate::serde_time")]
145 pub recommended_drain_at: Option<std::time::SystemTime>,
147 #[serde(with = "crate::serde_time")]
148 pub expires_at: Option<std::time::SystemTime>,
150}
151
152#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
154#[serde(rename_all = "camelCase")]
155pub struct RuntimeSupport {
156 pub can_host_apps: bool,
158 pub egress_mode: RuntimeEgressMode,
160 pub supports_prepare_workspace: bool,
162}
163
164#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
171#[serde(rename_all = "camelCase")]
172pub struct StartHostedAppRequest {
173 pub session_id: String,
175 pub app_name: String,
177 pub command: String,
179 pub args: Vec<String>,
181 pub env: std::collections::BTreeMap<String, String>,
183 pub allowed_hosts: Vec<String>,
185 pub default_action: String,
187 pub host_binary: String,
189 pub workdir: String,
191}
192
193#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
195#[serde(rename_all = "camelCase")]
196pub struct StartRuntimeSessionRequest {
197 pub app_name: String,
199 pub template: String,
201 pub image: String,
203 pub metadata: std::collections::BTreeMap<String, String>,
205 pub image_pull_auth: Option<RuntimeImagePullAuth>,
207}
208
209#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
211#[serde(rename_all = "camelCase")]
212pub struct StopRuntimeSessionRequest {
213 pub session_id: String,
215}
216
217pub struct Runtime {
219 inner: v1::runtime_client::RuntimeClient<tonic::transport::Channel>,
220 timeout: Option<std::time::Duration>,
221}
222
223impl Runtime {
224 pub fn new(channel: tonic::transport::Channel) -> Self {
226 Self {
227 inner: v1::runtime_client::RuntimeClient::new(channel),
228 timeout: None,
229 }
230 }
231
232 pub fn with_timeout(mut self, timeout: std::time::Duration) -> Self {
235 self.timeout = Some(timeout);
236 self
237 }
238
239 pub async fn get_support(&mut self) -> Result<RuntimeSupport, GestaltError> {
241 let mut tonic_request = tonic::Request::new(());
242 if let Some(timeout) = self.timeout {
243 tonic_request.set_timeout(timeout);
244 }
245 let response = self.inner.get_support(tonic_request).await?;
246 Ok(from_wire_runtime_support(response.into_inner()))
247 }
248
249 pub async fn start_session(
251 &mut self,
252 app_name: String,
253 template: String,
254 image: String,
255 image_pull_auth: Option<RuntimeImagePullAuth>,
256 ) -> Result<RuntimeSession, GestaltError> {
257 let request = StartRuntimeSessionRequest {
258 app_name,
259 template,
260 image,
261 image_pull_auth,
262 ..Default::default()
263 };
264 let mut tonic_request = tonic::Request::new(to_wire_start_runtime_session_request(request));
265 if let Some(timeout) = self.timeout {
266 tonic_request.set_timeout(timeout);
267 }
268 let response = self.inner.start_session(tonic_request).await?;
269 Ok(from_wire_runtime_session(response.into_inner()))
270 }
271
272 pub async fn start_session_raw(
274 &mut self,
275 request: StartRuntimeSessionRequest,
276 ) -> Result<RuntimeSession, GestaltError> {
277 let mut tonic_request = tonic::Request::new(to_wire_start_runtime_session_request(request));
278 if let Some(timeout) = self.timeout {
279 tonic_request.set_timeout(timeout);
280 }
281 let response = self.inner.start_session(tonic_request).await?;
282 Ok(from_wire_runtime_session(response.into_inner()))
283 }
284
285 pub async fn get_session(
287 &mut self,
288 session_id: String,
289 ) -> Result<RuntimeSession, GestaltError> {
290 let request = GetRuntimeSessionRequest { session_id };
291 let mut tonic_request = tonic::Request::new(to_wire_get_runtime_session_request(request));
292 if let Some(timeout) = self.timeout {
293 tonic_request.set_timeout(timeout);
294 }
295 let response = self.inner.get_session(tonic_request).await?;
296 Ok(from_wire_runtime_session(response.into_inner()))
297 }
298
299 pub async fn get_session_raw(
301 &mut self,
302 request: GetRuntimeSessionRequest,
303 ) -> Result<RuntimeSession, GestaltError> {
304 let mut tonic_request = tonic::Request::new(to_wire_get_runtime_session_request(request));
305 if let Some(timeout) = self.timeout {
306 tonic_request.set_timeout(timeout);
307 }
308 let response = self.inner.get_session(tonic_request).await?;
309 Ok(from_wire_runtime_session(response.into_inner()))
310 }
311
312 pub async fn list_sessions(
314 &mut self,
315 request: ListRuntimeSessionsRequest,
316 ) -> Result<ListRuntimeSessionsResponse, GestaltError> {
317 let mut tonic_request = tonic::Request::new(to_wire_list_runtime_sessions_request(request));
318 if let Some(timeout) = self.timeout {
319 tonic_request.set_timeout(timeout);
320 }
321 let response = self.inner.list_sessions(tonic_request).await?;
322 Ok(from_wire_list_runtime_sessions_response(
323 response.into_inner(),
324 ))
325 }
326
327 pub async fn stop_session(&mut self, session_id: String) -> Result<(), GestaltError> {
329 let request = StopRuntimeSessionRequest { session_id };
330 let mut tonic_request = tonic::Request::new(to_wire_stop_runtime_session_request(request));
331 if let Some(timeout) = self.timeout {
332 tonic_request.set_timeout(timeout);
333 }
334 self.inner.stop_session(tonic_request).await?;
335 Ok(())
336 }
337
338 pub async fn stop_session_raw(
340 &mut self,
341 request: StopRuntimeSessionRequest,
342 ) -> Result<(), GestaltError> {
343 let mut tonic_request = tonic::Request::new(to_wire_stop_runtime_session_request(request));
344 if let Some(timeout) = self.timeout {
345 tonic_request.set_timeout(timeout);
346 }
347 self.inner.stop_session(tonic_request).await?;
348 Ok(())
349 }
350
351 pub async fn prepare_workspace(
353 &mut self,
354 session_id: String,
355 agent_session_id: String,
356 workspace: Option<AgentWorkspace>,
357 ) -> Result<Option<PreparedAgentWorkspace>, GestaltError> {
358 let request = PrepareRuntimeWorkspaceRequest {
359 session_id,
360 agent_session_id,
361 workspace,
362 };
363 let mut tonic_request =
364 tonic::Request::new(to_wire_prepare_runtime_workspace_request(request));
365 if let Some(timeout) = self.timeout {
366 tonic_request.set_timeout(timeout);
367 }
368 let response = from_wire_prepare_runtime_workspace_response(
369 self.inner
370 .prepare_workspace(tonic_request)
371 .await?
372 .into_inner(),
373 );
374 Ok(response.workspace)
375 }
376
377 pub async fn prepare_workspace_raw(
379 &mut self,
380 request: PrepareRuntimeWorkspaceRequest,
381 ) -> Result<PrepareRuntimeWorkspaceResponse, GestaltError> {
382 let mut tonic_request =
383 tonic::Request::new(to_wire_prepare_runtime_workspace_request(request));
384 if let Some(timeout) = self.timeout {
385 tonic_request.set_timeout(timeout);
386 }
387 let response = self.inner.prepare_workspace(tonic_request).await?;
388 Ok(from_wire_prepare_runtime_workspace_response(
389 response.into_inner(),
390 ))
391 }
392
393 pub async fn remove_workspace(
395 &mut self,
396 session_id: String,
397 agent_session_id: String,
398 ) -> Result<(), GestaltError> {
399 let request = RemoveRuntimeWorkspaceRequest {
400 session_id,
401 agent_session_id,
402 };
403 let mut tonic_request =
404 tonic::Request::new(to_wire_remove_runtime_workspace_request(request));
405 if let Some(timeout) = self.timeout {
406 tonic_request.set_timeout(timeout);
407 }
408 self.inner.remove_workspace(tonic_request).await?;
409 Ok(())
410 }
411
412 pub async fn remove_workspace_raw(
414 &mut self,
415 request: RemoveRuntimeWorkspaceRequest,
416 ) -> Result<(), GestaltError> {
417 let mut tonic_request =
418 tonic::Request::new(to_wire_remove_runtime_workspace_request(request));
419 if let Some(timeout) = self.timeout {
420 tonic_request.set_timeout(timeout);
421 }
422 self.inner.remove_workspace(tonic_request).await?;
423 Ok(())
424 }
425
426 #[allow(clippy::too_many_arguments)]
428 pub async fn start_app(
429 &mut self,
430 session_id: String,
431 app_name: String,
432 command: String,
433 args: Vec<String>,
434 allowed_hosts: Vec<String>,
435 default_action: String,
436 host_binary: String,
437 workdir: String,
438 ) -> Result<HostedApp, GestaltError> {
439 let request = StartHostedAppRequest {
440 session_id,
441 app_name,
442 command,
443 args,
444 allowed_hosts,
445 default_action,
446 host_binary,
447 workdir,
448 ..Default::default()
449 };
450 let mut tonic_request = tonic::Request::new(to_wire_start_hosted_app_request(request));
451 if let Some(timeout) = self.timeout {
452 tonic_request.set_timeout(timeout);
453 }
454 let response = self.inner.start_app(tonic_request).await?;
455 Ok(from_wire_hosted_app(response.into_inner()))
456 }
457
458 pub async fn start_app_raw(
460 &mut self,
461 request: StartHostedAppRequest,
462 ) -> Result<HostedApp, GestaltError> {
463 let mut tonic_request = tonic::Request::new(to_wire_start_hosted_app_request(request));
464 if let Some(timeout) = self.timeout {
465 tonic_request.set_timeout(timeout);
466 }
467 let response = self.inner.start_app(tonic_request).await?;
468 Ok(from_wire_hosted_app(response.into_inner()))
469 }
470}