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>
This commit is contained in:
Nickolay 2025-02-10 21:57:43 +02:00 committed by GitHub
parent fbae190393
commit 28a390f167
8 changed files with 112 additions and 84 deletions

View File

@ -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 }}

View File

@ -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<void> {
await TAURI_INVOKE('stop_drag');
},

View File

@ -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" }
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 = [

View File

@ -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;

View File

@ -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 {

View File

@ -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::<String>()
.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<Volume> {
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<u16> = OsStr::new(path)
let mut wide_path: Vec<u16> = 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(

View File

@ -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);
}

View File

@ -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,8 +58,19 @@ impl VolumeWatcher {
}
last_check = Instant::now();
match super::os::get_volumes().await {
Ok(discovered_volumes) => {
#[cfg(any(target_os = "linux", target_os = "macos"))]
let discovered_volumes = match super::os::get_volumes().await {
Ok(volumes) => volumes,
Err(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
@ -80,13 +91,7 @@ impl VolumeWatcher {
.iter()
.any(|v| VolumeFingerprint::new(&device_id, v) == fingerprint)
{
let _ =
event_tx.send(VolumeEvent::VolumeRemoved(volume.clone()));
}
}
}
Err(e) => {
warn!("Failed to get volumes during watch: {}", e);
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());
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;