transmission_gobject/
session.rs

1use std::cell::{Cell, OnceCell, RefCell};
2
3use async_compat::CompatExt;
4use gio::prelude::FileExt;
5use glib::object::ObjectExt;
6use glib::subclass::prelude::{ObjectSubclass, *};
7use glib::{Properties, clone};
8use transmission_client::{Session, SessionMutator};
9
10use crate::{TrClient, TrEncryption};
11
12mod imp {
13    use super::*;
14
15    #[derive(Debug, Default, Properties)]
16    #[properties(wrapper_type = super::TrSession)]
17    pub struct TrSession {
18        #[property(get, set, construct_only)]
19        pub client: OnceCell<TrClient>,
20
21        #[property(get)]
22        pub version: RefCell<String>,
23        #[property(get, set = Self::set_download_dir)]
24        pub download_dir: RefCell<Option<gio::File>>,
25        #[property(get, set = Self::set_start_added_torrents)]
26        pub start_added_torrents: Cell<bool>,
27        #[property(get, set = Self::set_encryption, builder(Default::default()))]
28        pub encryption: Cell<TrEncryption>,
29        #[property(get, set = Self::set_incomplete_dir_enabled)]
30        pub incomplete_dir_enabled: Cell<bool>,
31        #[property(get, set = Self::set_incomplete_dir)]
32        pub incomplete_dir: RefCell<Option<gio::File>>,
33        #[property(get, set = Self::set_download_queue_enabled)]
34        pub download_queue_enabled: Cell<bool>,
35        #[property(get, set = Self::set_download_queue_size, minimum = 1, default_value = 1)]
36        pub download_queue_size: Cell<i32>,
37        #[property(get, set = Self::set_seed_queue_enabled)]
38        pub seed_queue_enabled: Cell<bool>,
39        #[property(get, set = Self::set_seed_queue_size, minimum = 1, default_value = 1)]
40        pub seed_queue_size: Cell<i32>,
41        #[property(get, set = Self::set_port_forwarding_enabled)]
42        pub port_forwarding_enabled: Cell<bool>,
43        #[property(get, set = Self::set_peer_port_random_on_start)]
44        pub peer_port_random_on_start: Cell<bool>,
45        #[property(get, set = Self::set_peer_port, minimum = 1, default_value = 1)]
46        pub peer_port: Cell<i32>,
47        #[property(get, set = Self::set_peer_limit_global, minimum = 1, default_value = 1)]
48        pub peer_limit_global: Cell<i32>,
49        #[property(get, set = Self::set_peer_limit_per_torrent, minimum = 1, default_value = 1)]
50        pub peer_limit_per_torrent: Cell<i32>,
51    }
52
53    #[glib::object_subclass]
54    impl ObjectSubclass for TrSession {
55        const NAME: &'static str = "TrSession";
56        type ParentType = glib::Object;
57        type Type = super::TrSession;
58    }
59
60    #[glib::derived_properties]
61    impl ObjectImpl for TrSession {}
62
63    impl TrSession {
64        pub fn set_download_dir(&self, value: gio::File) {
65            *self.download_dir.borrow_mut() = Some(value.clone());
66
67            let mutator = SessionMutator {
68                download_dir: Some(value.path().unwrap()),
69                ..Default::default()
70            };
71            self.mutate_session(mutator, "download_dir");
72        }
73
74        pub fn set_start_added_torrents(&self, value: bool) {
75            self.start_added_torrents.set(value);
76
77            let mutator = SessionMutator {
78                start_added_torrents: Some(value),
79                ..Default::default()
80            };
81            self.mutate_session(mutator, "start-added-torrents");
82        }
83
84        pub fn set_encryption(&self, value: TrEncryption) {
85            self.encryption.set(value);
86
87            let mutator = SessionMutator {
88                encryption: Some(value.into()),
89                ..Default::default()
90            };
91            self.mutate_session(mutator, "encryption");
92        }
93
94        pub fn set_incomplete_dir_enabled(&self, value: bool) {
95            self.incomplete_dir_enabled.set(value);
96
97            let mutator = SessionMutator {
98                incomplete_dir_enabled: Some(value),
99                ..Default::default()
100            };
101            self.mutate_session(mutator, "incomplete-dir-enabled");
102        }
103
104        pub fn set_incomplete_dir(&self, value: gio::File) {
105            *self.incomplete_dir.borrow_mut() = Some(value.clone());
106
107            let mutator = SessionMutator {
108                incomplete_dir: Some(value.path().unwrap()),
109                ..Default::default()
110            };
111            self.mutate_session(mutator, "incomplete-dir");
112        }
113
114        pub fn set_download_queue_enabled(&self, value: bool) {
115            self.download_queue_enabled.set(value);
116
117            let mutator = SessionMutator {
118                download_queue_enabled: Some(value),
119                ..Default::default()
120            };
121            self.mutate_session(mutator, "download-queue-enabled");
122        }
123
124        pub fn set_download_queue_size(&self, value: i32) {
125            self.download_queue_size.set(value);
126
127            let mutator = SessionMutator {
128                download_queue_size: Some(value),
129                ..Default::default()
130            };
131            self.mutate_session(mutator, "download-queue-size");
132        }
133
134        pub fn set_seed_queue_enabled(&self, value: bool) {
135            self.seed_queue_enabled.set(value);
136
137            let mutator = SessionMutator {
138                seed_queue_enabled: Some(value),
139                ..Default::default()
140            };
141            self.mutate_session(mutator, "seed-queue-enabled");
142        }
143
144        pub fn set_seed_queue_size(&self, value: i32) {
145            self.seed_queue_size.set(value);
146
147            let mutator = SessionMutator {
148                seed_queue_size: Some(value),
149                ..Default::default()
150            };
151            self.mutate_session(mutator, "seed-queue-size");
152        }
153
154        pub fn set_port_forwarding_enabled(&self, value: bool) {
155            self.port_forwarding_enabled.set(value);
156
157            let mutator = SessionMutator {
158                port_forwarding_enabled: Some(value),
159                ..Default::default()
160            };
161            self.mutate_session(mutator, "port-forwarding-enabled");
162        }
163
164        pub fn set_peer_port_random_on_start(&self, value: bool) {
165            self.peer_port_random_on_start.set(value);
166
167            let mutator = SessionMutator {
168                peer_port_random_on_start: Some(value),
169                ..Default::default()
170            };
171            self.mutate_session(mutator, "peer-port-random-on-start");
172        }
173
174        pub fn set_peer_port(&self, value: i32) {
175            self.peer_port.set(value);
176
177            let mutator = SessionMutator {
178                peer_port: Some(value),
179                ..Default::default()
180            };
181            self.mutate_session(mutator, "peer-port");
182        }
183
184        pub fn set_peer_limit_global(&self, value: i32) {
185            self.peer_limit_global.set(value);
186
187            let mutator = SessionMutator {
188                peer_limit_global: Some(value),
189                ..Default::default()
190            };
191            self.mutate_session(mutator, "peer-limit-global");
192        }
193
194        pub fn set_peer_limit_per_torrent(&self, value: i32) {
195            self.peer_limit_per_torrent.set(value);
196
197            let mutator = SessionMutator {
198                peer_limit_per_torrent: Some(value),
199                ..Default::default()
200            };
201            self.mutate_session(mutator, "peer-limit-per-torrent");
202        }
203
204        fn mutate_session(&self, mutator: SessionMutator, prop_name: &str) {
205            self.obj().notify(prop_name);
206
207            let fut = clone!(
208                #[weak(rename_to = this)]
209                self,
210                async move {
211                    if let Some(rpc_client) = this.client.get().unwrap().rpc_client() {
212                        rpc_client.session_set(mutator).compat().await.unwrap();
213                    } else {
214                        warn!("Unable set mutate session, no rpc connection.");
215                    }
216                }
217            );
218            glib::spawn_future_local(fut);
219        }
220    }
221}
222
223glib::wrapper! {
224    pub struct TrSession(ObjectSubclass<imp::TrSession>);
225}
226
227impl TrSession {
228    pub(crate) fn new(client: &TrClient) -> Self {
229        glib::Object::builder().property("client", client).build()
230    }
231
232    pub(crate) fn refresh_values(&self, rpc_session: Session) {
233        let imp = self.imp();
234
235        // version
236        if *imp.version.borrow() != rpc_session.version {
237            *imp.version.borrow_mut() = rpc_session.version;
238            self.notify_version();
239        }
240
241        // download_dir
242        let download_dir = gio::File::for_path(rpc_session.download_dir);
243        if download_dir.path() != imp.download_dir.borrow().as_ref().and_then(|f| f.path()) {
244            *imp.download_dir.borrow_mut() = Some(download_dir);
245            self.notify_download_dir();
246        }
247
248        // start_added_torrents
249        if imp.start_added_torrents.get() != rpc_session.start_added_torrents {
250            imp.start_added_torrents
251                .set(rpc_session.start_added_torrents);
252            self.notify_start_added_torrents();
253        }
254
255        // encryption
256        if imp.encryption.get() != rpc_session.encryption.clone().into() {
257            imp.encryption.set(rpc_session.encryption.into());
258            self.notify_encryption();
259        }
260
261        // incomplete_dir_enabled
262        if imp.incomplete_dir_enabled.get() != rpc_session.incomplete_dir_enabled {
263            imp.incomplete_dir_enabled
264                .set(rpc_session.incomplete_dir_enabled);
265            self.notify_incomplete_dir_enabled();
266        }
267
268        // incomplete_dir
269        let incomplete_dir = gio::File::for_path(rpc_session.incomplete_dir);
270        if incomplete_dir.path() != imp.incomplete_dir.borrow().as_ref().and_then(|f| f.path()) {
271            *imp.incomplete_dir.borrow_mut() = Some(incomplete_dir);
272            self.notify_incomplete_dir();
273        }
274
275        // download_queue_enabled
276        if imp.download_queue_enabled.get() != rpc_session.download_queue_enabled {
277            imp.download_queue_enabled
278                .set(rpc_session.download_queue_enabled);
279            self.notify_download_queue_enabled();
280        }
281
282        // download_queue_size
283        if imp.download_queue_size.get() != rpc_session.download_queue_size {
284            imp.download_queue_size.set(rpc_session.download_queue_size);
285            self.notify_download_queue_size();
286        }
287
288        // seed_queue_enabled
289        if imp.seed_queue_enabled.get() != rpc_session.seed_queue_enabled {
290            imp.seed_queue_enabled.set(rpc_session.seed_queue_enabled);
291            self.notify_seed_queue_enabled();
292        }
293
294        // seed_queue_size
295        if imp.seed_queue_size.get() != rpc_session.seed_queue_size {
296            imp.seed_queue_size.set(rpc_session.seed_queue_size);
297            self.notify_seed_queue_size();
298        }
299
300        // port_forwarding_enabled
301        if imp.port_forwarding_enabled.get() != rpc_session.port_forwarding_enabled {
302            imp.port_forwarding_enabled
303                .set(rpc_session.port_forwarding_enabled);
304            self.notify_port_forwarding_enabled();
305        }
306
307        // peer_port_random_on_start
308        if imp.peer_port_random_on_start.get() != rpc_session.peer_port_random_on_start {
309            imp.peer_port_random_on_start
310                .set(rpc_session.peer_port_random_on_start);
311            self.notify_peer_port_random_on_start();
312        }
313
314        // peer_port
315        if imp.peer_port.get() != rpc_session.peer_port {
316            imp.peer_port.set(rpc_session.peer_port);
317            self.notify_peer_port();
318        }
319
320        // peer_limit_global
321        if imp.peer_limit_global.get() != rpc_session.peer_limit_global {
322            imp.peer_limit_global.set(rpc_session.peer_limit_global);
323            self.notify_peer_limit_global();
324        }
325
326        // peer_limit_per_torrent
327        if imp.peer_limit_per_torrent.get() != rpc_session.peer_limit_per_torrent {
328            imp.peer_limit_per_torrent
329                .set(rpc_session.peer_limit_per_torrent);
330            self.notify_peer_limit_per_torrent();
331        }
332    }
333}