1use std::io::{Cursor, Seek, SeekFrom, Write};
4use std::marker::PhantomData;
5use std::os::fd::OwnedFd;
6use std::os::unix::net::UnixStream;
7use std::sync::{Arc, Mutex};
8
9use futures_util::FutureExt;
10use glycin_common::{BinaryData, Operations};
11use serde::{Deserialize, Serialize};
12use zbus::zvariant::{DeserializeDict, OwnedObjectPath, SerializeDict, Type};
13
14use crate::dbus_types::{self, *};
15use crate::error::*;
16
17#[derive(DeserializeDict, SerializeDict, Type, Debug)]
18#[zvariant(signature = "dict")]
19#[non_exhaustive]
20pub struct EditRequest {
21 pub operations: BinaryData,
22}
23
24impl EditRequest {
25 pub fn for_operations(operations: &Operations) -> Result<Self, RemoteError> {
26 let operations = operations
27 .to_message_pack()
28 .expected_error()
29 .map_err(|x| x.into_editor_error())?;
30 let operations = BinaryData::from_data(operations)
31 .expected_error()
32 .map_err(|x| x.into_editor_error())?;
33 Ok(Self { operations })
34 }
35
36 pub fn operations(&self) -> Result<Operations, RemoteError> {
37 let binary_data = self
38 .operations
39 .get()
40 .expected_error()
41 .map_err(|x| x.into_editor_error())?;
42
43 let operations = Operations::from_slice(&binary_data)
44 .expected_error()
45 .map_err(|x| x.into_editor_error())?;
46
47 Ok(operations)
48 }
49}
50
51#[derive(DeserializeDict, SerializeDict, Type, Debug, Clone)]
56#[zvariant(signature = "dict")]
57#[non_exhaustive]
58pub struct SparseEditorOutput {
59 pub byte_changes: Option<ByteChanges>,
60 pub data: Option<BinaryData>,
61 pub info: EditorOutputInfo,
62}
63
64impl SparseEditorOutput {
65 pub fn byte_changes(byte_changes: ByteChanges) -> Self {
66 SparseEditorOutput {
67 byte_changes: Some(byte_changes),
68 data: None,
69 info: EditorOutputInfo { lossless: true },
70 }
71 }
72}
73
74impl From<CompleteEditorOutput> for SparseEditorOutput {
75 fn from(value: CompleteEditorOutput) -> Self {
76 Self {
77 byte_changes: None,
78 data: Some(value.data),
79 info: value.info,
80 }
81 }
82}
83
84#[derive(DeserializeDict, SerializeDict, Type, Debug, Clone)]
85#[zvariant(signature = "dict")]
86#[non_exhaustive]
87pub struct ByteChanges {
88 pub changes: Vec<ByteChange>,
89}
90
91#[derive(Deserialize, Serialize, Type, Debug, Clone)]
92pub struct ByteChange {
93 pub offset: u64,
94 pub new_value: u8,
95}
96
97impl ByteChanges {
98 pub fn from_slice(changes: &[(u64, u8)]) -> Self {
99 ByteChanges {
100 changes: changes
101 .iter()
102 .map(|(offset, new_value)| ByteChange {
103 offset: *offset,
104 new_value: *new_value,
105 })
106 .collect(),
107 }
108 }
109
110 pub fn apply(&self, data: &mut [u8]) {
111 let mut cur = Cursor::new(data);
112 for change in self.changes.iter() {
113 cur.seek(SeekFrom::Start(change.offset)).unwrap();
114 cur.write_all(&[change.new_value]).unwrap();
115 }
116 }
117}
118
119#[derive(DeserializeDict, SerializeDict, Type, Debug, Clone)]
120#[zvariant(signature = "dict")]
121#[non_exhaustive]
122pub struct CompleteEditorOutput {
123 pub data: BinaryData,
124 pub info: EditorOutputInfo,
125}
126
127impl CompleteEditorOutput {
128 pub fn new(data: BinaryData) -> Self {
129 Self {
130 data,
131 info: Default::default(),
132 }
133 }
134
135 pub fn new_lossless(data: Vec<u8>) -> Result<Self, ProcessError> {
136 let data = BinaryData::from_data(data).expected_error()?;
137 let info = EditorOutputInfo { lossless: true };
138 Ok(Self { data, info })
139 }
140}
141
142#[derive(DeserializeDict, SerializeDict, Type, Debug, Default, Clone)]
143#[zvariant(signature = "dict")]
144#[non_exhaustive]
145pub struct EditorOutputInfo {
146 pub lossless: bool,
151}
152
153pub struct Editor<E: EditorImplementation> {
154 pub editor: PhantomData<E>,
155 pub image_id: Mutex<u64>,
156}
157
158#[zbus::interface(name = "org.gnome.glycin.Editor")]
160impl<E: EditorImplementation> Editor<E> {
161 async fn create(
162 &self,
163 mime_type: String,
164 new_image: NewImage,
165 encoding_options: EncodingOptions,
166 ) -> Result<EncodedImage, RemoteError> {
167 E::create(mime_type, new_image, encoding_options).map_err(|x| x.into_editor_error())
168 }
169
170 async fn edit(
171 &self,
172 init_request: InitRequest,
173 #[zbus(connection)] dbus_connection: &zbus::Connection,
174 ) -> Result<dbus_types::RemoteEditableImage, RemoteError> {
175 let fd = OwnedFd::from(init_request.fd);
176 let stream = UnixStream::from(fd);
177
178 let editor_state = E::edit(stream, init_request.mime_type, init_request.details)
179 .map_err(|x| x.into_loader_error())?;
180
181 let image_id = {
182 let lock = self.image_id.lock();
183 let mut image_id = match lock {
184 Ok(id) => id,
185 Err(err) => return Err(RemoteError::InternalLoaderError(err.to_string())),
186 };
187 let id = *image_id;
188 *image_id = id + 1;
189 id
190 };
191
192 let path =
193 OwnedObjectPath::try_from(format!("/org/gnome/glycin/editable_image/{image_id}"))
194 .internal_error()
195 .map_err(|x| x.into_loader_error())?;
196
197 let dbus_image = dbus_types::RemoteEditableImage::new(path.clone());
198
199 dbus_connection
200 .object_server()
201 .at(
202 &path,
203 EditableImage {
204 editor_implementation: Arc::new(Box::new(editor_state)),
205 path: path.clone(),
206 dropped: Default::default(),
207 },
208 )
209 .await
210 .internal_error()
211 .map_err(|x| x.into_loader_error())?;
212
213 Ok(dbus_image)
214 }
215}
216
217pub struct EditableImage<E: EditorImplementation> {
218 pub editor_implementation: Arc<Box<E>>,
219 pub path: OwnedObjectPath,
220 dropped: async_lock::OnceCell<()>,
221}
222
223#[zbus::interface(name = "org.gnome.glycin.EditableImage")]
224impl<E: EditorImplementation> EditableImage<E> {
225 async fn apply_sparse(
226 &self,
227 edit_request: EditRequest,
228 ) -> Result<SparseEditorOutput, RemoteError> {
229 let operations = edit_request.operations()?;
230
231 let editor_implementation = self.editor_implementation.clone();
232 let mut editor_output = blocking::unblock(move || {
233 editor_implementation
234 .apply_sparse(operations)
235 .map_err(|x| x.into_loader_error())
236 })
237 .fuse();
238
239 futures_util::select! {
240 result = editor_output => result,
241 _ = self.dropped.wait().fuse() => Err(RemoteError::Aborted),
242 }
243 }
244
245 async fn apply_complete(
247 &self,
248 edit_request: EditRequest,
249 ) -> Result<CompleteEditorOutput, RemoteError> {
250 let operations = edit_request.operations()?;
251
252 let editor_implementation = self.editor_implementation.clone();
253 let mut editor_output = blocking::unblock(move || {
254 editor_implementation
255 .apply_complete(operations)
256 .map_err(|x| x.into_loader_error())
257 })
258 .fuse();
259
260 futures_util::select! {
261 result = editor_output => result,
262 _ = self.dropped.wait().fuse() => Err(RemoteError::Aborted),
263 }
264 }
265
266 async fn done(
267 &self,
268 #[zbus(object_server)] object_server: &zbus::ObjectServer,
269 ) -> Result<(), RemoteError> {
270 log::debug!("Disconnecting {}", self.path);
271 let removed = object_server
272 .remove::<EditableImage<E>, _>(&self.path)
273 .await?;
274 if removed {
275 log::debug!("Removed {}", self.path);
276 } else {
277 log::error!("Failed to remove {}", self.path);
278 }
279 let _ = self.dropped.set(()).await;
280 Ok(())
281 }
282}
283
284pub trait EditorImplementation: Send + Sync + Sized + 'static {
286 const USEABLE: bool = true;
287
288 fn edit(
289 stream: UnixStream,
290 mime_type: String,
291 details: InitializationDetails,
292 ) -> Result<Self, ProcessError>;
293
294 fn create(
295 mime_type: String,
296 new_image: NewImage,
297 encoding_options: EncodingOptions,
298 ) -> Result<EncodedImage, ProcessError>;
299
300 fn apply_sparse(&self, operations: Operations) -> Result<SparseEditorOutput, ProcessError> {
301 let complete = Self::apply_complete(self, operations)?;
302
303 Ok(SparseEditorOutput::from(complete))
304 }
305
306 fn apply_complete(&self, operations: Operations) -> Result<CompleteEditorOutput, ProcessError>;
307}
308
309pub enum VoidEditorImplementation {}
311
312impl EditorImplementation for VoidEditorImplementation {
313 const USEABLE: bool = false;
314
315 fn edit(
316 _stream: UnixStream,
317 _mime_type: String,
318 _details: InitializationDetails,
319 ) -> Result<Self, ProcessError> {
320 unreachable!()
321 }
322
323 fn create(
324 _mime_type: String,
325 _new_image: NewImage,
326 _encoding_options: EncodingOptions,
327 ) -> Result<EncodedImage, ProcessError> {
328 unreachable!()
329 }
330
331 fn apply_complete(
332 &self,
333 _operations: Operations,
334 ) -> Result<CompleteEditorOutput, ProcessError> {
335 unreachable!()
336 }
337}