Module "agera::file"

I have done the initial agera::file module of my rich internet applications SDK.

While it does not yet include "Open/Save As" as file dialogs, it is generally usable and already includes alternatives to its common File object, such as FileReference, which builds for the web browser and native platforms. I have not experimented anything yet when exporting the actual application to an executable, installer or web application. I have not worked on exporting the application as well, however I am already embedding installation files for the web browser by using something like let _ = File::application_directory().resolve_path(path).write_async(include_bytes!(...)).await; in a bootstrap code after pattern matching on installation files specified by the application descriptor (agera-application.json).

It includes synchronous and asynchronous operations, where only the browsers do not support synchronous operations because of the use of the origin-private file system. Additionally, the file: scheme for File objects is only supported in native platforms.

Here is a demo: the following output is what I get in a test function when using app:.

use agera::file::*;
for file in File::application_directory().directory_listing()? {
    println!("{}", file.url());
}

app://Cargo.toml
app://README.md
app://src

Note that File::new("app://") is equivalent to File::application_directory(), just as File::new("app-storage://") is equivalent to File::application_storage_directory().

  • I have made it so that every app: File is read-only.

The app: URI should resolve to the installation's directory, while app-storage: should resolve to the data storage's directory. What concerns me is that I am not sure if I am choosing the best paths for the installation directory and storage directory.

Here is what I am doing for internally determining the application paths for File across all platforms:

fn application_directory() -> String {
    if_native_platform! {{
        cfg_if! {
            if #[cfg(target_os = "android")] {
                let path = if let Some(p) = crate::platforms::application().external_data_path() { p } else { crate::platforms::application().internal_data_path().unwrap() };
                path.join("installFiles").to_string_lossy().into_owned()
            } else if #[cfg(debug_assertions)] {
                std::env::current_dir().unwrap().to_str().unwrap().into()
            } else if #[cfg(target_os = "windows")] {
                // dirs::data_local_dir().unwrap().join(&crate::application::id()).to_string_lossy().into_owned()
                std::path::PathBuf::from(&std::env::current_exe().unwrap()).parent().unwrap().to_str().unwrap().into()
            } else {
                dirs::data_dir().unwrap().join(&crate::application::id()).join("installFiles").to_string_lossy().into_owned()
            }
        }
    }}
    if_browser! {{
        "/installFiles".into()
    }}
}

fn application_storage_directory() -> String {
    if_native_platform! {{
        cfg_if! {
            if #[cfg(target_os = "android")] {
                let path = if let Some(p) = crate::platforms::application().external_data_path() { p } else { crate::platforms::application().internal_data_path().unwrap() };
                path.join("storageFiles").to_string_lossy().into_owned()
            } else if #[cfg(debug_assertions)] {
                std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("agera_sdk_build/debug_storage_files").to_string_lossy().into_owned()
            } else if #[cfg(target_os = "windows")] {
                dirs::data_dir().unwrap().join(&crate::application::id()).to_string_lossy().into_owned()
            } else {
                dirs::data_dir().unwrap().join(&crate::application::id()).join("storageFiles").to_string_lossy().into_owned()
            }
        }
    }}
    if_browser! {{
        "/storageFiles".into()
    }}
}

Why is there the src folder in the installation directory? That where you'd put the compiled executable.

Edit: It comes from the if #[cfg(debug_assertions)], right? I don't know if that's a good or bad thing, as you can't test a packaged application with that.

1 Like

Right, however these debug_assertions sections only compile if Rust is compiling the code for debugging purposes.

You usually use app: for accessing asset files, that is why I am resolving to the project's root when debugging.