Huakun Shen ed87fc6c12
App Setup (#2)
* chore: add vendor submodules

* feat: add packages for db,ci,schema,api,jarvis cmds

* feat: add tauri-jarvis-plugin

* feat: implement extension commands list

* fix(desktop): import path errors after packages refactor

* chore: add self signed cert

* fix: prevent prerender for desktop

* fix(desktop): desktop sveltekit static build, use csr for dynamic route

* feat: add error handling page and components

* refactor: component lib

* refactor: move more types, functions and components out of desktop

* refactor(ui): more refactor

* refactor(ui): move store components to @kksh/ui

* ci: add CI for build & test

* refactor: rename @kksh/extensions to @kksh/extension

* ci: add 2 more ci

* ci: fix

* fix: CI env var

* chore: add changeset

* feat: implement extension store item detail view

* feat: implement extension store install, uninstall, upgrade

* format

* revert: upgradable logic, the new one doesn't work yet

* refactor: make @kksh/ui dependent only on @kksh/api

Reason: @kksh/ui may be published later for building website, all its dependency packages must be also published. To avoid trouble it should be standalone, depend only on packages already published

* refactor: cleanup

* fixed: some typescript error

* chore: got typedoc working on @kksh/api

* ci: disable manifest schema upload CI on push
2024-11-03 13:54:44 -05:00

242 lines
10 KiB
Rust

use std::{path::PathBuf, sync::Mutex};
mod setup;
pub mod utils;
use log;
#[cfg(target_os = "macos")]
use tauri::ActivationPolicy;
use tauri::Manager;
use tauri_plugin_deep_link::DeepLinkExt;
use tauri_plugin_jarvis::{
db::JarvisDB,
server::Protocol,
utils::{
path::{get_default_extensions_dir, get_kunkun_db_path},
settings::AppSettings,
},
};
pub use tauri_plugin_log::fern::colors::ColoredLevelConfig;
use tauri_plugin_store::{StoreBuilder, StoreExt};
use utils::server::tauri_file_server;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let context = tauri::generate_context!();
let mut builder = tauri::Builder::default();
#[cfg(debug_assertions)]
{
println!("Install crabnebula devtools");
// let devtools = tauri_plugin_devtools::init(); // initialize the plugin as early as possible
// builder = builder.plugin(devtools);
}
// #[cfg(not(debug_assertions))]
// {
// builder = builder.plugin(
// tauri_plugin_log::Builder::new()
// .targets(utils::log::get_log_targets())
// .level(utils::log::get_log_level())
// .filter(|metadata| !metadata.target().starts_with("mdns_sd"))
// .with_colors(ColoredLevelConfig::default())
// .max_file_size(10_000_000) // max 10MB
// .format(|out, message, record| {
// out.finish(format_args!(
// "{}[{}] {}",
// chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
// // record.target(),
// record.level(),
// message
// ))
// })
// .build(),
// );
// }
let shell_unlocked = true;
builder = builder
.plugin(tauri_plugin_single_instance::init(|app, args, cwd| {
let _ = app
.get_webview_window("main")
.expect("no main window")
.set_focus();
}))
.plugin(
tauri_plugin_log::Builder::new()
.targets(utils::log::get_log_targets())
.level(utils::log::get_log_level())
.filter(|metadata| !metadata.target().starts_with("mdns_sd"))
.with_colors(ColoredLevelConfig::default())
.max_file_size(10_000_000) // max 10MB
.format(|out, message, record| {
out.finish(format_args!(
"{}[{}] {}",
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
// record.target(),
record.level(),
message
))
})
.build(),
)
.plugin(tauri_plugin_cli::init())
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_upload::init())
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_store::Builder::default().build())
.plugin(tauri_plugin_global_shortcut::Builder::new().build())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_shellx::init(shell_unlocked))
.plugin(tauri_plugin_jarvis::init())
.plugin(tauri_plugin_clipboard::init())
.plugin(tauri_plugin_network::init())
.plugin(tauri_plugin_system_info::init());
let app = builder
.register_uri_scheme_protocol("appicon", |_app, request| {
let url = &request.uri().path()[1..];
let url = urlencoding::decode(url).unwrap().to_string();
let path = PathBuf::from(url);
return tauri_plugin_jarvis::utils::icns::load_icon(path);
})
.register_uri_scheme_protocol("ext", |app, request| {
let app_handle = app.app_handle();
// app_handle.
let win_label = app.webview_label();
let jarvis_state = app_handle.state::<tauri_plugin_jarvis::JarvisState>();
let window_ext_map = jarvis_state.window_label_ext_map.lock().unwrap();
match window_ext_map.get(win_label) {
Some(ext) => {
// let app_state = app_handle.state::<tauri_plugin_jarvis::model::app_state::AppState>();
// let extension_path = app_state.extension_path.lock().unwrap().clone();
// tauri_file_server(app_handle, request, extension_path)
tauri_file_server(app_handle, request, ext.path.clone(), ext.dist.clone())
}
None => tauri::http::Response::builder()
.status(tauri::http::StatusCode::NOT_FOUND)
.header("Access-Control-Allow-Origin", "*")
.body("Extension Not Found".as_bytes().to_vec())
.unwrap(),
}
})
.setup(|app| {
setup::window::setup_window(app.handle());
setup::tray::create_tray(app.handle())?;
#[cfg(all(not(target_os = "macos"), debug_assertions))]
{
app.deep_link().register("kunkun")?;
}
// setup::deeplink::setup_deeplink(app);
// #[cfg(all(target_os = "macos", debug_assertions))]
// app.set_activation_policy(ActivationPolicy::Accessory);
// let mut store = StoreBuilder::new("appConfig.bin").build(app.handle().clone());
// let store = app.handle().store_builder("appConfig.json").build()?;
// let app_settings = match AppSettings::load_from_store(&store) {
// Ok(settings) => settings,
// Err(_) => AppSettings::default(),
// };
// let dev_extension_path: Option<PathBuf> = app_settings.dev_extension_path.clone();
let my_port = tauri_plugin_network::network::scan::find_available_port_from_list(
tauri_plugin_jarvis::server::CANDIDATE_PORTS.to_vec(),
)
.unwrap();
log::info!("Jarvis Server Port: {}", my_port);
// log::info!(
// "App Settings Dev Extension Path: {:?}",
// app_settings.dev_extension_path.clone(),
// );
app.manage(tauri_plugin_jarvis::server::http::Server::new(
app.handle().clone(),
my_port,
Protocol::Http,
// Protocol::Https,
));
app.manage(tauri_plugin_jarvis::model::app_state::AppState {});
tauri_plugin_jarvis::setup::server::setup_server(app.handle())?; // start the server
let mdns = tauri_plugin_jarvis::setup::peer_discovery::setup_mdns(my_port)?;
tauri_plugin_jarvis::setup::peer_discovery::handle_mdns_service_evt(
app.handle(),
mdns.browse()?,
);
/* ----------------------------- Database Setup ----------------------------- */
// setup::db::setup_db(app)?;
/* ------------------------- Clipboard History Setup ------------------------ */
let db_path = get_kunkun_db_path(app.app_handle())?;
let db_key: Option<String> = None;
let jarvis_db = JarvisDB::new(db_path.clone(), db_key.clone())?;
// The clipboard extension should be created in setup_db, ext is guaranteed to be Some
let ext = jarvis_db.get_unique_extension_by_identifier(
tauri_plugin_jarvis::constants::KUNKUN_CLIPBOARD_EXT_IDENTIFIER,
)?;
app.manage(
tauri_plugin_jarvis::model::clipboard_history::ClipboardHistory::new(
jarvis_db,
ext.unwrap().ext_id,
),
);
let (clipboard_update_tx, clipboard_update_rx) = tokio::sync::broadcast::channel::<
tauri_plugin_jarvis::model::clipboard_history::Record,
>(10);
/* --------------------------- Cliipboard Listener -------------------------- */
setup::clipboard::setup_clipboard_listener(
&app.app_handle(),
clipboard_update_tx.clone(),
);
app.state::<tauri_plugin_clipboard::Clipboard>()
.start_monitor(app.app_handle().clone())?;
setup::clipboard::setup_clipboard_update_handler(app.app_handle(), clipboard_update_rx);
#[cfg(debug_assertions)] // only include this code on debug builds
{
let window = app.get_webview_window("main").unwrap();
window.open_devtools();
// window.close_devtools();
}
let main_window = app.get_webview_window("main").unwrap();
std::thread::spawn(move || {
// this is a backup plan, if frontend is not properly loaded, show() will not be called, then we need to call it manually from rust after a long delay
std::thread::sleep(std::time::Duration::from_secs(1));
main_window.show().unwrap();
});
Ok(())
})
.build(context)
.expect("error while running tauri application");
app.run(|_app_handle, event| match event {
// tauri::RunEvent::Exit => todo!(),
// tauri::RunEvent::ExitRequested { code, api, .. } => todo!(),
// tauri::RunEvent::WindowEvent { label, event, .. } => todo!(),
// tauri::RunEvent::WebviewEvent { label, event, .. } => todo!(),
// tauri::RunEvent::Ready => todo!(),
// tauri::RunEvent::Resumed => todo!(),
// tauri::RunEvent::MainEventsCleared => todo!(),
// tauri::RunEvent::Opened { urls } => todo!(),
// tauri::RunEvent::MenuEvent(_) => todo!(),
// tauri::RunEvent::TrayIconEvent(_) => todo!(),
#[cfg(target_os = "macos")]
tauri::RunEvent::Reopen {
has_visible_windows,
..
} => {
_app_handle
.webview_windows()
.iter()
.for_each(|(label, window)| {
window.show().unwrap();
});
// let main_window = _app_handle.get_webview_window("main").unwrap();
// main_window.show().unwrap();
}
_ => {}
});
}