#Unsure of where to write a user config file

13 messages · Page 1 of 1 (latest)

whole root
#

I'm trying to store a .json file that would be used for a user. I want to store a file path to this .json file that the user has selected from a function using FileDialogBuilder::new().pick_folder() which would also need to invoke another function using this path.
Currently the file is being written inside of the src-tauri directory.

async fn select_directory() -> Result<String, String> {
    let (tx, rx) = std::sync::mpsc::channel();

    FileDialogBuilder::new().pick_folder(move |folder_path| {
        if let Some(path) = folder_path {
            let path_str = path.to_str().unwrap_or("").to_string();
            
            // Update the global BASE_FOLDER variable
            let mut base_folder = BASE_FOLDER.lock().unwrap();
            *base_folder = Some(path_str.clone());

            // Write to a JSON file
            let j = json!({
                "base_folder": path_str.clone()
            });

            if let Err(e) = write("config.json", j.to_string()) {
                eprintln!("Unable to write to config.json: {}", e);
            }
            
            // Debug statement
            println!("Debug: BASE_FOLDER inside select_directory is now: {:?}", base_folder);

            tx.send(Ok(path_str)).unwrap();

        } else {
            tx.send(Err("No folder was picked".to_string())).unwrap();
        }
    });

    // Receive the result from the closure
    let result = rx.recv().unwrap();

    // Perform the scan_directory if folder was successfully picked
    if let Ok(path_str) = &result {
        if let Err(e) = scan_directory(path_str.clone()).await {
            eprintln!("Failed to rescan directory after folder change: {}", e);
        }
    }

    result
}```
steep musk
whole root
#
#[tauri::command]
async fn select_directory(app_handle: tauri::AppHandle) -> Result<String, String> {
    let config_dir_option = app_handle.path_resolver().app_config_dir();

    // Safely unwrap the Option
    if let Some(config_dir) = config_dir_option {
        // Print the config directory path
        println!("Config file should be at: {:?}", config_dir);
        
        let (tx, rx) = std::sync::mpsc::channel();
        FileDialogBuilder::new().pick_folder(move |folder_path| {
            if let Some(path) = folder_path {
                let path_str = path.to_str().unwrap_or("").to_string();
                
                // Update the global BASE_FOLDER variable
                let mut base_folder = BASE_FOLDER.lock().unwrap();
                *base_folder = Some(path_str.clone());
                
                // Convert PathBuf to &Path and then write to the configuration file
                if let Err(e) = write_base_folder_to_config(&config_dir.as_path(), &path_str) {
                    eprintln!("Failed to write base folder to config: {}", e);
                }
                
                tx.send(Ok(path_str)).unwrap();
            } else {
                println!("No folder was picked.");
                tx.send(Err("No folder was picked".to_string())).unwrap();
            }
        });
        rx.recv().unwrap()
    } else {
        // Handle the case where the app_config_dir is None
        Err("Could not determine the application config directory.".to_string())
    }
}

fn write_base_folder_to_config(config_dir: &Path, base_folder: &str) -> std::io::Result<()> {
    let config_file_path = config_dir.join("base_folder_config.json");
    let serialized = json!({
        "base_folder": base_folder
    }).to_string();
    
    let mut file = File::create(config_file_path)?;
    file.write_all(serialized.as_bytes())?;
    Ok(())
}
steep musk
#

You'll have to create the dir yourself via create_dir_all for example

whole root
#

gotcha! ok thanks for your help Fabian, much appreciated

whole root
#

@steep musk

How can I call a function on the rust layer with the app_handle: tauri::AppHandle as an argument? I notice I can call a function with it as an argument from the frontend no problem without needing to pass any args.

for example invoking this function from main:

pub fn initialize_config_dir(app_handle: tauri::AppHandle) -> std::io::Result<()> {
// ...
}
steep musk
#

well

#

that depends a bit on where you call it

#

the earliest point in time you can get an apphandle is the setup hook on the builder

#

but all the hooks on the tauri builder have a way to access an apphandle

#

but you have to somehow get it from the tauri app instance to your function, you can't make it magically appear like in tauri commands

#

if there is absolutely no semi-direct connection between the tauri app and that function the next best thing would be a global-ish AppHandle via a OnceCell (recently added to rust std, but there's also a once_cell crate) which you then init from the setup hook