yggdrasil/pages/admin/settings/
runner_section.rs1use leptos::prelude::*;
6
7use super::kit::{use_section, SettingRow, SettingsCard, SwitchRow};
8use super::SettingsSection;
9use crate::api::error::ApiError;
10use crate::api::settings::{get_runner_settings, update_runner_settings};
11use crate::components::forms::{FormInput, NumberInput};
12use crate::models::settings::RunnerSettings;
13
14async fn save(d: RunnerSettings) -> Result<RunnerSettings, ApiError> {
15 update_runner_settings(
16 d.allow_network,
17 d.max_concurrent,
18 d.max_cpu_cores,
19 d.max_memory_mb,
20 d.max_timeout_secs,
21 d.max_output_bytes,
22 d.max_source_bytes,
23 d.queue_timeout_secs,
24 d.task_ttl_secs,
25 d.languages,
26 )
27 .await
28}
29
30#[component]
32pub fn RunnerSection() -> impl IntoView {
33 let st = use_section(SettingsSection::Runner, get_runner_settings, save);
34 view! {
35 <SettingsCard
36 section=SettingsSection::Runner
37 description="文章里可运行代码块的沙箱资源限制。"
38 ready=st.ready()
39 load_failed=st.load_failed()
40 failed=st.failed()
41 >
42 <SwitchRow
43 label="允许容器联网"
44 hint="开启后读者运行的代码可以访问网络,有安全风险。"
45 checked=st.field(|d| d.allow_network)
46 ontoggle=move |()| st.edit(|d| d.allow_network = !d.allow_network)
47 />
48 <SettingRow label="最大并发任务" html_for="runner-concurrent">
49 <NumberInput
50 id="runner-concurrent"
51 value=st.field(|d| i64::from(d.max_concurrent))
52 min=1
53 max=64
54 unit="个"
55 onchange=move |v: i64| st.edit(|d| d.max_concurrent = v as u32)
56 />
57 </SettingRow>
58 <SettingRow label="CPU" html_for="runner-cpu" hint="每个任务可用的 CPU 核数,可以是小数。">
59 <div class="settings-inline">
60 <FormInput
61 id="runner-cpu"
62 class="field settings-number"
63 r#type="number"
64 min="0.1"
65 step="0.1"
66 value=st.field(|d| format!("{:.1}", d.max_cpu_cores))
67 oninput=move |v: String| {
68 if let Ok(v) = v.parse::<f64>() {
69 st.edit(|d| d.max_cpu_cores = v);
70 }
71 }
72 />
73 <span class="settings-unit">"核"</span>
74 </div>
75 </SettingRow>
76 <SettingRow label="内存" html_for="runner-mem">
77 <NumberInput
78 id="runner-mem"
79 value=st.field(|d| i64::from(d.max_memory_mb))
80 min=16
81 max=65_536
82 step=64
83 unit="MB"
84 onchange=move |v: i64| st.edit(|d| d.max_memory_mb = v as u32)
85 />
86 </SettingRow>
87 <SettingRow label="执行超时" html_for="runner-timeout">
88 <NumberInput
89 id="runner-timeout"
90 value=st.field(|d| i64::from(d.max_timeout_secs))
91 min=1
92 max=600
93 unit="秒"
94 onchange=move |v: i64| st.edit(|d| d.max_timeout_secs = v as u32)
95 />
96 </SettingRow>
97 <SettingRow label="排队超时" html_for="runner-queue">
98 <NumberInput
99 id="runner-queue"
100 value=st.field(|d| i64::from(d.queue_timeout_secs))
101 min=1
102 max=600
103 unit="秒"
104 onchange=move |v: i64| st.edit(|d| d.queue_timeout_secs = v as u32)
105 />
106 </SettingRow>
107 <SettingRow label="输出上限" html_for="runner-output">
108 <NumberInput
109 id="runner-output"
110 value=st.field(|d| (d.max_output_bytes / 1024) as i64)
111 min=1
112 max=65_536
113 unit="KB"
114 onchange=move |v: i64| st.edit(|d| d.max_output_bytes = v as u64 * 1024)
115 />
116 </SettingRow>
117 <SettingRow label="源码上限" html_for="runner-source">
118 <NumberInput
119 id="runner-source"
120 value=st.field(|d| (d.max_source_bytes / 1024) as i64)
121 min=1
122 max=65_536
123 unit="KB"
124 onchange=move |v: i64| st.edit(|d| d.max_source_bytes = v as u64 * 1024)
125 />
126 </SettingRow>
127 <SettingRow label="任务记录保留" html_for="runner-ttl">
128 <NumberInput
129 id="runner-ttl"
130 value=st.field(|d| i64::from(d.task_ttl_secs))
131 min=10
132 max=86_400
133 step=60
134 unit="秒"
135 hint="运行结束后保留输出供页面读取的时长。"
136 onchange=move |v: i64| st.edit(|d| d.task_ttl_secs = v as u32)
137 />
138 </SettingRow>
139 <SettingRow label="语言白名单" html_for="runner-langs" hint="逗号分隔,留空表示全部注册语言可用。">
140 <FormInput
141 id="runner-langs"
142 class="field settings-mono"
143 placeholder="python, node, rust"
144 value=st.field(|d| d.languages.clone().unwrap_or_default())
145 oninput=move |v: String| st.edit(|d| d.languages = (!v.trim().is_empty()).then_some(v))
146 />
147 </SettingRow>
148 </SettingsCard>
149 }
150}