# Conflicts: # src-tauri/src/core/setup.rs # src-tauri/src/lib.rs # web-app/src/hooks/useChat.ts
214 lines
9.1 KiB
Rust
214 lines
9.1 KiB
Rust
mod core;
|
|
use core::{
|
|
app::commands::get_jan_data_folder_path,
|
|
downloads::models::DownloadManagerState,
|
|
mcp::helpers::clean_up_mcp_servers,
|
|
setup::{self, setup_mcp},
|
|
state::AppState,
|
|
};
|
|
use jan_utils::generate_app_token;
|
|
use std::{collections::HashMap, sync::Arc};
|
|
use tauri::{Emitter, Manager, RunEvent};
|
|
use tauri_plugin_llamacpp::cleanup_llama_processes;
|
|
use tauri_plugin_store::StoreExt;
|
|
use tokio::sync::Mutex;
|
|
|
|
#[cfg_attr(all(mobile, any(target_os = "android", target_os = "ios")), tauri::mobile_entry_point)]
|
|
pub fn run() {
|
|
let mut builder = tauri::Builder::default();
|
|
#[cfg(desktop)]
|
|
{
|
|
builder = builder.plugin(tauri_plugin_single_instance::init(|_app, argv, _cwd| {
|
|
println!("a new app instance was opened with {argv:?} and the deep link event was already triggered");
|
|
// when defining deep link schemes at runtime, you must also check `argv` here
|
|
}));
|
|
}
|
|
|
|
let mut app_builder = builder
|
|
.plugin(tauri_plugin_os::init())
|
|
.plugin(tauri_plugin_dialog::init())
|
|
.plugin(tauri_plugin_opener::init())
|
|
.plugin(tauri_plugin_http::init())
|
|
.plugin(tauri_plugin_store::Builder::new().build())
|
|
.plugin(tauri_plugin_shell::init())
|
|
.plugin(tauri_plugin_llamacpp::init());
|
|
|
|
#[cfg(feature = "deep-link")]
|
|
{
|
|
app_builder = app_builder.plugin(tauri_plugin_deep_link::init());
|
|
}
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
{
|
|
app_builder = app_builder.plugin(tauri_plugin_hardware::init());
|
|
}
|
|
|
|
let app = app_builder
|
|
.invoke_handler(tauri::generate_handler![
|
|
// FS commands - Deperecate soon
|
|
core::filesystem::commands::join_path,
|
|
core::filesystem::commands::mkdir,
|
|
core::filesystem::commands::exists_sync,
|
|
core::filesystem::commands::readdir_sync,
|
|
core::filesystem::commands::read_file_sync,
|
|
core::filesystem::commands::rm,
|
|
core::filesystem::commands::mv,
|
|
core::filesystem::commands::file_stat,
|
|
core::filesystem::commands::write_file_sync,
|
|
core::filesystem::commands::write_yaml,
|
|
core::filesystem::commands::read_yaml,
|
|
core::filesystem::commands::decompress,
|
|
// App configuration commands
|
|
core::app::commands::get_app_configurations,
|
|
core::app::commands::get_user_home_path,
|
|
core::app::commands::update_app_configuration,
|
|
core::app::commands::get_jan_data_folder_path,
|
|
core::app::commands::get_configuration_file_path,
|
|
core::app::commands::default_data_folder_path,
|
|
core::app::commands::change_app_data_folder,
|
|
core::app::commands::app_token,
|
|
// Extension commands
|
|
core::extensions::commands::get_jan_extensions_path,
|
|
core::extensions::commands::install_extensions,
|
|
core::extensions::commands::get_active_extensions,
|
|
// System commands
|
|
core::system::commands::relaunch,
|
|
core::system::commands::open_app_directory,
|
|
core::system::commands::open_file_explorer,
|
|
core::system::commands::factory_reset,
|
|
core::system::commands::read_logs,
|
|
core::system::commands::is_library_available,
|
|
// Server commands
|
|
core::server::commands::start_server,
|
|
core::server::commands::stop_server,
|
|
core::server::commands::get_server_status,
|
|
// MCP commands
|
|
core::mcp::commands::get_tools,
|
|
core::mcp::commands::call_tool,
|
|
core::mcp::commands::cancel_tool_call,
|
|
core::mcp::commands::restart_mcp_servers,
|
|
core::mcp::commands::get_connected_servers,
|
|
core::mcp::commands::save_mcp_configs,
|
|
core::mcp::commands::get_mcp_configs,
|
|
core::mcp::commands::activate_mcp_server,
|
|
core::mcp::commands::deactivate_mcp_server,
|
|
core::mcp::commands::reset_mcp_restart_count,
|
|
// Threads
|
|
core::threads::commands::list_threads,
|
|
core::threads::commands::create_thread,
|
|
core::threads::commands::modify_thread,
|
|
core::threads::commands::delete_thread,
|
|
core::threads::commands::list_messages,
|
|
core::threads::commands::create_message,
|
|
core::threads::commands::modify_message,
|
|
core::threads::commands::delete_message,
|
|
core::threads::commands::get_thread_assistant,
|
|
core::threads::commands::create_thread_assistant,
|
|
core::threads::commands::modify_thread_assistant,
|
|
// Download
|
|
core::downloads::commands::download_files,
|
|
core::downloads::commands::cancel_download_task,
|
|
])
|
|
.manage(AppState {
|
|
app_token: Some(generate_app_token()),
|
|
mcp_servers: Arc::new(Mutex::new(HashMap::new())),
|
|
download_manager: Arc::new(Mutex::new(DownloadManagerState::default())),
|
|
mcp_restart_counts: Arc::new(Mutex::new(HashMap::new())),
|
|
mcp_active_servers: Arc::new(Mutex::new(HashMap::new())),
|
|
mcp_successfully_connected: Arc::new(Mutex::new(HashMap::new())),
|
|
server_handle: Arc::new(Mutex::new(None)),
|
|
tool_call_cancellations: Arc::new(Mutex::new(HashMap::new())),
|
|
})
|
|
.setup(|app| {
|
|
app.handle().plugin(
|
|
tauri_plugin_log::Builder::default()
|
|
.level(log::LevelFilter::Debug)
|
|
.targets([
|
|
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Stdout),
|
|
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Webview),
|
|
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Folder {
|
|
path: get_jan_data_folder_path(app.handle().clone()).join("logs"),
|
|
file_name: Some("app".to_string()),
|
|
}),
|
|
])
|
|
.build(),
|
|
)?;
|
|
#[cfg(not(any(target_os = "ios", target_os = "android")))]
|
|
app.handle().plugin(tauri_plugin_updater::Builder::new().build())?;
|
|
|
|
// Start migration
|
|
let mut store_path = get_jan_data_folder_path(app.handle().clone());
|
|
store_path.push("store.json");
|
|
let store = app
|
|
.handle()
|
|
.store(store_path)
|
|
.expect("Store not initialized");
|
|
let stored_version = store
|
|
.get("version")
|
|
.and_then(|v| v.as_str().map(String::from))
|
|
.unwrap_or_default();
|
|
let app_version = app
|
|
.config()
|
|
.version
|
|
.clone()
|
|
.unwrap_or_else(|| "".to_string());
|
|
// Migrate extensions
|
|
if let Err(e) =
|
|
setup::install_extensions(app.handle().clone(), stored_version != app_version)
|
|
{
|
|
log::error!("Failed to install extensions: {}", e);
|
|
}
|
|
|
|
// Migrate MCP servers
|
|
if let Err(e) = setup::migrate_mcp_servers(app.handle().clone(), store.clone()) {
|
|
log::error!("Failed to migrate MCP servers: {}", e);
|
|
}
|
|
|
|
// Store the new app version
|
|
store.set("version", serde_json::json!(app_version));
|
|
store.save().expect("Failed to save store");
|
|
// Migration completed
|
|
|
|
#[cfg(desktop)]
|
|
if option_env!("ENABLE_SYSTEM_TRAY_ICON").unwrap_or("false") == "true" {
|
|
log::info!("Enabling system tray icon");
|
|
let _ = setup::setup_tray(app);
|
|
}
|
|
|
|
#[cfg(all(feature = "deep-link", any(windows, target_os = "linux")))]
|
|
{
|
|
use tauri_plugin_deep_link::DeepLinkExt;
|
|
app.deep_link().register_all()?;
|
|
}
|
|
setup_mcp(app);
|
|
Ok(())
|
|
})
|
|
.build(tauri::generate_context!())
|
|
.expect("error while running tauri application");
|
|
|
|
// Handle app lifecycle events
|
|
app.run(|app, event| match event {
|
|
RunEvent::Exit => {
|
|
// This is called when the app is actually exiting (e.g., macOS dock quit)
|
|
// We can't prevent this, so run cleanup quickly
|
|
let app_handle = app.clone();
|
|
tokio::task::block_in_place(|| {
|
|
tauri::async_runtime::block_on(async {
|
|
// Hide window immediately (not available on mobile platforms)
|
|
if let Some(window) = app_handle.get_webview_window("main") {
|
|
#[cfg(not(any(target_os = "ios", target_os = "android")))]
|
|
{ let _ = window.hide(); }
|
|
let _ = window.emit("kill-mcp-servers", ());
|
|
}
|
|
|
|
// Quick cleanup with shorter timeout
|
|
let state = app_handle.state::<AppState>();
|
|
let _ = clean_up_mcp_servers(state).await;
|
|
let _ = cleanup_llama_processes(app.clone()).await;
|
|
});
|
|
});
|
|
}
|
|
_ => {}
|
|
});
|
|
}
|