auto_update_helper.rs

 1#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
 2
 3#[cfg(target_os = "windows")]
 4mod dialog;
 5#[cfg(target_os = "windows")]
 6mod updater;
 7
 8#[cfg(target_os = "windows")]
 9fn main() {
10    if let Err(e) = windows_impl::run() {
11        log::error!("Error: Zed update failed, {:?}", e);
12        windows_impl::show_error(format!("Error: {:?}", e));
13    }
14}
15
16#[cfg(not(target_os = "windows"))]
17fn main() {}
18
19#[cfg(target_os = "windows")]
20mod windows_impl {
21    use std::path::Path;
22
23    use super::dialog::create_dialog_window;
24    use super::updater::perform_update;
25    use anyhow::{Context as _, Result};
26    use windows::{
27        Win32::{
28            Foundation::{HWND, LPARAM, WPARAM},
29            UI::WindowsAndMessaging::{
30                DispatchMessageW, GetMessageW, MB_ICONERROR, MB_SYSTEMMODAL, MSG, MessageBoxW,
31                PostMessageW, WM_USER,
32            },
33        },
34        core::HSTRING,
35    };
36
37    pub(crate) const WM_JOB_UPDATED: u32 = WM_USER + 1;
38    pub(crate) const WM_TERMINATE: u32 = WM_USER + 2;
39
40    pub(crate) fn run() -> Result<()> {
41        let helper_dir = std::env::current_exe()?
42            .parent()
43            .context("No parent directory")?
44            .to_path_buf();
45        init_log(&helper_dir)?;
46        let app_dir = helper_dir
47            .parent()
48            .context("No parent directory")?
49            .to_path_buf();
50
51        log::info!("======= Starting Zed update =======");
52        let (tx, rx) = std::sync::mpsc::channel();
53        let hwnd = create_dialog_window(rx)?.0 as isize;
54        std::thread::spawn(move || {
55            let result = perform_update(app_dir.as_path(), Some(hwnd));
56            tx.send(result).ok();
57            unsafe { PostMessageW(Some(HWND(hwnd as _)), WM_TERMINATE, WPARAM(0), LPARAM(0)) }.ok();
58        });
59        unsafe {
60            let mut message = MSG::default();
61            while GetMessageW(&mut message, None, 0, 0).as_bool() {
62                DispatchMessageW(&message);
63            }
64        }
65        Ok(())
66    }
67
68    fn init_log(helper_dir: &Path) -> Result<()> {
69        simplelog::WriteLogger::init(
70            simplelog::LevelFilter::Info,
71            simplelog::Config::default(),
72            std::fs::File::options()
73                .append(true)
74                .create(true)
75                .open(helper_dir.join("auto_update_helper.log"))?,
76        )?;
77        Ok(())
78    }
79
80    pub(crate) fn show_error(mut content: String) {
81        if content.len() > 600 {
82            content.truncate(600);
83            content.push_str("...\n");
84        }
85        let _ = unsafe {
86            MessageBoxW(
87                None,
88                &HSTRING::from(content),
89                windows::core::w!("Error: Zed update failed."),
90                MB_ICONERROR | MB_SYSTEMMODAL,
91            )
92        };
93    }
94}