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