1use crate::common::{AutoNeverAlways, OnOff, OnOffDefaultOff, OnOffDefaultOn};
2use crate::to_command::ToArg;
3use crate::to_command::ToCommand;
4use bon::Builder;
5use std::path::PathBuf;
6
7pub enum Channel {
8 Main,
9 Display,
10 Cursor,
11 Inputs,
12 Record,
13 Playback,
14}
15
16impl ToArg for Channel {
17 fn to_arg(&self) -> &str {
18 match self {
19 Channel::Main => "main",
20 Channel::Display => "display",
21 Channel::Cursor => "cursor",
22 Channel::Inputs => "inputs",
23 Channel::Record => "record",
24 Channel::Playback => "playback",
25 }
26 }
27}
28#[derive(Default)]
29pub enum ImageCompression {
30 AutoGlz,
31 #[default]
32 AutoLz,
33 Quic,
34 Glz,
35 Lz,
36 Off,
37}
38
39impl ToArg for ImageCompression {
40 fn to_arg(&self) -> &str {
41 match self {
42 ImageCompression::AutoGlz => "auto_glz",
43 ImageCompression::AutoLz => "auto_lz",
44 ImageCompression::Quic => "quic",
45 ImageCompression::Glz => "glz",
46 ImageCompression::Lz => "lz",
47 ImageCompression::Off => "off",
48 }
49 }
50}
51#[derive(Default)]
52pub enum OffAllFilter {
53 #[default]
54 Off,
55 All,
56 Filter,
57}
58
59impl ToArg for OffAllFilter {
60 fn to_arg(&self) -> &str {
61 match self {
62 OffAllFilter::Off => "off",
63 OffAllFilter::All => "all",
64 OffAllFilter::Filter => "filter",
65 }
66 }
67}
68#[derive(Default, Builder)]
70pub struct Spice {
71 port: Option<u16>,
73
74 addr: Option<String>,
76
77 ipv4: Option<OnOff>,
79 ipv6: Option<OnOff>,
80 unix: Option<OnOff>,
81
82 password_secret: Option<String>,
85
86 sasl: Option<OnOff>,
99
100 disable_ticketing: Option<OnOff>,
102
103 disable_copy_paste: Option<OnOff>,
105
106 disable_agent_file_xfer: Option<OnOff>,
109
110 tls_port: Option<u16>,
112
113 x509_dir: Option<PathBuf>,
116
117 x509_key_file: Option<PathBuf>,
119 x509_key_password: Option<PathBuf>,
120 x509_cert_file: Option<PathBuf>,
121 x509_cacert_file: Option<PathBuf>,
122 x509_dh_key_file: Option<PathBuf>,
123
124 tls_ciphers: Option<String>,
126
127 tls_channel: Option<Channel>,
134 plaintext_channel: Option<Channel>,
135
136 image_compression: Option<ImageCompression>,
138
139 jpeg_wan_compression: Option<AutoNeverAlways>,
142 zlib_glz_wan_compression: Option<AutoNeverAlways>,
143
144 streaming_video: Option<OffAllFilter>,
146
147 agent_mouse: Option<OnOffDefaultOn>,
149
150 playback_compression: Option<OnOffDefaultOn>,
153
154 seamless_migration: Option<OnOffDefaultOff>,
156
157 gl: Option<OnOffDefaultOn>,
159
160 rendernode: Option<PathBuf>,
163}
164
165impl ToCommand for Spice {
166 fn to_command(&self) -> Vec<String> {
167 let mut cmd = vec![];
168
169 cmd.push("-spice".to_string());
170
171 let mut args = vec![];
172 if let Some(port) = &self.port {
173 args.push(format!("port={}", port));
174 }
175 if let Some(addr) = &self.addr {
176 args.push(format!("addr={}", addr));
177 }
178 if let Some(ipv4) = &self.ipv4 {
179 args.push(format!("ipv4={}", ipv4.to_arg()));
180 }
181 if let Some(ipv6) = &self.ipv6 {
182 args.push(format!("ipv6={}", ipv6.to_arg()));
183 }
184 if let Some(unix) = &self.unix {
185 args.push(format!("unix={}", unix.to_arg()));
186 }
187 if let Some(password_secret) = &self.password_secret {
188 args.push(format!("password-secret={}", password_secret));
189 }
190 if let Some(sasl) = &self.sasl {
191 args.push(format!("sasl={}", sasl.to_arg()));
192 }
193 if let Some(disable_ticketing) = &self.disable_ticketing {
194 args.push(format!("disable-ticketing={}", disable_ticketing.to_arg()));
195 }
196 if let Some(disable_copy_paste) = &self.disable_copy_paste {
197 args.push(format!(
198 "disable-copy-paste={}",
199 disable_copy_paste.to_arg()
200 ));
201 }
202 if let Some(disable_agent_file_xfer) = &self.disable_agent_file_xfer {
203 args.push(format!(
204 "disable-agent-file-xfer={}",
205 disable_agent_file_xfer.to_arg()
206 ));
207 }
208 if let Some(tls_port) = &self.tls_port {
209 args.push(format!("tls-port={}", tls_port));
210 }
211 if let Some(x509_dir) = &self.x509_dir {
212 args.push(format!("x509-dir={}", x509_dir.display()));
213 }
214 if let Some(x509_key_file) = &self.x509_key_file {
215 args.push(format!("x509-key-file={}", x509_key_file.display()));
216 }
217 if let Some(x509_key_password) = &self.x509_key_password {
218 args.push(format!("x509-key-password={}", x509_key_password.display()));
219 }
220 if let Some(x509_cert_file) = &self.x509_cert_file {
221 args.push(format!("x509-cert-file={}", x509_cert_file.display()));
222 }
223 if let Some(x509_cacert_file) = &self.x509_cacert_file {
224 args.push(format!("x509-caert-file={}", x509_cacert_file.display()));
225 }
226 if let Some(x509_dh_key_file) = &self.x509_dh_key_file {
227 args.push(format!("x509-dh-key-file={}", x509_dh_key_file.display()));
228 }
229 if let Some(tls_ciphers) = &self.tls_ciphers {
230 args.push(format!("tls-ciphers={}", tls_ciphers));
231 }
232 if let Some(tls_channel) = &self.tls_channel {
233 args.push(format!("tls-channel={}", tls_channel.to_arg()));
234 }
235 if let Some(plaintext_channel) = &self.plaintext_channel {
236 args.push(format!("plaintext-channel={}", plaintext_channel.to_arg()));
237 }
238 if let Some(image_compression) = &self.image_compression {
239 args.push(format!("image-compression={}", image_compression.to_arg()));
240 }
241 if let Some(jpeg_wan_compression) = &self.jpeg_wan_compression {
242 args.push(format!(
243 "jpeg-wan-compression={}",
244 jpeg_wan_compression.to_arg()
245 ));
246 }
247 if let Some(zlib_glz_wan_compression) = &self.zlib_glz_wan_compression {
248 args.push(format!(
249 "zlib-glz-wan-compression={}",
250 zlib_glz_wan_compression.to_arg()
251 ));
252 }
253 if let Some(streaming_video) = &self.streaming_video {
254 args.push(format!("streaming-video={}", streaming_video.to_arg()));
255 }
256 if let Some(agent_mouse) = &self.agent_mouse {
257 args.push(format!("agent-mouse={}", agent_mouse.to_arg()));
258 }
259 if let Some(playback_compression) = &self.playback_compression {
260 args.push(format!(
261 "playback-compression={}",
262 playback_compression.to_arg()
263 ));
264 }
265 if let Some(seamless_migration) = &self.seamless_migration {
266 args.push(format!(
267 "seamless-migration={}",
268 seamless_migration.to_arg()
269 ));
270 }
271 if let Some(gl) = &self.gl {
272 args.push(format!("gl={}", gl.to_arg()));
273 }
274 if let Some(rendernode) = &self.rendernode {
275 args.push(format!("rendernode={}", rendernode.display()));
276 }
277
278 cmd.push(args.join(","));
279
280 cmd
281 }
282}