diff --git a/proto/anki/launcher.proto b/proto/anki/launcher.proto new file mode 100644 index 000000000..d16bc760c --- /dev/null +++ b/proto/anki/launcher.proto @@ -0,0 +1,87 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.launcher; + +import "anki/generic.proto"; + +service LauncherService { + rpc I18nResources(I18nResourcesRequest) returns (generic.Json); + rpc GetLangs(generic.Empty) returns (GetLangsResponse); + rpc SetLang(generic.String) returns (generic.Empty); + rpc GetVersions(generic.Empty) returns (GetVersionsResponse); + rpc ChooseVersion(ChooseVersionRequest) returns (ChooseVersionResponse); + rpc GetOptions(generic.Empty) returns (Options); + rpc GetMirrors(generic.Empty) returns (GetMirrorsResponse); + rpc WindowReady(generic.Empty) returns (generic.Empty); + rpc ZoomWebview(ZoomWebviewRequest) returns (generic.Empty); +} + +// TODO: this should not be necessary +service BackendLauncherService {} + +// TODO: codegen +enum Event { + TERM_INPUT = 0; + WINDOWS_READY = 1; +} + +message I18nResourcesRequest { + repeated string modules = 1; +} + +message I18nResourcesResponse { + repeated string langs = 1; + repeated string resources = 2; +} + +message GetLangsResponse { + message Pair { + string name = 1; + string locale = 2; + } + string user_locale = 1; + repeated Pair langs = 2; +} + +enum Mirror { + DISABLED = 0; + CHINA = 1; +} + +message GetMirrorsResponse { + message Pair { + Mirror mirror = 1; + string name = 2; + } + repeated Pair mirrors = 1; +} + +message Options { + bool allow_betas = 1; + bool download_caching = 2; + Mirror mirror = 3; +} + +message GetVersionsResponse { + repeated string all = 1; + repeated string latest = 2; + optional string current = 3; + optional string previous = 4; +} + +message ChooseVersionRequest { + string version = 1; + bool keep_existing = 2; + Options options = 3; +} + +message ChooseVersionResponse { + string version = 1; +} + +message ZoomWebviewRequest { + float scale_factor = 1; +} diff --git a/rslib/proto/build.rs b/rslib/proto/build.rs index feb84d410..4ede26409 100644 --- a/rslib/proto/build.rs +++ b/rslib/proto/build.rs @@ -14,8 +14,16 @@ fn main() -> Result<()> { let pool = rust::write_rust_protos(descriptors_path)?; let (_, services) = get_services(&pool); + + let (services, launcher_services): (Vec<_>, Vec<_>) = services + .into_iter() + .partition(|s| !s.name.trim_start_matches("Backend").starts_with("Launcher")); + python::write_python_interface(&services)?; - typescript::write_ts_interface(&services)?; + typescript::write_ts_interface(&services, false)?; + + // for launcher-gui + typescript::write_ts_interface(&launcher_services, true)?; Ok(()) } diff --git a/rslib/proto/rust.rs b/rslib/proto/rust.rs index 85834f19f..61e12ba61 100644 --- a/rslib/proto/rust.rs +++ b/rslib/proto/rust.rs @@ -49,6 +49,7 @@ pub fn write_rust_protos(descriptors_path: PathBuf) -> Result { "ImportAnkiPackageUpdateCondition", "#[derive(serde::Deserialize, serde::Serialize)]", ) + .type_attribute(".anki.launcher.Mirror", "#[derive(strum::EnumIter)]") .compile_protos(paths.as_slice(), &[proto_dir]) .context("prost build")?; diff --git a/rslib/proto/src/lib.rs b/rslib/proto/src/lib.rs index 86d7d1580..7396192e3 100644 --- a/rslib/proto/src/lib.rs +++ b/rslib/proto/src/lib.rs @@ -37,3 +37,4 @@ protobuf!(stats, "stats"); protobuf!(sync, "sync"); protobuf!(tags, "tags"); protobuf!(ankihub, "ankihub"); +protobuf!(launcher, "launcher"); diff --git a/rslib/proto/typescript.rs b/rslib/proto/typescript.rs index 4e941a0ca..66cc7e590 100644 --- a/rslib/proto/typescript.rs +++ b/rslib/proto/typescript.rs @@ -13,7 +13,7 @@ use anyhow::Result; use inflections::Inflect; use itertools::Itertools; -pub(crate) fn write_ts_interface(services: &[BackendService]) -> Result<()> { +pub(crate) fn write_ts_interface(services: &[BackendService], is_launcher: bool) -> Result<()> { let root = Path::new("../../out/ts/lib/generated"); create_dir_all(root)?; @@ -29,13 +29,17 @@ pub(crate) fn write_ts_interface(services: &[BackendService]) -> Result<()> { let method = MethodDetails::from_method(method); record_referenced_type(&mut referenced_packages, &method.input_type); record_referenced_type(&mut referenced_packages, &method.output_type); - write_ts_method(&method, &mut ts_out); + write_ts_method(&method, &mut ts_out, is_launcher); } } let imports = imports(referenced_packages); write_file_if_changed( - root.join("backend.ts"), + root.join(if is_launcher { + "backend-launcher.ts" + } else { + "backend.ts" + }), format!("{}{}{}", ts_header(), imports, ts_out), )?; @@ -75,12 +79,19 @@ fn write_ts_method( comments, }: &MethodDetails, out: &mut String, + is_launcher: bool, ) { let comments = format_comments(comments); + let proto_method_name = method_name; + let options = if is_launcher { + "{ ...options, customProtocol: true }" + } else { + "options" + }; writeln!( out, r#"{comments}export async function {method_name}(input: PlainMessage<{input_type}>, options?: PostProtoOptions): Promise<{output_type}> {{ - return await postProto("{method_name}", new {input_type}(input), {output_type}, options); + return await postProto("{proto_method_name}", new {input_type}(input), {output_type}, {options}); }}"# ).unwrap() } diff --git a/rslib/rust_interface.rs b/rslib/rust_interface.rs index 6861df7dc..fb3a0ec96 100644 --- a/rslib/rust_interface.rs +++ b/rslib/rust_interface.rs @@ -20,14 +20,20 @@ pub fn write_rust_interface(pool: &DescriptorPool) -> Result<()> { let mut buf = String::new(); buf.push_str("use crate::error::Result; use prost::Message;"); + // TODO: we're misusing this for the launcher let (col_services, backend_services) = get_services(pool); let col_services = col_services .into_iter() - .filter(|s| s.name != "FrontendService") + .filter(|s| !matches!(&*s.name, "FrontendService" | "LauncherService")) .collect_vec(); let backend_services = backend_services .into_iter() - .filter(|s| s.name != "BackendFrontendService") + .filter(|s| { + !matches!( + &*s.name, + "BackendFrontendService" | "BackendLauncherService" + ) + }) .collect_vec(); render_collection_services(&col_services, &mut buf)?;