-
-
Notifications
You must be signed in to change notification settings - Fork 114
Expand file tree
/
Copy pathmanager.rs
More file actions
131 lines (110 loc) · 4.8 KB
/
manager.rs
File metadata and controls
131 lines (110 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use anyhow::Result;
use pyo3::prelude::*;
use std::sync::mpsc;
use std::thread;
use velopack::sources::AutoSource;
use velopack::{UpdateCheck, UpdateInfo, UpdateManager as VelopackUpdateManagerRust, VelopackAsset};
use crate::{types::*, PyUpdateInfoOrAsset};
#[pyclass(name = "UpdateManager")]
pub struct UpdateManagerWrapper {
inner: VelopackUpdateManagerRust,
}
#[pymethods]
impl UpdateManagerWrapper {
#[new]
#[pyo3(signature = (source, options = None, locator = None))]
pub fn new(source: String, options: Option<PyUpdateOptions>, locator: Option<PyVelopackLocatorConfig>) -> Result<Self> {
let source = AutoSource::new(&source);
let inner = VelopackUpdateManagerRust::new(source, options.map(Into::into), locator.map(Into::into))?;
Ok(UpdateManagerWrapper { inner })
}
pub fn get_current_version(&self) -> String {
self.inner.get_current_version_as_string()
}
pub fn get_app_id(&self) -> String {
self.inner.get_app_id().to_string()
}
pub fn get_is_portable(&self) -> bool {
self.inner.get_is_portable()
}
pub fn get_update_pending_restart(&self) -> Option<PyVelopackAsset> {
let pending = self.inner.get_update_pending_restart();
pending.map(Into::into)
}
pub fn check_for_updates(&mut self, py: Python) -> Result<Option<PyUpdateInfo>> {
// Release GIL during network operation
let update_check = py.detach(|| self.inner.check_for_updates())?;
match update_check {
UpdateCheck::UpdateAvailable(updates) => {
let py_updates = PyUpdateInfo::from(updates);
Ok(Some(py_updates))
}
UpdateCheck::NoUpdateAvailable => Ok(None),
UpdateCheck::RemoteIsEmpty => Ok(None),
}
}
#[pyo3(signature = (update_info, progress_callback = None))]
pub fn download_updates(&mut self, py: Python, update_info: PyUpdateInfo, progress_callback: Option<Py<PyAny>>) -> Result<()> {
// Convert PyUpdateInfo back to rust UpdateInfo
let rust_update_info: UpdateInfo = update_info.into();
if let Some(callback) = progress_callback {
// Create a channel for progress updates
let (sender, receiver) = mpsc::channel::<i16>();
// Clone the callback for the thread
let callback_clone = callback.clone_ref(py);
// Release the GIL before starting the download
py.detach(|| {
// Spawn a thread to handle progress updates
let progress_thread = thread::spawn(move || {
while let Ok(progress) = receiver.recv() {
// Acquire GIL only when needed to call the callback
Python::try_attach(|py| {
if let Err(e) = callback_clone.call1(py, (progress,)) {
// Log error but continue - don't break the download
eprintln!("Progress callback error: {}", e);
}
});
}
});
// Call download with the sender
let result = self.inner.download_updates(&rust_update_info, Some(sender));
// Wait for the progress thread to finish
let _ = progress_thread.join();
result
})?;
Ok(())
} else {
// No progress callback provided - still release GIL for the download
py.detach(|| self.inner.download_updates(&rust_update_info, None))?;
Ok(())
}
}
pub fn apply_updates_and_restart(&mut self, update: PyUpdateInfoOrAsset) -> Result<()> {
let asset: VelopackAsset = update.into_asset();
self.inner.apply_updates_and_restart(&asset)?;
Ok(())
}
pub fn apply_updates_and_restart_with_args(&mut self, update: PyUpdateInfoOrAsset, restart_args: Vec<String>) -> Result<()> {
let asset: VelopackAsset = update.into_asset();
self.inner.apply_updates_and_restart_with_args(&asset, restart_args)?;
Ok(())
}
pub fn apply_updates_and_exit(&mut self, update: PyUpdateInfoOrAsset) -> Result<()> {
let asset: VelopackAsset = update.into_asset();
self.inner.apply_updates_and_exit(&asset)?;
Ok(())
}
#[pyo3(signature = (update, silent = false, restart = true, restart_args = None))]
pub fn wait_exit_then_apply_updates(
&mut self,
update: PyUpdateInfoOrAsset,
silent: bool,
restart: bool,
restart_args: Option<Vec<String>>,
) -> Result<()> {
let asset: VelopackAsset = update.into_asset();
let args = restart_args.unwrap_or_default();
self.inner.wait_exit_then_apply_updates(&asset, silent, restart, args)?;
Ok(())
}
}