返回 DeepSeek-TUI-2026
backend.rs
根目录 / crates / tui / src / sandbox / backend.rs
1 //! Pluggable sandbox backend abstraction.
2 //!
3 //! External sandbox backends route shell command execution to a remote service
4 //! (e.g. Alibaba OpenSandbox) instead of spawning a local process. This is
5 //! complementary to the OS-level sandbox module (Seatbelt / Landlock / Windows)
6 //! — the external backend *replaces* local execution entirely when configured.
7
8 use std::collections::HashMap;
9
10 use anyhow::Result;
11 use async_trait::async_trait;
12
13 /// Output from a sandbox backend execution.
14 #[derive(Debug, Clone)]
15 pub struct SandboxOutput {
16 /// Standard output from the command.
17 pub stdout: String,
18 /// Standard error from the command.
19 pub stderr: String,
20 /// Exit code (0 for success).
21 pub exit_code: i32,
22 }
23
24 /// The kind of external sandbox backend.
25 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
26 pub enum SandboxKind {
27 /// No external sandbox — execute commands locally.
28 None,
29 /// Alibaba OpenSandbox remote execution.
30 OpenSandbox,
31 }
32
33 impl SandboxKind {
34 /// Parse a sandbox backend name from config (case-insensitive).
35 #[must_use]
36 pub fn parse(value: &str) -> Option<Self> {
37 match value.trim().to_ascii_lowercase().as_str() {
38 "none" | "" => Some(Self::None),
39 "opensandbox" | "open-sandbox" | "open_sandbox" => Some(Self::OpenSandbox),
40 _ => None,
41 }
42 }
43
44 /// Human-readable label.
45 #[must_use]
46 pub fn as_str(self) -> &'static str {
47 match self {
48 Self::None => "none",
49 Self::OpenSandbox => "opensandbox",
50 }
51 }
52 }
53
54 /// Abstract interface for an external sandbox backend.
55 ///
56 /// Implementations send commands to a remote execution environment and return
57 /// structured output. The trait is `Send + Sync` so it can be stored in an
58 /// `Arc` and shared across async tasks.
59 #[async_trait]
60 pub trait SandboxBackend: Send + Sync {
61 /// Execute a shell command and return its output.
62 ///
63 /// `cmd` is the full shell command string (e.g. `"ls -la"`).
64 /// `env` contains additional environment variables to set.
65 async fn exec(&self, cmd: &str, env: &HashMap<String, String>) -> Result<SandboxOutput>;
66 }
67
68 use crate::config::Config;
69
70 /// Create the configured sandbox backend from config.
71 ///
72 /// Returns `None` when no external sandbox backend is configured (i.e. the
73 /// `sandbox_backend` key is absent, empty, or `"none"`). When `"opensandbox"`
74 /// is set, constructs an [`OpenSandboxBackend`] using `sandbox_url` and
75 /// `sandbox_api_key`.
76 pub fn create_backend(config: &Config) -> Result<Option<Box<dyn SandboxBackend>>> {
77 let kind = config
78 .sandbox_backend
79 .as_deref()
80 .and_then(SandboxKind::parse)
81 .unwrap_or(SandboxKind::None);
82
83 match kind {
84 SandboxKind::None => Ok(None),
85 SandboxKind::OpenSandbox => {
86 let base_url = config
87 .sandbox_url
88 .clone()
89 .unwrap_or_else(|| "http://localhost:8080".to_string());
90 let api_key = config.sandbox_api_key.clone();
91 let backend = super::opensandbox::OpenSandboxBackend::new(base_url, api_key, 30)?;
92 Ok(Some(Box::new(backend)))
93 }
94 }
95 }
96
96 lines RUST