refactor: setup extensions, engines and sidecar
This commit is contained in:
parent
5b8eab6469
commit
c0756767cd
@ -129,9 +129,6 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
|
||||
)
|
||||
if (!Number.isNaN(threads_number)) this.cpu_threads = threads_number
|
||||
|
||||
// Run the process watchdog
|
||||
// const systemInfo = await systemInformation()
|
||||
await executeOnMain(NODE, 'run')
|
||||
this.subscribeToEvents()
|
||||
|
||||
window.addEventListener('beforeunload', () => {
|
||||
@ -143,7 +140,6 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
|
||||
console.log('Clean up cortex.cpp services')
|
||||
this.shouldReconnect = false
|
||||
this.clean()
|
||||
// await executeOnMain(NODE, 'dispose')
|
||||
super.onUnload()
|
||||
}
|
||||
|
||||
@ -222,24 +218,6 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Do health check on cortex.cpp
|
||||
* @returns
|
||||
*/
|
||||
private async healthz(): Promise<void> {
|
||||
return this.apiInstance().then((api) =>
|
||||
api
|
||||
.get('healthz', {
|
||||
retry: {
|
||||
limit: 20,
|
||||
delay: () => 500,
|
||||
methods: ['get'],
|
||||
},
|
||||
})
|
||||
.then(() => {})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean cortex processes
|
||||
* @returns
|
||||
|
||||
2
src-tauri/.gitignore
vendored
2
src-tauri/.gitignore
vendored
@ -2,3 +2,5 @@
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
/gen/schemas
|
||||
binaries
|
||||
!binaries/download.sh
|
||||
@ -1,9 +1,4 @@
|
||||
use flate2::read::GzDecoder;
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use tar::Archive;
|
||||
use tauri::AppHandle;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -231,129 +226,4 @@ pub fn get_user_home_path(app: AppHandle) -> String {
|
||||
return get_app_configurations(app.clone()).data_folder;
|
||||
}
|
||||
|
||||
fn extract_extension_manifest<R: Read>(archive: &mut Archive<R>) -> Result<Option<Value>, String> {
|
||||
let entry = archive
|
||||
.entries()
|
||||
.map_err(|e| e.to_string())?
|
||||
.filter_map(|e| e.ok()) // Ignore errors in individual entries
|
||||
.find(|entry| {
|
||||
if let Ok(file_path) = entry.path() {
|
||||
let path_str = file_path.to_string_lossy();
|
||||
path_str == "package/package.json" || path_str == "package.json"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(mut entry) = entry {
|
||||
let mut content = String::new();
|
||||
entry
|
||||
.read_to_string(&mut content)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let package_json: Value = serde_json::from_str(&content).map_err(|e| e.to_string())?;
|
||||
return Ok(Some(package_json));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn install_extensions(app: tauri::AppHandle) -> Result<(), String> {
|
||||
let extensions_path = get_jan_extensions_path(app.clone());
|
||||
let pre_install_path = PathBuf::from("./../pre-install");
|
||||
|
||||
if !extensions_path.exists() {
|
||||
fs::create_dir_all(&extensions_path).map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
let extensions_json_path = extensions_path.join("extensions.json");
|
||||
let mut extensions_list = if extensions_json_path.exists() {
|
||||
let existing_data =
|
||||
fs::read_to_string(&extensions_json_path).unwrap_or_else(|_| "[]".to_string());
|
||||
serde_json::from_str::<Vec<Value>>(&existing_data).unwrap_or_else(|_| vec![])
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
for entry in fs::read_dir(&pre_install_path).map_err(|e| e.to_string())? {
|
||||
let entry = entry.map_err(|e| e.to_string())?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.extension().map_or(false, |ext| ext == "tgz") {
|
||||
println!("Installing extension from {:?}", path);
|
||||
let tar_gz = File::open(&path).map_err(|e| e.to_string())?;
|
||||
let gz_decoder = GzDecoder::new(tar_gz);
|
||||
let mut archive = Archive::new(gz_decoder);
|
||||
|
||||
let mut extension_name = None;
|
||||
let mut extension_manifest = None;
|
||||
extract_extension_manifest(&mut archive)
|
||||
.map_err(|e| e.to_string())
|
||||
.and_then(|manifest| match manifest {
|
||||
Some(manifest) => {
|
||||
extension_name = manifest["name"].as_str().map(|s| s.to_string());
|
||||
extension_manifest = Some(manifest);
|
||||
Ok(())
|
||||
}
|
||||
None => Err("Manifest is None".to_string()),
|
||||
})?;
|
||||
|
||||
let extension_name = extension_name.ok_or("package.json not found in archive")?;
|
||||
let extension_dir = extensions_path.join(extension_name.clone());
|
||||
fs::create_dir_all(&extension_dir).map_err(|e| e.to_string())?;
|
||||
|
||||
let tar_gz = File::open(&path).map_err(|e| e.to_string())?;
|
||||
let gz_decoder = GzDecoder::new(tar_gz);
|
||||
let mut archive = Archive::new(gz_decoder);
|
||||
for entry in archive.entries().map_err(|e| e.to_string())? {
|
||||
let mut entry = entry.map_err(|e| e.to_string())?;
|
||||
let file_path = entry.path().map_err(|e| e.to_string())?;
|
||||
let components: Vec<_> = file_path.components().collect();
|
||||
if components.len() > 1 {
|
||||
let relative_path: PathBuf = components[1..].iter().collect();
|
||||
let target_path = extension_dir.join(relative_path);
|
||||
if let Some(parent) = target_path.parent() {
|
||||
fs::create_dir_all(parent).map_err(|e| e.to_string())?;
|
||||
}
|
||||
let _result = entry.unpack(&target_path).map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
|
||||
let main_entry = extension_manifest
|
||||
.as_ref()
|
||||
.and_then(|manifest| manifest["main"].as_str())
|
||||
.unwrap_or("index.js");
|
||||
let url = extension_dir.join(main_entry).to_string_lossy().to_string();
|
||||
|
||||
let new_extension = serde_json::json!({
|
||||
"url": url,
|
||||
"name": extension_name.clone(),
|
||||
"origin": extension_dir.to_string_lossy(),
|
||||
"active": true,
|
||||
"description": extension_manifest
|
||||
.as_ref()
|
||||
.and_then(|manifest| manifest["description"].as_str())
|
||||
.unwrap_or(""),
|
||||
"version": extension_manifest
|
||||
.as_ref()
|
||||
.and_then(|manifest| manifest["version"].as_str())
|
||||
.unwrap_or(""),
|
||||
"productName": extension_manifest
|
||||
.as_ref()
|
||||
.and_then(|manifest| manifest["productName"].as_str())
|
||||
.unwrap_or(""),
|
||||
});
|
||||
|
||||
extensions_list.push(new_extension);
|
||||
|
||||
println!("Installed extension to {:?}", extension_dir);
|
||||
}
|
||||
}
|
||||
fs::write(
|
||||
&extensions_json_path,
|
||||
serde_json::to_string_pretty(&extensions_list).map_err(|e| e.to_string())?,
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::handlers::cmd::get_jan_data_folder_path;
|
||||
use crate::core::cmd::get_jan_data_folder_path;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
pub mod cmd;
|
||||
pub mod fs;
|
||||
pub mod setup;
|
||||
244
src-tauri/src/core/setup.rs
Normal file
244
src-tauri/src/core/setup.rs
Normal file
@ -0,0 +1,244 @@
|
||||
use flate2::read::GzDecoder;
|
||||
use tauri::{App, Manager};
|
||||
use tauri_plugin_shell::process::CommandEvent;
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use tar::Archive;
|
||||
|
||||
use crate::AppState;
|
||||
|
||||
use super::cmd::get_jan_extensions_path;
|
||||
|
||||
pub fn install_extensions(app: tauri::AppHandle) -> Result<(), String> {
|
||||
let extensions_path = get_jan_extensions_path(app.clone());
|
||||
let pre_install_path = PathBuf::from("./../pre-install");
|
||||
|
||||
if !extensions_path.exists() {
|
||||
fs::create_dir_all(&extensions_path).map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
let extensions_json_path = extensions_path.join("extensions.json");
|
||||
let mut extensions_list = if extensions_json_path.exists() {
|
||||
let existing_data =
|
||||
fs::read_to_string(&extensions_json_path).unwrap_or_else(|_| "[]".to_string());
|
||||
serde_json::from_str::<Vec<serde_json::Value>>(&existing_data).unwrap_or_else(|_| vec![])
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
for entry in fs::read_dir(&pre_install_path).map_err(|e| e.to_string())? {
|
||||
let entry = entry.map_err(|e| e.to_string())?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.extension().map_or(false, |ext| ext == "tgz") {
|
||||
println!("Installing extension from {:?}", path);
|
||||
let tar_gz = File::open(&path).map_err(|e| e.to_string())?;
|
||||
let gz_decoder = GzDecoder::new(tar_gz);
|
||||
let mut archive = Archive::new(gz_decoder);
|
||||
|
||||
let mut extension_name = None;
|
||||
let mut extension_manifest = None;
|
||||
extract_extension_manifest(&mut archive)
|
||||
.map_err(|e| e.to_string())
|
||||
.and_then(|manifest| match manifest {
|
||||
Some(manifest) => {
|
||||
extension_name = manifest["name"].as_str().map(|s| s.to_string());
|
||||
extension_manifest = Some(manifest);
|
||||
Ok(())
|
||||
}
|
||||
None => Err("Manifest is None".to_string()),
|
||||
})?;
|
||||
|
||||
let extension_name = extension_name.ok_or("package.json not found in archive")?;
|
||||
let extension_dir = extensions_path.join(extension_name.clone());
|
||||
fs::create_dir_all(&extension_dir).map_err(|e| e.to_string())?;
|
||||
|
||||
let tar_gz = File::open(&path).map_err(|e| e.to_string())?;
|
||||
let gz_decoder = GzDecoder::new(tar_gz);
|
||||
let mut archive = Archive::new(gz_decoder);
|
||||
for entry in archive.entries().map_err(|e| e.to_string())? {
|
||||
let mut entry = entry.map_err(|e| e.to_string())?;
|
||||
let file_path = entry.path().map_err(|e| e.to_string())?;
|
||||
let components: Vec<_> = file_path.components().collect();
|
||||
if components.len() > 1 {
|
||||
let relative_path: PathBuf = components[1..].iter().collect();
|
||||
let target_path = extension_dir.join(relative_path);
|
||||
if let Some(parent) = target_path.parent() {
|
||||
fs::create_dir_all(parent).map_err(|e| e.to_string())?;
|
||||
}
|
||||
let _result = entry.unpack(&target_path).map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
|
||||
let main_entry = extension_manifest
|
||||
.as_ref()
|
||||
.and_then(|manifest| manifest["main"].as_str())
|
||||
.unwrap_or("index.js");
|
||||
let url = extension_dir.join(main_entry).to_string_lossy().to_string();
|
||||
|
||||
let new_extension = serde_json::json!({
|
||||
"url": url,
|
||||
"name": extension_name.clone(),
|
||||
"origin": extension_dir.to_string_lossy(),
|
||||
"active": true,
|
||||
"description": extension_manifest
|
||||
.as_ref()
|
||||
.and_then(|manifest| manifest["description"].as_str())
|
||||
.unwrap_or(""),
|
||||
"version": extension_manifest
|
||||
.as_ref()
|
||||
.and_then(|manifest| manifest["version"].as_str())
|
||||
.unwrap_or(""),
|
||||
"productName": extension_manifest
|
||||
.as_ref()
|
||||
.and_then(|manifest| manifest["productName"].as_str())
|
||||
.unwrap_or(""),
|
||||
});
|
||||
|
||||
extensions_list.push(new_extension);
|
||||
|
||||
println!("Installed extension to {:?}", extension_dir);
|
||||
}
|
||||
}
|
||||
fs::write(
|
||||
&extensions_json_path,
|
||||
serde_json::to_string_pretty(&extensions_list).map_err(|e| e.to_string())?,
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract_extension_manifest<R: Read>(
|
||||
archive: &mut Archive<R>,
|
||||
) -> Result<Option<serde_json::Value>, String> {
|
||||
let entry = archive
|
||||
.entries()
|
||||
.map_err(|e| e.to_string())?
|
||||
.filter_map(|e| e.ok()) // Ignore errors in individual entries
|
||||
.find(|entry| {
|
||||
if let Ok(file_path) = entry.path() {
|
||||
let path_str = file_path.to_string_lossy();
|
||||
path_str == "package/package.json" || path_str == "package.json"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(mut entry) = entry {
|
||||
let mut content = String::new();
|
||||
entry
|
||||
.read_to_string(&mut content)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let package_json: serde_json::Value =
|
||||
serde_json::from_str(&content).map_err(|e| e.to_string())?;
|
||||
return Ok(Some(package_json));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn setup_sidecar(app: &App) -> Result<(), String> {
|
||||
// Setup sidecar
|
||||
|
||||
let app_state = app.state::<AppState>();
|
||||
let mut sidecar_command = app.shell().sidecar("cortex-server").unwrap().args([
|
||||
"--start-server",
|
||||
"--port",
|
||||
"39291",
|
||||
"--config_file_path",
|
||||
app.app_handle()
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.unwrap()
|
||||
.join(".janrc")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
"--data_folder_path",
|
||||
app.app_handle()
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
"config",
|
||||
"--api_keys",
|
||||
app_state.inner().app_token.as_deref().unwrap_or(""),
|
||||
]);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
sidecar_command = sidecar_command.env("PATH", {
|
||||
let app_data_dir = app.app_handle().path().app_data_dir().unwrap();
|
||||
let dest = app_data_dir.to_str().unwrap();
|
||||
let path = std::env::var("PATH").unwrap_or_default();
|
||||
format!("{}{}{}", path, std::path::MAIN_SEPARATOR, dest)
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
sidecar_command = sidecar_command.env("LD_LIBRARY_PATH", {
|
||||
let app_data_dir = app.app_handle().path().app_data_dir().unwrap();
|
||||
let dest = app_data_dir.to_str().unwrap();
|
||||
let ld_library_path = std::env::var("LD_LIBRARY_PATH").unwrap_or_default();
|
||||
format!("{}{}{}", ld_library_path, std::path::MAIN_SEPARATOR, dest)
|
||||
});
|
||||
}
|
||||
|
||||
let (mut rx, mut _child) = sidecar_command.spawn().expect("Failed to spawn sidecar");
|
||||
tauri::async_runtime::spawn(async move {
|
||||
// read events such as stdout
|
||||
while let Some(event) = rx.recv().await {
|
||||
if let CommandEvent::Stdout(line_bytes) = event {
|
||||
let line = String::from_utf8_lossy(&line_bytes);
|
||||
println!("Outputs: {:?}", line)
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn copy_dir_all(src: PathBuf, dst: PathBuf) -> Result<(), String> {
|
||||
fs::create_dir_all(&dst).map_err(|e| e.to_string())?;
|
||||
println!("Copying from {:?} to {:?}", src, dst);
|
||||
for entry in fs::read_dir(src).map_err(|e| e.to_string())? {
|
||||
let entry = entry.map_err(|e| e.to_string())?;
|
||||
let ty = entry.file_type().map_err(|e| e.to_string())?;
|
||||
if ty.is_dir() {
|
||||
copy_dir_all(entry.path(), dst.join(entry.file_name())).map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
fs::copy(entry.path(), dst.join(entry.file_name())).map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn setup_engine_binaries(app: &App) -> Result<(), String> {
|
||||
// Copy engine binaries to app_data
|
||||
let app_data_dir = app.handle().path().app_data_dir().unwrap();
|
||||
let binaries_dir = app
|
||||
.handle()
|
||||
.path()
|
||||
.resource_dir()
|
||||
.unwrap()
|
||||
.join("binaries");
|
||||
let themes_dir = app
|
||||
.handle()
|
||||
.path()
|
||||
.resource_dir()
|
||||
.unwrap()
|
||||
.join("resources");
|
||||
|
||||
if let Err(e) = copy_dir_all(binaries_dir, app_data_dir.clone()) {
|
||||
eprintln!("Failed to copy binaries: {}", e);
|
||||
}
|
||||
if let Err(e) = copy_dir_all(themes_dir, app_data_dir.clone()) {
|
||||
eprintln!("Failed to copy themes: {}", e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -1,12 +1,8 @@
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
mod core;
|
||||
use core::setup::{self, setup_engine_binaries, setup_sidecar};
|
||||
|
||||
mod handlers;
|
||||
|
||||
use crate::handlers::cmd;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use tauri::{command, Manager, State};
|
||||
use tauri_plugin_shell::{process::CommandEvent, ShellExt};
|
||||
use tauri::{command, State};
|
||||
|
||||
struct AppState {
|
||||
app_token: Option<String>,
|
||||
@ -25,44 +21,29 @@ fn generate_app_token() -> String {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn copy_dir_all(src: PathBuf, dst: PathBuf) -> Result<(), String> {
|
||||
fs::create_dir_all(&dst).map_err(|e| e.to_string())?;
|
||||
println!("Copying from {:?} to {:?}", src, dst);
|
||||
for entry in fs::read_dir(src).map_err(|e| e.to_string())? {
|
||||
let entry = entry.map_err(|e| e.to_string())?;
|
||||
let ty = entry.file_type().map_err(|e| e.to_string())?;
|
||||
if ty.is_dir() {
|
||||
copy_dir_all(entry.path(), dst.join(entry.file_name())).map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
fs::copy(entry.path(), dst.join(entry.file_name())).map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
handlers::fs::join_path,
|
||||
handlers::fs::mkdir,
|
||||
handlers::fs::exists_sync,
|
||||
handlers::fs::readdir_sync,
|
||||
handlers::fs::read_file_sync,
|
||||
handlers::fs::rm,
|
||||
core::fs::join_path,
|
||||
core::fs::mkdir,
|
||||
core::fs::exists_sync,
|
||||
core::fs::readdir_sync,
|
||||
core::fs::read_file_sync,
|
||||
core::fs::rm,
|
||||
// App commands
|
||||
handlers::cmd::get_themes,
|
||||
handlers::cmd::get_app_configurations,
|
||||
handlers::cmd::get_active_extensions,
|
||||
handlers::cmd::get_user_home_path,
|
||||
handlers::cmd::update_app_configuration,
|
||||
handlers::cmd::get_jan_data_folder_path,
|
||||
handlers::cmd::get_jan_extensions_path,
|
||||
handlers::cmd::relaunch,
|
||||
handlers::cmd::open_app_directory,
|
||||
handlers::cmd::open_file_explorer,
|
||||
core::cmd::get_themes,
|
||||
core::cmd::get_app_configurations,
|
||||
core::cmd::get_active_extensions,
|
||||
core::cmd::get_user_home_path,
|
||||
core::cmd::update_app_configuration,
|
||||
core::cmd::get_jan_data_folder_path,
|
||||
core::cmd::get_jan_extensions_path,
|
||||
core::cmd::relaunch,
|
||||
core::cmd::open_app_directory,
|
||||
core::cmd::open_file_explorer,
|
||||
app_token,
|
||||
])
|
||||
.manage(AppState {
|
||||
@ -77,59 +58,14 @@ pub fn run() {
|
||||
)?;
|
||||
}
|
||||
|
||||
// Setup sidecar
|
||||
let app_state = app.state::<AppState>();
|
||||
let sidecar_command = app.shell().sidecar("cortex-server").unwrap().args([
|
||||
"--start-server",
|
||||
"--port",
|
||||
"39291",
|
||||
"--config_file_path",
|
||||
app.app_handle()
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.unwrap()
|
||||
.join(".janrc")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
"--data_folder_path",
|
||||
app.app_handle()
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
"config",
|
||||
"--api_keys",
|
||||
app_state.inner().app_token.as_deref().unwrap_or("")
|
||||
|
||||
]);
|
||||
let (mut rx, mut _child) = sidecar_command.spawn().expect("Failed to spawn sidecar");
|
||||
tauri::async_runtime::spawn(async move {
|
||||
// read events such as stdout
|
||||
while let Some(event) = rx.recv().await {
|
||||
if let CommandEvent::Stdout(line_bytes) = event {
|
||||
let line = String::from_utf8_lossy(&line_bytes);
|
||||
println!("Outputs: {:?}", line)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Install extensions
|
||||
if let Err(e) = cmd::install_extensions(app.handle().clone()) {
|
||||
if let Err(e) = setup::install_extensions(app.handle().clone()) {
|
||||
eprintln!("Failed to install extensions: {}", e);
|
||||
}
|
||||
|
||||
// Copy engine binaries to app_data
|
||||
let app_data_dir = app.app_handle().path().app_data_dir().unwrap();
|
||||
let binaries_dir = app.app_handle().path().resource_dir().unwrap().join("binaries");
|
||||
let themes_dir = app.app_handle().path().resource_dir().unwrap().join("resources");
|
||||
setup_sidecar(app).expect("Failed to setup sidecar");
|
||||
|
||||
if let Err(e) = copy_dir_all(binaries_dir, app_data_dir.clone()) {
|
||||
eprintln!("Failed to copy binaries: {}", e);
|
||||
}
|
||||
if let Err(e) = copy_dir_all(themes_dir, app_data_dir.clone()) {
|
||||
eprintln!("Failed to copy themes: {}", e);
|
||||
}
|
||||
setup_engine_binaries(app).expect("Failed to setup engine binaries");
|
||||
|
||||
Ok(())
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user