From 99155d1e5b46c00f1c38aa29494b44afb13e00a1 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 12:49:07 +0100 Subject: [PATCH 01/15] impl From reqwest::Error for ChorusError --- src/errors.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/errors.rs b/src/errors.rs index 4099a6b..7494433 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,6 @@ //! Contains all the errors that can be returned by the library. use custom_error::custom_error; +use url::Url; use crate::types::WebSocketEvent; @@ -44,6 +45,18 @@ custom_error! { InvalidArguments{error: String} = "Invalid arguments were provided. Error: {error}" } +impl From for ChorusError { + fn from(value: reqwest::Error) -> Self { + ChorusError::RequestFailed { + url: match value.url() { + Some(url) => url.to_string(), + None => "None".to_string(), + }, + error: value.to_string(), + } + } +} + custom_error! { #[derive(PartialEq, Eq)] pub ObserverError From ceac04201c95791feec70d8e42879a6f0087aa77 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 12:49:22 +0100 Subject: [PATCH 02/15] impl from_root_domain for UrlBundle --- src/lib.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 71e0553..3333bf0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,9 +104,12 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read #[cfg(all(feature = "rt", feature = "rt_multi_thread"))] compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time"); +use errors::ChorusResult; use serde::{Deserialize, Serialize}; use url::{ParseError, Url}; +use crate::errors::ChorusError; + #[cfg(feature = "client")] pub mod api; pub mod errors; @@ -168,7 +171,7 @@ impl UrlBundle { let url_fmt = format!("http://{}", url); return UrlBundle::parse_url(url_fmt); } - Err(_) => panic!("Invalid URL"), + Err(_) => panic!("Invalid URL"), // TODO: should not panic here }; // if the last character of the string is a slash, remove it. let mut url_string = url.to_string(); @@ -177,6 +180,52 @@ impl UrlBundle { } url_string } + + /// Performs a few HTTP requests to try and retrieve a `UrlBundle` from an instances' root domain. + /// The method tries to retrieve the `UrlBundle` via these three strategies, in order: + /// - GET: `$url/.well-known/spacebar` -> Retrieve UrlBundle via `$wellknownurl/api/policies/instance/domains` + /// - GET: `$url/api/policies/instance/domains` + /// - GET: `$url/policies/instance/domains` + /// + /// The URL stored at `.well-known/spacebar` is the instances' API endpoint. The API + /// stores the CDN and WSS URLs under the `$api/policies/instance/domains` endpoint. If all three + /// of the above approaches fail, it is very likely that the instance is misconfigured, unreachable, or that + /// a wrong URL was provided. + pub async fn from_root_domain(url: &str) -> ChorusResult { + let parsed = UrlBundle::parse_url(url.to_string()); + let client = reqwest::Client::new(); + let request_wellknown = client + .get(format!("{}/.well-known/spacebar", &parsed)) + .header(http::header::ACCEPT, "application/json") + .build()?; + let response_wellknown = client.execute(request_wellknown).await?; + if response_wellknown.status().is_success() { + let body = response_wellknown.json::().await?.api; + UrlBundle::from_api_url(&body).await + } else { + if let Ok(response_slash_api) = + UrlBundle::from_api_url(&format!("{}/api/policies/instance/domains", url)).await + { + return Ok(response_slash_api); + } + if let Ok(response_api) = + UrlBundle::from_api_url(&format!("{}/policies/instance/domains", url)).await + { + Ok(response_api) + } else { + Err(ChorusError::RequestFailed { url: url.to_string(), error: "Could not retrieve UrlBundle from url after trying 3 different approaches. Check the provided Url and if the instance is reachable.".to_string() } ) + } + } + } + + async fn from_api_url(url: &str) -> ChorusResult { + todo!() + } +} + +#[derive(Deserialize)] +struct WellKnownResponse { + pub(crate) api: String, } #[cfg(test)] From 9bec639634b9f46539b664cf11eedfedf789ea4d Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 12:51:34 +0100 Subject: [PATCH 03/15] clean up imports --- src/errors.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/errors.rs b/src/errors.rs index 7494433..c20ac64 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,5 @@ //! Contains all the errors that can be returned by the library. use custom_error::custom_error; -use url::Url; use crate::types::WebSocketEvent; From 25a09c3980455b18255c170011ee8c6497835ecc Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 13:04:02 +0100 Subject: [PATCH 04/15] Create domains_config, create Domains struct --- .../config/types/domains_configuration.rs | 29 +++++++++++++++++++ src/types/config/types/mod.rs | 1 + 2 files changed, 30 insertions(+) create mode 100644 src/types/config/types/domains_configuration.rs diff --git a/src/types/config/types/domains_configuration.rs b/src/types/config/types/domains_configuration.rs new file mode 100644 index 0000000..297b827 --- /dev/null +++ b/src/types/config/types/domains_configuration.rs @@ -0,0 +1,29 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Eq, PartialEq, Hash, Clone, Debug)] +/// Represents the result of the `$rooturl/.well-known/spacebar` endpoint. +/// +/// See for more information. +pub struct WellKnownResponse { + pub api: String, +} + +#[derive(Deserialize, Serialize, Eq, PartialEq, Hash, Clone, Debug)] +#[serde(rename_all = "camelCase")] +/// Represents the result of the `$api/policies/instance/domains` endpoint. +pub struct Domains { + pub cdn: String, + pub gateway: String, + pub api_endpoint: String, + pub default_api_version: String, +} + +impl std::fmt::Display for Domains { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{{\n\tCDN URL: {},\n\tGateway URL: {},\n\tAPI Endpoint: {},\n\tDefault API Version: {}\n}}", + self.cdn, self.gateway, self.api_endpoint, self.default_api_version + ) + } +} diff --git a/src/types/config/types/mod.rs b/src/types/config/types/mod.rs index dce4eb0..6ea2c03 100644 --- a/src/types/config/types/mod.rs +++ b/src/types/config/types/mod.rs @@ -1,6 +1,7 @@ pub mod api_configuration; pub mod cdn_configuration; pub mod defaults_configuration; +pub mod domains_configuration; pub mod email_configuration; pub mod endpoint_configuration; pub mod external_tokens_configuration; From c66cc9b16c9f96e7f83aa1ddc407de3f8d2840f7 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 13:04:17 +0100 Subject: [PATCH 05/15] move WellKnownResponse to src/types/ --- src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3333bf0..8e38026 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,6 +106,7 @@ compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled use errors::ChorusResult; use serde::{Deserialize, Serialize}; +use types::types::domains_configuration::WellKnownResponse; use url::{ParseError, Url}; use crate::errors::ChorusError; @@ -223,11 +224,6 @@ impl UrlBundle { } } -#[derive(Deserialize)] -struct WellKnownResponse { - pub(crate) api: String, -} - #[cfg(test)] mod lib { use super::*; From 97fc99354a054d855af919507374de2578351487 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 13:13:57 +0100 Subject: [PATCH 06/15] add warning lint for usage of todo!() --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 8e38026..d2db694 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,6 +101,7 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read clippy::new_without_default, clippy::useless_conversion )] +#![warn(clippy::todo, clippy::unimplemented)] #[cfg(all(feature = "rt", feature = "rt_multi_thread"))] compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time"); From 410eef1edd7ff9147d7a235a9dd1012f72262bfb Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 13:16:34 +0100 Subject: [PATCH 07/15] impl from_api_url --- src/lib.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d2db694..093d297 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,13 +215,29 @@ impl UrlBundle { { Ok(response_api) } else { - Err(ChorusError::RequestFailed { url: url.to_string(), error: "Could not retrieve UrlBundle from url after trying 3 different approaches. Check the provided Url and if the instance is reachable.".to_string() } ) + Err(ChorusError::RequestFailed { url: url.to_string(), error: "Could not retrieve UrlBundle from url after trying 3 different approaches. Check the provided Url and make sure the instance is reachable.".to_string() } ) } } } async fn from_api_url(url: &str) -> ChorusResult { - todo!() + let client = reqwest::Client::new(); + let request = client + .get(url) + .header(http::header::ACCEPT, "application/json") + .build()?; + let response = client.execute(request).await?; + if let Ok(body) = response + .json::() + .await + { + Ok(UrlBundle::new(body.api_endpoint, body.gateway, body.cdn)) + } else { + Err(ChorusError::RequestFailed { + url: url.to_string(), + error: "Could not retrieve a UrlBundle from the given url. Check the provided url and make sure the instance is reachable.".to_string(), + }) + } } } From c835bf1123e6c542b71ac55f8191322ff2dc606b Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 13:28:50 +0100 Subject: [PATCH 08/15] check for dbg! println! eprintln! in production code --- src/lib.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 093d297..47fda75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,7 +101,13 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read clippy::new_without_default, clippy::useless_conversion )] -#![warn(clippy::todo, clippy::unimplemented)] +#![warn( + clippy::todo, + clippy::unimplemented, + clippy::dbg_macro, + clippy::print_stdout, + clippy::print_stderr +)] #[cfg(all(feature = "rt", feature = "rt_multi_thread"))] compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time"); @@ -206,16 +212,16 @@ impl UrlBundle { UrlBundle::from_api_url(&body).await } else { if let Ok(response_slash_api) = - UrlBundle::from_api_url(&format!("{}/api/policies/instance/domains", url)).await + UrlBundle::from_api_url(&format!("{}/api/policies/instance/domains", parsed)).await { return Ok(response_slash_api); } if let Ok(response_api) = - UrlBundle::from_api_url(&format!("{}/policies/instance/domains", url)).await + UrlBundle::from_api_url(&format!("{}/policies/instance/domains", parsed)).await { Ok(response_api) } else { - Err(ChorusError::RequestFailed { url: url.to_string(), error: "Could not retrieve UrlBundle from url after trying 3 different approaches. Check the provided Url and make sure the instance is reachable.".to_string() } ) + Err(ChorusError::RequestFailed { url: parsed.to_string(), error: "Could not retrieve UrlBundle from url after trying 3 different approaches. Check the provided Url and make sure the instance is reachable.".to_string() } ) } } } From b246e08aca29682d0b82e8de2644d8873404d575 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 13:29:38 +0100 Subject: [PATCH 09/15] Write test to check basic functionality of UrlBundle::from_root_domain() --- tests/urlbundle.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/urlbundle.rs diff --git a/tests/urlbundle.rs b/tests/urlbundle.rs new file mode 100644 index 0000000..296e86b --- /dev/null +++ b/tests/urlbundle.rs @@ -0,0 +1,12 @@ +use chorus::UrlBundle; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::*; +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test_configure!(run_in_browser); + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_parse_url() { + let url = url::Url::parse("http://localhost:3001/").unwrap(); + UrlBundle::from_root_domain(url.as_str()).await.unwrap(); +} From 1a52975dbda9db3fd3b33ac16212891399a07c7e Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 13:33:24 +0100 Subject: [PATCH 10/15] Add test if an example well-known response gets parsed correctly. --- tests/urlbundle.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/urlbundle.rs b/tests/urlbundle.rs index 296e86b..94dcc6d 100644 --- a/tests/urlbundle.rs +++ b/tests/urlbundle.rs @@ -1,4 +1,6 @@ +use chorus::types::types::domains_configuration::WellKnownResponse; use chorus::UrlBundle; +use serde_json::json; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] @@ -7,6 +9,18 @@ wasm_bindgen_test_configure!(run_in_browser); #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_parse_url() { + // TODO: Currently only tests two of the three branches in UrlBundle::from_root_domain. let url = url::Url::parse("http://localhost:3001/").unwrap(); UrlBundle::from_root_domain(url.as_str()).await.unwrap(); + let url = url::Url::parse("http://localhost:3001/api/").unwrap(); + UrlBundle::from_root_domain(url.as_str()).await.unwrap(); +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_parse_wellknown() { + let json = json!({ + "api": "http://localhost:3001/api/v9" + }); + let _well_known: WellKnownResponse = serde_json::from_value(json).unwrap(); } From b5ff7e3347bd1d8ea8346d6ec7e06bed78b1ddad Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 13:37:32 +0100 Subject: [PATCH 11/15] Add Instance::from_root_domain(), change documentation wording --- src/instance.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/instance.rs b/src/instance.rs index fc0bcda..6a3b9af 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -70,7 +70,7 @@ impl PartialEq for LimitsInformation { } impl Instance { - /// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle), where `limited` is whether or not to automatically use rate limits. + /// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle), where `limited` is whether Chorus will track and enforce rate limits for this instance. pub async fn new(urls: UrlBundle, limited: bool) -> ChorusResult { let limits_information; if limited { @@ -99,12 +99,22 @@ impl Instance { }; Ok(instance) } + pub(crate) fn clone_limits_if_some(&self) -> Option> { if self.limits_information.is_some() { return Some(self.limits_information.as_ref().unwrap().ratelimits.clone()); } None } + + /// Creates a new [`Instance`] by trying to get the [relevant instance urls](UrlBundle) from a root domain. + /// Shorthand for `Instance::new(UrlBundle::from_root_domain(root_domain).await?)`. + /// + /// If `limited` is `true`, then Chorus will track and enforce rate limits for this instance. + pub async fn from_root_domain(root_domain: &str, limited: bool) -> ChorusResult { + let urls = UrlBundle::from_root_domain(root_domain).await?; + Instance::new(urls, limited).await + } } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] From 0125c38bd011d4a3cc6722cdcb0a12089b0703bd Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 13:39:23 +0100 Subject: [PATCH 12/15] Rename from_root_domain to from_root_url --- src/instance.rs | 6 +++--- src/lib.rs | 4 ++-- tests/urlbundle.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/instance.rs b/src/instance.rs index 6a3b9af..90ee1fa 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -107,12 +107,12 @@ impl Instance { None } - /// Creates a new [`Instance`] by trying to get the [relevant instance urls](UrlBundle) from a root domain. + /// Creates a new [`Instance`] by trying to get the [relevant instance urls](UrlBundle) from a root url. /// Shorthand for `Instance::new(UrlBundle::from_root_domain(root_domain).await?)`. /// /// If `limited` is `true`, then Chorus will track and enforce rate limits for this instance. - pub async fn from_root_domain(root_domain: &str, limited: bool) -> ChorusResult { - let urls = UrlBundle::from_root_domain(root_domain).await?; + pub async fn from_root_url(root_url: &str, limited: bool) -> ChorusResult { + let urls = UrlBundle::from_root_url(root_url).await?; Instance::new(urls, limited).await } } diff --git a/src/lib.rs b/src/lib.rs index 47fda75..80374fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -189,7 +189,7 @@ impl UrlBundle { url_string } - /// Performs a few HTTP requests to try and retrieve a `UrlBundle` from an instances' root domain. + /// Performs a few HTTP requests to try and retrieve a `UrlBundle` from an instances' root url. /// The method tries to retrieve the `UrlBundle` via these three strategies, in order: /// - GET: `$url/.well-known/spacebar` -> Retrieve UrlBundle via `$wellknownurl/api/policies/instance/domains` /// - GET: `$url/api/policies/instance/domains` @@ -199,7 +199,7 @@ impl UrlBundle { /// stores the CDN and WSS URLs under the `$api/policies/instance/domains` endpoint. If all three /// of the above approaches fail, it is very likely that the instance is misconfigured, unreachable, or that /// a wrong URL was provided. - pub async fn from_root_domain(url: &str) -> ChorusResult { + pub async fn from_root_url(url: &str) -> ChorusResult { let parsed = UrlBundle::parse_url(url.to_string()); let client = reqwest::Client::new(); let request_wellknown = client diff --git a/tests/urlbundle.rs b/tests/urlbundle.rs index 94dcc6d..790229b 100644 --- a/tests/urlbundle.rs +++ b/tests/urlbundle.rs @@ -11,9 +11,9 @@ wasm_bindgen_test_configure!(run_in_browser); async fn test_parse_url() { // TODO: Currently only tests two of the three branches in UrlBundle::from_root_domain. let url = url::Url::parse("http://localhost:3001/").unwrap(); - UrlBundle::from_root_domain(url.as_str()).await.unwrap(); + UrlBundle::from_root_url(url.as_str()).await.unwrap(); let url = url::Url::parse("http://localhost:3001/api/").unwrap(); - UrlBundle::from_root_domain(url.as_str()).await.unwrap(); + UrlBundle::from_root_url(url.as_str()).await.unwrap(); } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] From c0004d732c50377db636362e3656a9cd9d3557f0 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 14:18:14 +0100 Subject: [PATCH 13/15] Change macOS Safari test strategy to no-fail-fast --- .github/workflows/build_and_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index a6abe43..6751f05 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -72,7 +72,7 @@ jobs: rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force - SAFARIDRIVER=$(which safaridriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt" + SAFARIDRIVER=$(which safaridriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt" --no-fail-fast wasm-gecko: runs-on: macos-latest steps: From 3a4fd470dfe7860f242c6c333329497a135e5c74 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 15:06:09 +0100 Subject: [PATCH 14/15] Try giving macos-safari its own cache key to fix CI --- .github/workflows/build_and_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 6751f05..bb28584 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -66,7 +66,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: cache-all-crates: "true" - prefix-key: "macos" + prefix-key: "macos-safari" - name: Run WASM tests with Safari, Firefox, Chrome run: | rustup target add wasm32-unknown-unknown From 2c0f71793d12044f11b350421c12d67347400999 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 3 Dec 2023 15:57:03 +0100 Subject: [PATCH 15/15] wasm-safari CI seems to be bugged - disabling for now --- .github/workflows/build_and_test.yml | 56 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index bb28584..0cf6fd9 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -45,34 +45,34 @@ jobs: cargo build --verbose --all-features cargo test --verbose --all-features fi - wasm-safari: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Clone spacebar server - run: | - git clone https://github.com/bitfl0wer/server.git - - uses: actions/setup-node@v3 - with: - node-version: 18 - cache: 'npm' - cache-dependency-path: server/package-lock.json - - name: Prepare and start Spacebar server - run: | - npm install - npm run setup - npm run start & - working-directory: ./server - - uses: Swatinem/rust-cache@v2 - with: - cache-all-crates: "true" - prefix-key: "macos-safari" - - name: Run WASM tests with Safari, Firefox, Chrome - run: | - rustup target add wasm32-unknown-unknown - curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force - SAFARIDRIVER=$(which safaridriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt" --no-fail-fast + # wasm-safari: + # runs-on: macos-latest + # steps: + # - uses: actions/checkout@v4 + # - name: Clone spacebar server + # run: | + # git clone https://github.com/bitfl0wer/server.git + # - uses: actions/setup-node@v3 + # with: + # node-version: 18 + # cache: 'npm' + # cache-dependency-path: server/package-lock.json + # - name: Prepare and start Spacebar server + # run: | + # npm install + # npm run setup + # npm run start & + # working-directory: ./server + # - uses: Swatinem/rust-cache@v2 + # with: + # cache-all-crates: "true" + # prefix-key: "macos-safari" + # - name: Run WASM tests with Safari, Firefox, Chrome + # run: | + # rustup target add wasm32-unknown-unknown + # curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + # cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force + # SAFARIDRIVER=$(which safaridriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt" --no-fail-fast wasm-gecko: runs-on: macos-latest steps: