From 28a390f167ab04432290b78d5d4963178d27df50 Mon Sep 17 00:00:00 2001 From: Nickolay Date: Mon, 10 Feb 2025 21:57:43 +0200 Subject: [PATCH] Fix builds on windows (#2864) * Fix builds on windows * Fix rust compile issues * Autoformat * Fix windows volumes compile again --------- Co-authored-by: Arnab Chakraborty <11457760+Rocky43007@users.noreply.github.com> --- .github/workflows/release.yml | 4 -- apps/desktop/src/commands.ts | 3 + core/Cargo.toml | 13 ++-- core/crates/cloud-services/src/client.rs | 1 - core/src/library/statistics.rs | 4 ++ core/src/volume/os.rs | 78 +++++++++++----------- core/src/volume/state.rs | 9 ++- core/src/volume/watcher.rs | 84 ++++++++++++++---------- 8 files changed, 112 insertions(+), 84 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 238554fb4..123a02c88 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -100,10 +100,6 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} - - name: Run pnpm prep - run: | - pnpm prep - - name: Build run: | pnpm tauri build --ci -v --target ${{ matrix.settings.target }} --bundles ${{ matrix.settings.bundles }} diff --git a/apps/desktop/src/commands.ts b/apps/desktop/src/commands.ts index 21e45b6bd..68606304f 100644 --- a/apps/desktop/src/commands.ts +++ b/apps/desktop/src/commands.ts @@ -74,6 +74,9 @@ export const commands = { else return { status: 'error', error: e as any }; } }, + /** + * Stops the cursor position tracking for drag operations + */ async stopDrag(): Promise { await TAURI_INVOKE('stop_drag'); }, diff --git a/core/Cargo.toml b/core/Cargo.toml index 0fa984d56..e39a0624a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -95,6 +95,7 @@ http-range = "0.1.5" hyper-util = { version = "0.1.9", features = ["tokio"] } int-enum = "0.5" # Update blocked due to API breaking changes mini-moka = "0.10.3" +once_cell = "1.19.0" serde-hashkey = "0.4.5" serde_repr = "0.1.19" serde_with = "3.8" @@ -104,7 +105,6 @@ tar = "0.4.41" tower-service = "0.3.2" tracing-appender = "0.2.3" whoami = "1.5.2" -once_cell = "1.19.0" [dependencies.tokio] features = ["io-util", "macros", "process", "rt-multi-thread", "sync", "time"] @@ -130,12 +130,17 @@ plist = "1.6" trash = "5.1" [target.'cfg(target_os = "linux")'.dependencies] -trash = "5.1" inotify = "0.11.0" +trash = "5.1" [target.'cfg(target_os = "windows")'.dependencies] -trash = "5.1" -windows = { features = ["Win32_Storage_FileSystem"], version = "0.58" } +trash = "5.1" +windows = { features = [ + "Win32_Storage_FileSystem", + "Win32_System_IO", + "Win32_System_Ioctl", + "Win32_System_WindowsProgramming" +], version = "0.58" } [target.'cfg(target_os = "ios")'.dependencies] icrate = { version = "0.1.2", features = [ diff --git a/core/crates/cloud-services/src/client.rs b/core/crates/cloud-services/src/client.rs index c37274b61..3e98c7a83 100644 --- a/core/crates/cloud-services/src/client.rs +++ b/core/crates/cloud-services/src/client.rs @@ -10,7 +10,6 @@ use quic_rpc::{transport::quinn::QuinnConnector, RpcClient, RpcMessage}; use quinn::{crypto::rustls::QuicClientConfig, ClientConfig, Endpoint}; use reqwest::{IntoUrl, Url}; use reqwest_middleware::{reqwest, ClientBuilder, ClientWithMiddleware}; -use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware}; use tokio::sync::{Mutex, RwLock}; use tracing::warn; diff --git a/core/src/library/statistics.rs b/core/src/library/statistics.rs index 078076738..8e376e6c7 100644 --- a/core/src/library/statistics.rs +++ b/core/src/library/statistics.rs @@ -39,8 +39,12 @@ pub async fn update_library_statistics( if total_capacity == 0 && available_capacity == 0 { // Failed to fetch volume statistics from database, so we compute from local volumes + #[cfg(any(target_os = "linux", target_os = "macos"))] let volumes = crate::volume::get_volumes().await?; + #[cfg(target_os = "windows")] + let volumes = crate::volume::get_volumes().await; + let mut local_total_capacity: u64 = 0; let mut local_available_capacity: u64 = 0; for volume in volumes { diff --git a/core/src/volume/os.rs b/core/src/volume/os.rs index f368faaf2..315d18fbb 100644 --- a/core/src/volume/os.rs +++ b/core/src/volume/os.rs @@ -27,7 +27,7 @@ mod common { pub fn parse_size(size_str: &str) -> u64 { size_str .chars() - .filter(|c| c.is_digit(10)) + .filter(|c| c.is_ascii_digit()) .collect::() .parse() .unwrap_or(0) @@ -315,19 +315,23 @@ pub mod linux { pub mod windows { use super::*; use std::ffi::OsString; - use std::os::windows::ffi::OsStringExt; - use windows::Win32::Storage::FileSystem::{ - GetDiskFreeSpaceExW, GetDriveTypeW, GetVolumeInformationW, DRIVE_FIXED, DRIVE_REMOTE, - DRIVE_REMOVABLE, + use std::path::PathBuf; + + use ::windows::core::PCWSTR; + use ::windows::Win32::Storage::FileSystem::{ + GetDiskFreeSpaceExW, GetDriveTypeW, GetVolumeInformationW, }; - use windows::Win32::System::Ioctl::STORAGE_PROPERTY_QUERY; + use ::windows::Win32::System::WindowsProgramming::{ + DRIVE_FIXED, DRIVE_REMOTE, DRIVE_REMOVABLE, + }; + use std::os::windows::ffi::OsStrExt; pub async fn get_volumes() -> Vec { task::spawn_blocking(|| { let mut volumes = Vec::new(); // Get available drives - let drives = unsafe { windows::Win32::Storage::FileSystem::GetLogicalDrives() }; + let drives = unsafe { ::windows::Win32::Storage::FileSystem::GetLogicalDrives() }; for i in 0..26 { if (drives & (1 << i)) != 0 { @@ -338,7 +342,7 @@ pub mod windows { .chain(std::iter::once(0)) .collect(); - let drive_type = unsafe { GetDriveTypeW(wide_path.as_ptr()) }; + let drive_type = unsafe { GetDriveTypeW(PCWSTR(wide_path.as_ptr())) }; // Skip CD-ROM drives and other unsupported types if drive_type == DRIVE_FIXED @@ -379,29 +383,25 @@ pub mod windows { unsafe { let success = GetVolumeInformationW( - wide_path.as_ptr(), - name_buf.as_mut_ptr(), - name_buf.len() as u32, - &mut serial_number, - &mut max_component_length, - &mut flags, - fs_name_buf.as_mut_ptr(), - fs_name_buf.len() as u32, + PCWSTR(wide_path.as_ptr()), + Some(name_buf.as_mut_slice()), + Some(&mut serial_number), + Some(&mut max_component_length), + Some(&mut flags), + Some(&mut fs_name_buf), ); - if success.as_bool() { + if let Ok(_) = success { let mut total_bytes = 0; let mut free_bytes = 0; let mut available_bytes = 0; - if GetDiskFreeSpaceExW( - wide_path.as_ptr(), - &mut available_bytes, - &mut total_bytes, - &mut free_bytes, - ) - .as_bool() - { + if let Ok(_) = GetDiskFreeSpaceExW( + PCWSTR(wide_path.as_ptr()), + Some(&mut available_bytes), + Some(&mut total_bytes), + Some(&mut free_bytes), + ) { let mount_type = match drive_type { DRIVE_FIXED => MountType::System, DRIVE_REMOVABLE => MountType::External, @@ -425,10 +425,12 @@ pub mod windows { }, mount_type, PathBuf::from(path), + vec![PathBuf::from(path)], detect_disk_type(path), FileSystem::from_string(&fs_name), - total_bytes as u64, - available_bytes as u64, + total_bytes, + available_bytes, + false, )) } else { None @@ -440,37 +442,39 @@ pub mod windows { } pub async fn unmount_volume(path: &std::path::Path) -> Result<(), VolumeError> { - use std::ffi::OsStr; - use std::os::windows::ffi::OsStrExt; - use windows::core::PWSTR; - use windows::Win32::Storage::FileSystem::{ + use ::windows::core::PWSTR; + use ::windows::Win32::Storage::FileSystem::{ DeleteVolumeMountPointW, GetVolumeNameForVolumeMountPointW, }; + use std::ffi::OsStr; + use std::os::windows::ffi::OsStrExt; // Convert path to wide string for Windows API - let wide_path: Vec = OsStr::new(path) + let mut wide_path: Vec = OsStr::new(path) .encode_wide() .chain(std::iter::once(0)) .collect(); + let wide_path_ptr = PWSTR(wide_path.as_mut_ptr()); + unsafe { // Buffer for volume name let mut volume_name = [0u16; 50]; - let mut volume_name_ptr = PWSTR(volume_name.as_mut_ptr()); // Get the volume name for the mount point - let result = GetVolumeNameForVolumeMountPointW(wide_path.as_ptr(), volume_name_ptr); + let result = + GetVolumeNameForVolumeMountPointW(wide_path_ptr, volume_name.as_mut_slice()); - if !result.as_bool() { + if result.is_err() { return Err(VolumeError::Platform( "Failed to get volume name".to_string(), )); } // Delete the mount point - let result = DeleteVolumeMountPointW(wide_path.as_ptr()); + let result = DeleteVolumeMountPointW(wide_path_ptr); - if result.as_bool() { + if let Ok(_) = result { Ok(()) } else { Err(VolumeError::Platform( diff --git a/core/src/volume/state.rs b/core/src/volume/state.rs index 886c22971..25d7a4c89 100644 --- a/core/src/volume/state.rs +++ b/core/src/volume/state.rs @@ -2,7 +2,7 @@ use crate::{ library::Library, volume::{ speed::SpeedTest, - types::{LibraryId, Volume, VolumeEvent, VolumeFingerprint, VolumePubId}, + types::{Volume, VolumeEvent, VolumeFingerprint}, }, }; @@ -84,7 +84,12 @@ impl VolumeManagerState { } pub async fn scan_volumes(&mut self) -> Result<(), VolumeError> { + #[cfg(any(target_os = "linux", target_os = "macos"))] let detected_volumes = super::os::get_volumes().await?; + + #[cfg(target_os = "windows")] + let detected_volumes = super::os::get_volumes().await; + let mut registry = self.registry.write().await; // Track existing volumes for removal detection @@ -192,7 +197,7 @@ impl VolumeManagerState { for (fingerprint, volume) in registry.volumes() { let mut volume = volume.clone(); - if let Some(db_volume) = db_volumes.get(&fingerprint) { + if let Some(db_volume) = db_volumes.get(fingerprint) { volume = Volume::merge_with_db(&volume, db_volume); } diff --git a/core/src/volume/watcher.rs b/core/src/volume/watcher.rs index f5d9cf415..53f800387 100644 --- a/core/src/volume/watcher.rs +++ b/core/src/volume/watcher.rs @@ -10,7 +10,7 @@ use tokio::{ sync::{broadcast, mpsc, RwLock}, time::{sleep, Instant}, }; -use tracing::{debug, error, warn}; +use tracing::{debug, error}; const DEBOUNCE_MS: u64 = 100; @@ -58,35 +58,40 @@ impl VolumeWatcher { } last_check = Instant::now(); - match super::os::get_volumes().await { - Ok(discovered_volumes) => { - let actor = actor.lock().await; - - // Find new volumes - for volume in &discovered_volumes { - let fingerprint = VolumeFingerprint::new(&device_id, volume); - - let volume_exists = actor.volume_exists(fingerprint.clone()).await; - // if the volume doesn't exist in the actor state, we need to send an event - if !volume_exists { - let _ = event_tx.send(VolumeEvent::VolumeAdded(volume.clone())); - } - } - - // Find removed volumes and send an event - for volume in &actor.get_volumes().await { - let fingerprint = VolumeFingerprint::new(&device_id, volume); - if !discovered_volumes - .iter() - .any(|v| VolumeFingerprint::new(&device_id, v) == fingerprint) - { - let _ = - event_tx.send(VolumeEvent::VolumeRemoved(volume.clone())); - } - } - } + #[cfg(any(target_os = "linux", target_os = "macos"))] + let discovered_volumes = match super::os::get_volumes().await { + Ok(volumes) => volumes, Err(e) => { - warn!("Failed to get volumes during watch: {}", e); + error!("Failed to get volumes: {}", e); + // Return empty volumes to avoid sending events + vec![] + } + }; + + #[cfg(target_os = "windows")] + let discovered_volumes = super::os::get_volumes().await; + + let actor = actor.lock().await; + + // Find new volumes + for volume in &discovered_volumes { + let fingerprint = VolumeFingerprint::new(&device_id, volume); + + let volume_exists = actor.volume_exists(fingerprint.clone()).await; + // if the volume doesn't exist in the actor state, we need to send an event + if !volume_exists { + let _ = event_tx.send(VolumeEvent::VolumeAdded(volume.clone())); + } + } + + // Find removed volumes and send an event + for volume in &actor.get_volumes().await { + let fingerprint = VolumeFingerprint::new(&device_id, volume); + if !discovered_volumes + .iter() + .any(|v| VolumeFingerprint::new(&device_id, v) == fingerprint) + { + let _ = event_tx.send(VolumeEvent::VolumeRemoved(volume.clone())); } } } @@ -183,10 +188,7 @@ impl VolumeWatcher { #[cfg(target_os = "windows")] { - use windows::Win32::Storage::FileSystem::{ - FindFirstVolumeW, FindNextVolumeW, FindVolumeClose, ReadDirectoryChangesW, - FILE_NOTIFY_CHANGE_DIR_NAME, - }; + use ::windows::Win32::Storage::FileSystem::{FindFirstVolumeW, FindVolumeClose}; let check_tx = check_tx.clone(); tokio::spawn(async move { @@ -194,13 +196,23 @@ impl VolumeWatcher { // Watch for volume arrival/removal unsafe { let mut volume_name = [0u16; 260]; - let handle = FindFirstVolumeW(volume_name.as_mut_ptr()); - if !handle.is_invalid() { + let mut volume_change_detected = false; + match FindFirstVolumeW(volume_name.as_mut_slice()) { + Ok(handle) => { + if !handle.is_invalid() { + volume_change_detected = true; + FindVolumeClose(handle); + } + } + Err(e) => { + error!("Failed to get a volume handle: {}", e); + } + } + if volume_change_detected { // Volume change detected if let Err(e) = check_tx.send(()).await { error!("Failed to trigger volume check: {}", e); } - FindVolumeClose(handle); } } sleep(Duration::from_millis(100)).await;