refactor and implement rpc commands

This commit is contained in:
llama 2025-10-18 09:58:58 +08:00
parent 572cbf1043
commit b04520a352
No known key found for this signature in database
GPG key ID: 0B7543854B9413C3

View file

@ -8,15 +8,16 @@ use anki_proto::launcher::ChooseVersionRequest;
use anki_proto::launcher::ChooseVersionResponse; use anki_proto::launcher::ChooseVersionResponse;
use anki_proto::launcher::GetLangsResponse; use anki_proto::launcher::GetLangsResponse;
use anki_proto::launcher::GetMirrorsResponse; use anki_proto::launcher::GetMirrorsResponse;
use anki_proto::launcher::GetVersionsResponse;
use anki_proto::launcher::I18nResourcesRequest; use anki_proto::launcher::I18nResourcesRequest;
use anki_proto::launcher::Mirror; use anki_proto::launcher::Mirror;
use anki_proto::launcher::Options; use anki_proto::launcher::Options;
use anki_proto::launcher::ZoomWebviewRequest; use anki_proto::launcher::ZoomWebviewRequest;
use anyhow::anyhow;
use anyhow::Context; use anyhow::Context;
use anyhow::Result; use anyhow::Result;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use tauri::AppHandle; use tauri::AppHandle;
use tauri::Emitter;
use tauri::Manager; use tauri::Manager;
use tauri::Runtime; use tauri::Runtime;
use tauri::WebviewWindow; use tauri::WebviewWindow;
@ -27,6 +28,9 @@ use crate::lang::setup_i18n;
use crate::lang::LANGS; use crate::lang::LANGS;
use crate::lang::LANGS_DEFAULT_REGION; use crate::lang::LANGS_DEFAULT_REGION;
use crate::lang::LANGS_WITH_REGIONS; use crate::lang::LANGS_WITH_REGIONS;
use crate::state::ExistingVersions;
use crate::state::State;
use crate::state::Versions;
use crate::uv; use crate::uv;
pub async fn i18n_resources<R: Runtime>( pub async fn i18n_resources<R: Runtime>(
@ -107,45 +111,40 @@ pub async fn get_options<R: Runtime>(
app: AppHandle<R>, app: AppHandle<R>,
_window: WebviewWindow<R>, _window: WebviewWindow<R>,
) -> Result<Options> { ) -> Result<Options> {
let state = app.state::<uv::State>(); let state = app.state::<State>();
let allow_betas = state.prerelease_marker.exists(); let options = (&state.normal()?.initial_options).into();
let download_caching = !state.no_cache_marker.exists(); Ok(options)
let mirror = if state.mirror_path.exists() {
Mirror::China
} else {
Mirror::Disabled
}
.into();
Ok(Options {
allow_betas,
download_caching,
mirror,
})
} }
pub async fn get_versions<R: Runtime>( pub async fn get_available_versions<R: Runtime>(
app: AppHandle<R>, app: AppHandle<R>,
_window: WebviewWindow<R>, _window: WebviewWindow<R>,
) -> Result<GetVersionsResponse> { ) -> Result<Versions> {
let state = (*app.state::<uv::State>()).clone(); let state = app.state::<State>();
// TODO: why... let state = state.normal()?;
let mut state1 = state.clone(); let mut rx = state.available_versions.clone().unwrap();
rx.changed().await.unwrap();
let x = rx.borrow();
match x.as_ref().unwrap() {
Ok(versions) => Ok(versions.clone()),
// TODO: errors are passed as strings to the web
Err(e) => Err(anyhow!("{e:?}")),
}
}
let releases_fut = tauri::async_runtime::spawn_blocking(move || uv::get_releases(&state)); pub async fn get_existing_versions<R: Runtime>(
let check_fut = tauri::async_runtime::spawn_blocking(move || uv::check_versions(&mut state1)); app: AppHandle<R>,
_window: WebviewWindow<R>,
let (releases, check) = futures::future::join(releases_fut, check_fut).await; ) -> Result<ExistingVersions> {
// TODO: handle errors properly let state = app.state::<State>();
let uv::Releases { latest, all } = releases.unwrap().unwrap(); let state = state.normal()?;
let (current, previous) = check.unwrap().unwrap(); let mut rx = state.current_versions.clone().unwrap();
rx.changed().await.unwrap();
Ok(GetVersionsResponse { let x = rx.borrow();
latest, match x.as_ref().unwrap() {
all, Ok(versions) => Ok(versions.clone()),
current, Err(e) => Err(anyhow!("{e:?}")),
previous, }
})
} }
pub async fn choose_version<R: Runtime>( pub async fn choose_version<R: Runtime>(
@ -153,46 +152,59 @@ pub async fn choose_version<R: Runtime>(
_window: WebviewWindow<R>, _window: WebviewWindow<R>,
input: ChooseVersionRequest, input: ChooseVersionRequest,
) -> Result<ChooseVersionResponse> { ) -> Result<ChooseVersionResponse> {
let state = (*app.state::<uv::State>()).clone(); let state = app.state::<State>();
let version = input.version.clone(); let state = state.normal()?;
let paths = state.paths.clone();
tauri::async_runtime::spawn_blocking(move || -> Result<()> { tauri::async_runtime::spawn_blocking(move || {
if let Some(options) = input.options { if let Some(options) = input.options {
uv::set_allow_betas(&state, options.allow_betas)?; uv::set_allow_betas(&paths, options.allow_betas)?;
uv::set_cache_enabled(&state, options.download_caching)?; uv::set_cache_enabled(&paths, options.download_caching)?;
uv::set_mirror(&state, options.mirror != Mirror::Disabled as i32)?; uv::set_mirror(&paths, options.mirror != Mirror::Disabled as i32)?;
} }
if !input.keep_existing || state.pyproject_modified_by_user { let version = input.version;
let on_pty_data = move |data| {
let _ = app.emit("pty-data", data);
};
if !input.keep_existing || paths.pyproject_modified_by_user {
// install or resync // install or resync
let res = uv::handle_version_install_or_update( uv::handle_version_install_or_update(
app.clone(), &paths,
&state, &version,
&input.version,
input.keep_existing, input.keep_existing,
); input.current.as_deref(),
println!("handle_version_install_or_update: {res:?}"); on_pty_data,
res?; )?;
} }
uv::post_install(&state)?; let warming_up = paths.post_install()?;
// TODO: show some sort of notification before closing Ok(ChooseVersionResponse {
// if let Some(window) = app.get_webview_window("main") { version,
// let _ = window.destroy(); warming_up,
// } })
// // app.exit can't be called from the main thread
// app.exit(0);
Ok(())
}) })
.await??; .await?
}
Ok(ChooseVersionResponse { version }) pub async fn launch_anki<R: Runtime>(app: AppHandle<R>, _window: WebviewWindow<R>) -> Result<()> {
app.state::<State>().paths()?.launch_anki()
}
pub async fn exit<R: Runtime>(app: AppHandle<R>, window: WebviewWindow<R>) -> Result<()> {
tauri::async_runtime::spawn_blocking(move || {
let _ = window.destroy();
// can't be called from the main thread
app.exit(0);
});
Ok(())
} }
/// NOTE: [zoomHotkeysEnabled](https://v2.tauri.app/reference/config/#zoomhotkeysenabled) exists /// NOTE: [zoomHotkeysEnabled](https://v2.tauri.app/reference/config/#zoomhotkeysenabled) exists
/// but the polyfill it uses on lin doesn't allow regular scrolling /// but the polyfill it uses on linux doesn't allow regular scrolling
pub async fn zoom_webview<R: Runtime>( pub async fn zoom_webview<R: Runtime>(
_app: AppHandle<R>, _app: AppHandle<R>,
window: WebviewWindow<R>, window: WebviewWindow<R>,