Hi,
I try to call Backend from my Frontend, specifically a config. My code is compiling but I cannot reach the config.toml
Backend: Tauri 2.0
Frontend: YEW 0.21
Config is located at src-tauri/src/config.toml
I would be very happy if I can get help to spot the issue. Hopefully that is possible from the code I have provided. Otherwise make me aware of common mistakes I should pay attention to?
//snippet from Frontend YEW lib.rs
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"], js_name = invoke)]
async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}
#[function_component(DanceOmatic)]
pub fn dance_o_matic() -> Html {
let config = use_state(|| None);
let config_clone = config.clone();
use_effect(move || {
wasm_bindgen_futures::spawn_local(async move {
// Create an empty JSON object for the arguments
let args = serde_json::json!({});
// Convert to JsValue
let js_args = to_value(&args).unwrap();
let result = invoke("get_config", js_args).await;
let config_result: Result<Config, String> = serde_wasm_bindgen::from_value(result).unwrap();
match config_result {
Ok(loaded_config) => {
log::info!("Config loaded successfully");
config_clone.set(Some(Rc::new(loaded_config)));
},
Err(err) => log::error!("Failed to parse result: {:?}", err),
}
});
|| ()
});
html! {
<div>
<MusicContextProvider>
<SoundEffectsProvider>
<BrowserRouter>
{ if let Some(config) = &*config {
html! { <Switch<Route> render={switch(config.clone())} /> }
} else {
html! { <p>{ "Loading config..." }</p> } //<-- I only get this output on screen
}}
</BrowserRouter>
</SoundEffectsProvider>
</MusicContextProvider>
</div>
}
}
//snippet end
Backend looks like this:
//src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
use toml;
use serde::Deserialize;
use serde::Serialize;
use std::fmt;
const CONFIG_PATH: &str = "src-tauri/src/config.toml";
pub struct ConfigError(String);
//impl of config error
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
struct Config {
pub dancers: Dancers,
pub demo_videos: DemoVideos,
pub choreo_videos: ChoreoVideos,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
struct Dancers {
pub list: Vec<ConfigDancer>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
struct ConfigDancer {
//fields of struct
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
struct DemoVideos {
pub list: Vec<DemoVideoConfig>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
struct DemoVideoConfig {
//fields of struct
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
struct ChoreoVideos {
pub list: Vec<ChoreoVideoConfig>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
struct ChoreoVideoConfig {
//fields of struct
}
impl Config {
pub fn from_file(path: &str) -> Result<Self, ConfigError> {
let config_content = std::fs::read_to_string(path).map_err(|err| err.to_string())?;
let config: Config = toml::from_str(&config_content).map_err(|err| err.to_string())?;
Ok(config)
}
}
#[tauri::command]
fn get_config() -> Result<Config, String> {
Config::from_file(CONFIG_PATH).map_err(|err| err.to_string())
}
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![get_config])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Inspecting element when running cargo tauri dev in terminal gives me:
panicked at src/lib.rs:38:1:
unexpected exception: JsValue("ConfigError: No such file or directory (os error 2)")
Stack:
@http://localhost:8080/yew-app-273cc721a4e71c34.js:614:30
<?>.wasm-function[21578]@[wasm code]*
*<?>.wasm-function[13475]@[wasm code]
<?>.wasm-function[3161]@[wasm code]
Output is much longer.
I also have a config.rs in frontend:
//src/components/data/config.rs
// snippet of code
// defining struct Dancers, DemoVideos, ChoreoVideos (again)
#[derive(Debug, Deserialize, Clone, PartialEq)]
pub struct Config {
pub dancers: Dancers,
pub demo_videos: DemoVideos,
pub choreo_videos: ChoreoVideos,
}
impl Config {
pub fn load_dancers(&self) -> std::collections::HashMap<usize, Vec<Dancer>> {
let mut choreography_map = std::collections::HashMap::new();
for dancer_config in &self.dancers.list {
let dancer = Dancer {
image: dancer_config.image.clone(),
name: dancer_config.name.clone(),
strength: dancer_config.strength,
flexibility: dancer_config.flexibility,
};
for &choreo_number in &dancer_config.in_chroeography_nr {
choreography_map
.entry(choreo_number)
.or_insert_with(Vec::new)
.push(dancer.clone());
}
}
choreography_map
}
pub fn get_demo_videos(&self) -> Vec<VideoType> {
self.demo_videos.list.iter().map(|video_config| {
VideoType::Demo(DemoVideo {
video: Video {
id: video_config.id,
url: video_config.url.clone(),
loop_video: video_config.loop_video,
},
title: video_config.title.clone(),
duration: video_config.duration.clone(),
})
}).collect()
}
pub fn load_choreo_videos(&self) -> Vec<VideoType> {
self.choreo_videos.list.iter().map(|video_config| {
VideoType::Regular(Video {
id: video_config.id,
url: video_config.url.clone(),
loop_video: video_config.loop_video,
})
}).collect()
}
}