Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src-tauri/capabilities/desktop.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@
"locale:default",
"updater:default",
"opener:default",
"fs:allow-exists",
"fs:allow-read-text-file",
"fs:allow-write-text-file",
"fs:allow-mkdir",
"fs:allow-remove",
"fs:allow-read-dir",
{
"identifier": "fs:allow-exists",
"allow": ["**"]
},
{
"identifier": "fs:allow-read-text-file",
"allow": ["**"]
},
{
"identifier": "opener:allow-open-path",
"allow": [
Expand Down
249 changes: 1 addition & 248 deletions src-tauri/src/commands/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,175 +2,14 @@ use crate::{
FileMetadata, PocketSyncState,
app_error::AppError,
clean_fs::find_dotfiles,
file_cache::get_file_with_cache,
hashes::{HashCacheState, crc32_for_file},
progress,
saves_zip::remove_leading_slash,
util::{find_common_path, get_mtime_timestamp},
};
use async_walkdir::{DirEntry, WalkDir};
use futures::{StreamExt, stream};
use log::{debug, error, trace};
use log::{debug, trace};
use std::{path::PathBuf, time::SystemTime};
use tauri::{Emitter, Manager, Window};
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tauri::command(async)]
pub async fn read_binary_file(
state: tauri::State<'_, PocketSyncState>,
path: &str,
app_handle: tauri::AppHandle,
) -> Result<Vec<u8>, String> {
debug!("Command: read_binary_file - {path}");
let pocket_path = state.0.pocket_path.read().await;
let path = pocket_path.join(path);

let arc_lock = state.0.file_locker.find_lock_for(&path).await;
let _read_lock = arc_lock.read().await;

if let Ok(mut f) = if let Ok(cache_dir) = app_handle.path().app_cache_dir() {
get_file_with_cache(&path, &cache_dir).await
} else {
tokio::fs::File::open(&path).await
} {
let mut buffer = vec![];
f.read_to_end(&mut buffer)
.await
.expect(&format!("failed to read file: {:?}", path));

Ok(buffer)
} else {
Err(format!("No file found: {}", path.display()))
}
}

#[tauri::command(async)]
pub async fn read_text_file(
state: tauri::State<'_, PocketSyncState>,
path: &str,
app_handle: tauri::AppHandle,
) -> Result<String, ()> {
debug!("Command: read_text_file - {path}");
let pocket_path = state.0.pocket_path.read().await;
let path = pocket_path.join(path);

let arc_lock = state.0.file_locker.find_lock_for(&path).await;
let _read_lock = arc_lock.read().await;

let mut f = if let Ok(cache_dir) = app_handle.path().app_cache_dir() {
get_file_with_cache(&path, &cache_dir).await
} else {
tokio::fs::File::open(&path).await
}
.expect(&format!("no file found: {:?}", &path));

let mut file_contents = String::new();
f.read_to_string(&mut file_contents)
.await
.expect(&format!("failed to read file: {:?}", path));
Ok(file_contents)
}

#[tauri::command(async)]
pub async fn file_exists(
state: tauri::State<'_, PocketSyncState>,
path: &str,
) -> Result<bool, AppError> {
trace!("Command: file_exists - {path}");
let pocket_path = state.0.pocket_path.read().await;
let path = pocket_path.join(path);

let exists = tokio::fs::try_exists(&path).await?;
Ok(exists)
}

#[tauri::command(async)]
pub async fn save_file(
path: &str,
buffer: Vec<u8>,
state: tauri::State<'_, PocketSyncState>,
) -> Result<bool, ()> {
debug!("Command: save_file - {path}");
let file_path = PathBuf::from(path);
let folder_path = file_path.parent().unwrap();
let arc_lock = state.0.file_locker.find_lock_for(&file_path).await;
let _write_lock = arc_lock.write().await;
tokio::fs::create_dir_all(&folder_path).await.unwrap();
let mut file = tokio::fs::File::create(file_path).await.unwrap();
file.write_all(&buffer).await.unwrap();
file.flush().await.unwrap();
Ok(true)
}

#[tauri::command(async)]
pub async fn list_files(
path: &str,
state: tauri::State<'_, PocketSyncState>,
) -> Result<Vec<String>, ()> {
debug!("Command: list_files - {path}");
let pocket_path = state.0.pocket_path.read().await;
let dir_path = pocket_path.join(path);

let arc_lock = state.0.file_locker.find_lock_for(&dir_path).await;
trace!("list_files lock requested");
let _read_lock = arc_lock.read().await;
trace!("list_files lock granted");

if !tokio::fs::try_exists(&dir_path).await.unwrap() {
return Ok(vec![]);
}

let mut paths = tokio::fs::read_dir(dir_path).await.unwrap();
let mut results: Vec<_> = Vec::new();

while let Ok(Some(entry)) = paths.next_entry().await {
let file_type = entry.file_type().await.unwrap();
if file_type.is_file() {
let file_name = entry.file_name();
let file_name = file_name.to_str().unwrap();

if !file_name.starts_with(".") {
results.push(String::from(file_name))
}
}
}

Ok(results)
}

#[tauri::command(async)]
pub async fn list_folders(
path: &str,
state: tauri::State<'_, PocketSyncState>,
) -> Result<Vec<String>, ()> {
debug!("Command: list_folders - {path}");
let pocket_path = state.0.pocket_path.read().await;
let dir_path = pocket_path.join(path);

let arc_lock = state.0.file_locker.find_lock_for(&dir_path).await;
let _read_lock = arc_lock.read().await;

if !tokio::fs::try_exists(&dir_path).await.unwrap() {
return Ok(vec![]);
}

let mut paths = tokio::fs::read_dir(dir_path).await.unwrap();
let mut results: Vec<_> = Vec::new();

while let Ok(Some(entry)) = paths.next_entry().await {
let file_type = entry.file_type().await.unwrap();
if file_type.is_dir() {
let file_name = entry.file_name();
let file_name = file_name.to_str().unwrap();

if !file_name.starts_with(".") {
results.push(String::from(file_name))
}
}
}

Ok(results)
}

#[tauri::command(async)]
pub async fn walkdir_list_files(
Expand Down Expand Up @@ -225,68 +64,6 @@ pub async fn walkdir_list_files(
Ok(file_paths)
}

#[tauri::command(async)]
pub async fn delete_files(
paths: Vec<&str>,
state: tauri::State<'_, PocketSyncState>,
) -> Result<bool, ()> {
debug!("Command: delete_files");
let pocket_path = state.0.pocket_path.read().await;

let tasks: Vec<_> = paths
.into_iter()
.filter_map(|path| {
let file_path = pocket_path.join(path);
file_path
.exists()
.then(|| tokio::fs::remove_file(file_path))
})
.collect();

futures::future::join_all(tasks).await;
Ok(true)
}

#[tauri::command(async)]
pub async fn copy_files(
copies: Vec<(&str, &str)>,
window: Window,
state: tauri::State<'_, PocketSyncState>,
) -> Result<bool, ()> {
debug!("Command: copy_files");

let mut progress = progress::ProgressEmitter::new(Box::new(|event| {
window.emit("progress-event::copy_files", event).unwrap();
}));

progress.begin_work_units(copies.len());

let all_dests: Vec<PathBuf> = copies
.iter()
.map(|(_source, dest)| PathBuf::from(dest))
.collect();
let common_dir = find_common_path(&all_dests).unwrap();
let arc_lock = state.0.file_locker.find_lock_for(&common_dir).await;
let _write_lock = arc_lock.write().await;

for (origin, destination) in copies {
let origin = PathBuf::from(origin);
let destination = PathBuf::from(&destination);

if let Err(err) = match tokio::fs::create_dir_all(destination.parent().unwrap()).await {
Ok(_) => tokio::fs::copy(&origin, &destination).await,
Err(e) => Err(e),
} {
error!("{}", err);
} else {
progress.complete_work_units(1);
progress.set_message("file", Some(&destination.to_string_lossy()));
}
}

Ok(true)
}

#[tauri::command(async)]
pub async fn find_cleanable_files(
path: &str,
Expand Down Expand Up @@ -363,18 +140,6 @@ pub async fn save_multiple_files(
Ok(())
}

#[tauri::command(async)]
pub async fn get_file_metadata_mtime_only(
state: tauri::State<'_, PocketSyncState>,
file_path: &str,
) -> Result<u64, AppError> {
trace!("Command: get_file_metadata_mtime_only");
let pocket_path = state.0.pocket_path.read().await;
let full_path = pocket_path.join(file_path);

Ok(get_mtime_timestamp(&full_path).await?)
}

#[tauri::command(async)]
pub async fn get_file_metadata(
state: tauri::State<'_, PocketSyncState>,
Expand All @@ -401,15 +166,3 @@ pub async fn get_file_metadata(
crc32,
})
}

#[tauri::command(async)]
pub async fn create_folder_if_missing(path: &str) -> Result<bool, ()> {
debug!("Command: create_folder_if_missing - {path}");
let folder_path = PathBuf::from(path);
if !folder_path.exists() {
tokio::fs::create_dir_all(path).await.unwrap();
return Ok(true);
}

Ok(false)
}
21 changes: 8 additions & 13 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use file_cache::clear_file_caches;
use file_locks::FileLocks;
use install_zip::start_zip_task;
use job_id::{Job, JobState};
use log::{LevelFilter, debug, trace};
use log::{LevelFilter, debug, info, trace};
use root_files::RootFile;
use save_sync_session::start_mister_save_sync_session;
use saves_zip::SaveZipFile;
Expand All @@ -19,6 +19,7 @@ use std::path::PathBuf;
use std::vec;
use tauri::{App, Emitter, Manager, RunEvent};
use tauri_plugin_dialog::DialogExt;
use tauri_plugin_fs::FsExt;
use tauri_plugin_log::{Target, TargetKind};
use tokio::sync::{Mutex, RwLock};

Expand Down Expand Up @@ -62,7 +63,7 @@ struct PocketSyncState(InnerState);
async fn open_pocket(
state: tauri::State<'_, PocketSyncState>,
app_handle: tauri::AppHandle,
) -> Result<Option<String>, ()> {
) -> Result<Option<String>, AppError> {
debug!("Command: open_pocket");

if let Some(tauri_plugin_dialog::FilePath::Path(pocket_path)) =
Expand All @@ -79,10 +80,14 @@ async fn open_pocket_folder(
state: tauri::State<'_, PocketSyncState>,
pocket_path: &str,
app_handle: tauri::AppHandle,
) -> Result<Option<String>, ()> {
) -> Result<Option<String>, AppError> {
debug!("Command: open_pocket_folder {pocket_path}");
let window = app_handle.get_webview_window("main").unwrap();
let pocket_path = PathBuf::from(pocket_path);

info!("Adding {:?} to fs_scope", &pocket_path);
app_handle.fs_scope().allow_directory(&pocket_path, true)?;

if !check_if_folder_looks_like_pocket(&pocket_path) {
return Ok(None);
}
Expand Down Expand Up @@ -279,30 +284,20 @@ fn main() {
.invoke_handler(tauri::generate_handler![
open_pocket,
open_pocket_folder,
commands::files::list_files,
commands::files::list_folders,
commands::files::walkdir_list_files,
commands::files::read_binary_file,
commands::files::read_text_file,
commands::files::save_file,
commands::cores::uninstall_core,
commands::archive::install_archive_files,
commands::files::file_exists,
commands::saves::backup_saves,
commands::saves::list_backup_saves,
commands::saves::list_saves_in_zip,
commands::saves::list_saves_on_pocket,
commands::saves::restore_save,
commands::files::create_folder_if_missing,
commands::files::delete_files,
commands::files::copy_files,
commands::files::find_cleanable_files,
commands::cores::list_instance_packageable_cores,
commands::cores::run_packager_for_core,
get_news_feed,
begin_mister_sync_session,
commands::files::get_file_metadata,
commands::files::get_file_metadata_mtime_only,
commands::firmware::get_firmware_versions_list,
commands::firmware::get_firmware_release_notes,
commands::firmware::download_firmware,
Expand Down
4 changes: 2 additions & 2 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from "@tauri-apps/plugin-window-state"
import { listen } from "@tauri-apps/api/event"
import { AutoUpdate } from "./components/autoUpdate"
import { createStore, Provider } from "jotai"
import { createStore, Provider, getDefaultStore } from "jotai"
import { PluginWindow } from "./components/plugins/pluginWindow"

installPolyfills()
Expand All @@ -32,7 +32,7 @@ listen<string>("resize", (event) => {
saveWindowState(StateFlags.ALL)
})

const jotaiStore = createStore()
const jotaiStore = getDefaultStore()

const MainWindow = () => {
return (
Expand Down
Loading
Loading