-
Notifications
You must be signed in to change notification settings - Fork 3
EIM-112: Added the ping check for mirrors #271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Summary of ChangesHello @alirana01, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a significant enhancement to the mirror selection process by integrating latency-based ping checks. The primary goal is to improve the reliability and speed of downloads and installations by ensuring the application connects to the most performant mirrors. This change provides a more intelligent and user-friendly way to manage mirror preferences across both command-line and graphical interfaces. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a latency check for mirrors, which is a great improvement for user experience. The implementation is solid, but there are several areas with significant code duplication in both the Rust backend and the Vue frontend. I've provided suggestions to refactor this duplicated logic into helper functions to improve maintainability. Additionally, I've identified a potential crash in a GUI command due to an unhandled error and a performance improvement opportunity by parallelizing mirror checks.
|
|
||
| /// Compute the latency map for the tools mirror | ||
| pub async fn get_tools_mirror_latency_map(&self) -> Result<HashMap<String, u32>> { | ||
| let available_mirrors = crate::get_idf_tools_mirrors_list() | ||
| .to_vec() | ||
| .iter() | ||
| .map(|s| s.to_string()) | ||
| .collect::<Vec<String>>(); | ||
| let mirror_latency_map = | ||
| crate::utils::calculate_mirror_latency_map(&available_mirrors).await; | ||
| Ok(mirror_latency_map) | ||
| } | ||
|
|
||
| /// Compute the latency map for the IDF mirror | ||
| pub async fn get_idf_mirror_latency_map(&self) -> Result<HashMap<String, u32>> { | ||
| let available_mirrors = crate::get_idf_mirrors_list() | ||
| .to_vec() | ||
| .iter() | ||
| .map(|s| s.to_string()) | ||
| .collect::<Vec<String>>(); | ||
| let mirror_latency_map = | ||
| crate::utils::calculate_mirror_latency_map(&available_mirrors).await; | ||
| Ok(mirror_latency_map) | ||
| } | ||
|
|
||
| /// Compute the latency map for the PyPI mirror | ||
| pub async fn get_pypi_mirror_latency_map(&self) -> Result<HashMap<String, u32>> { | ||
| let available_mirrors = crate::get_pypi_mirrors_list() | ||
| .to_vec() | ||
| .iter() | ||
| .map(|s| s.to_string()) | ||
| .collect::<Vec<String>>(); | ||
| let mirror_latency_map = | ||
| crate::utils::calculate_mirror_latency_map(&available_mirrors).await; | ||
| Ok(mirror_latency_map) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Hahihula I think i made it redundant by adding these functions here or I may have miss understood something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so why do you add them?
Hahihula
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you also use u32::MAX for unreachable on rust side and 0 on javascript side. avoid using magical numbers if possible. Usage of Option<> or enum will be better variant here.
You also have a lot of faulty code as well as code which will work only on happy path scenarios. Avoid using unwrap if you are not 100% sure it's ok to do so.
A lot of the logic is AntiIdiomatic.
Also, please turn off the automatic formatting features of your IDE and avoid copy&paste from LLMs, which changes the formatting of all the code. Unnecessary changes in code formatting are masking the history of changes in git. Please do not reformat part of code you otherwise did not touch.
You also completely ignored some of my comments from the last time. For example the error you have here with the stripping of port number from the url. I expect that after the fix you will also have test which covers this case.
The UI side logic can also be significantly simplified. There is also the issue of not easily understandable code with the converting u32::MAX to 0 and using positive and negative infinity alongside syntactic null and undefined. But the idea of bootstrapping the store after the app starts with values needed later is good and we should use it more broadly for example for getting OS params in one place.
I also think the functions mirror_entries_to_display and url_from_display_line really shouldn't exist at all
src-tauri/src/lib/utils.rs
Outdated
| use url::Url; | ||
| use zstd::{decode_all, Decoder}; | ||
|
|
||
| use crate::{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid needles reformatting/rearranging of imports as it masks history
src-tauri/src/lib/utils.rs
Outdated
| } | ||
|
|
||
| /// Turn `(url, latency)` tuples into display strings like `https://... (123 ms)` or `(... timeout)`. | ||
| pub fn mirror_entries_to_display(entries: &[MirrorEntry]) -> Vec<String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as this is formating fo cli part only, it should not be part of common library shared between cli and gui
| .unwrap() | ||
| .0 | ||
| .clone(); | ||
| let mirror = match best_mirror.is_empty() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here, you select the mirror to be either the best or the default mirror, than emit in in the message and never use it!
|
|
||
| let mirror = settings.idf_mirror.clone().unwrap_or_default(); | ||
| let mut available_mirrors = idf_im_lib::get_idf_mirrors_list().to_vec(); | ||
| let mirror = settings.idf_mirror.clone().unwrap_or_default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another unnecessary formating change... please avoid
src-tauri/src/lib/utils.rs
Outdated
| } | ||
|
|
||
| /// Return URL -> score (lower is better). Unreachable mirrors get u32::MAX. | ||
| pub async fn calculate_mirror_latency_map(mirrors: &[String]) -> HashMap<String, u32> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the function as it's written now will introduce potentially multiple 10s of second wait for timeout as it checks the mirrors sequentially, it also creates new reqwest::Client for every mirror. Creating a client is expensive (allocating connection pools, TLS configuration).
| const list = (urls || []).map((url) => ({ | ||
| value: url, | ||
| label: url, | ||
| ping: this.normalizePingValue(latencyMap ? latencyMap[url] : undefined), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as this is the only place you use normalizePingValue the function is there only for converting hardcoded undefined to hardcoded null...
| let default_mirror = rust_i18n::t!("gui.installation.default_mirror").to_string(); | ||
| let mirror = settings.idf_mirror.as_deref().unwrap_or(&default_mirror); | ||
| let default_mirror_str = rust_i18n::t!("gui.installation.default_mirror").to_string(); | ||
| let default_mirror = settings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not only default mirror but potentially also user selected preferred mirror
Hahihula
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You completely ignored my recommendation from last review:
I also think the functions mirror_entries_to_display and url_from_display_line really shouldn't exist at all
Could you please really pay attention to the review remarks?
| pub wizard_all_questions: Option<bool>, | ||
| pub mirror: Option<String>, | ||
| pub tools_mirror: Option<String>, | ||
| pub idf_mirror: Option<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a breaking API change. Will force to upgrade all integrations. Docker images and actions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reverted back!
src-tauri/src/cli/cli_args.rs
Outdated
| self.tools_json_file.map(Into::into), | ||
| ), | ||
| ("mirror".to_string(), self.mirror.map(Into::into)), | ||
| // map CLI flag `-m|--mirror` to settings field `tools_mirror` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mapping the CLI --mirror argument to the tools_mirror setting is inconsistent and unjustified. You apply this remapping only for this single argument, which means it behaves differently from all other CLI options. This breaks the established logic for how settings are populated.
Additionally, the CLI is not the only source of configuration. By introducing this one-off mapping, you are decoupling settings in a way that disrupts the overall configuration flow. This is not acceptable.
I already raised this concern in the previous iteration of the review, yet the issue not only remains unresolved, but it has been made worse.
On top of that, the renaming you introduced constitutes a breaking change to the application’s interface. All related changes must be reverted. If such a renaming is ever considered, it must be evaluated and delivered in a dedicated PR, not mixed in with unrelated work.
Do not bundle multiple unrelated changes into the same PR. While it may seem convenient to merge, it significantly increases the complexity and risk when a rollback is needed. My priority is not how easy it is to merge your changes — it’s how difficult it will be to revert them if something breaks. Please follow proper PR scoping and revert the unrelated interface changes before resubmitting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reverted
src-tauri/src/cli/helpers.rs
Outdated
| let latency_map = calculate_mirror_latency_map(&mirrors.to_vec()).await; | ||
| let mut entries: Vec<MirrorEntry> = Vec::new(); | ||
| for (key, value) in latency_map.iter() { | ||
| entries.push((key.clone(), value.clone())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you building a new structure by cloning everything? Please prefer iterator-based construction via collect() for simplicity and zero-cost abstraction. Also you wouldn't need mutable entries
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed here
src-tauri/src/cli/helpers.rs
Outdated
|
|
||
| /// Sort mirrors by measured latency (ascending), using None for timeouts. | ||
| pub async fn sorted_mirror_entries(mirrors: &[&str]) -> Vec<MirrorEntry> { | ||
| let latency_map = calculate_mirror_latency_map(&mirrors.to_vec()).await; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
&mirrors.to_vec() converts a slice to a vec and back to a slice reference
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed at required places
src-tauri/src/cli/helpers.rs
Outdated
| use idf_im_lib::utils::{calculate_mirror_latency_map}; | ||
|
|
||
| /// A tuple containing a mirror URL and its measured latency. | ||
| pub type MirrorEntry = (String, Option<u32>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should use struct instead of tuple so you are not later accessing it by mystique e.1
also use macro to derive Ord to make the sorting cleaner
something like this:
impl PartialOrd for MirrorEntry {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.latency.partial_cmp(&other.latency)
}
}
impl Ord for MirrorEntry {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap_or(Ordering::Equal) // Or handle None explicitly
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| #[tauri::command] | ||
| pub async fn start_simple_setup(app_handle: tauri::AppHandle) -> Result<(), String> { | ||
| let app_state = app_handle.state::<crate::gui::app_state::AppState>(); | ||
| app_state::set_is_simple_installation(&app_handle, true)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as mentioned above this true will always get overwritten by start_simple_setup to false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
| use anyhow::{Result}; | ||
|
|
||
| use crate::gui; | ||
| use crate::gui::{self, app_state}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You added app_state to the import list here, but it is never used. Introducing unused imports is unnecessary noise and should be caught before the PR is submitted.
It would be extremely helpful if you reviewed the GitHub diff yourself before requesting a review. Basic self-review should catch obvious issues like unused imports, leftover code, or incomplete refactoring. This is a matter of professional courtesy and respect for the reviewer’s time.
Please ensure you perform a thorough pass over your changes before assigning the PR for review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
src-tauri/src/gui/utils.rs
Outdated
| } | ||
| } | ||
|
|
||
| pub async fn get_best_mirror(mirror_latency_map: &HashMap<String, Option<u32>>) -> Option<String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This String + Option pairing is fundamentally the same data structure as the tuple you’re using in the CLI component. As mentioned in the previous review round, you should introduce a proper struct to represent a mirror entry and implement Ord (as previously suggested).
If you define this struct in the shared library layer, you can use it consistently in both the CLI and GUI code. This will simplify the implementation, remove the need for ad-hoc comparisons, and ensure that both parts of the application follow the exact same logic when selecting the best mirror.
Please refactor accordingly to avoid duplicating logic and relying on loosely structured tuples or paired values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved original struct to the library now
src-tauri/src/cli/helpers.rs
Outdated
| entries.push((key.clone(), value.clone())); | ||
| } | ||
|
|
||
| entries.sort_by_key(|e| e.1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
much more readable way to write this is
entries.sort_by_key(|(url, latency)| latency);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed here since now it is part of shared library as a struct
| ui::send_message, | ||
| utils::is_path_empty_or_nonexistent, | ||
| }; | ||
| use std::path::PathBuf; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid reformatting imports or modifying code that is unrelated to the scope of your changes. Splitting and rearranging imports without necessity introduces noise, obscures git history, and makes the review process significantly harder.
This is the third time I’ve had to raise this concern on this PR, and it is becoming a recurring issue. Going forward, do not make non-essential formatting or structural changes unless they are directly required for the feature or fix you are implementing.
Thank you for addressing this properly in future submissions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cleaned up
|
Just to add clarification to the comment I cannot figure out a way other than to separate the call from the command and the function the command invoked from frontend should not have been called in the backend at first place I guess we can try to refactor code in another PR where we make sure that all such functions are broken down further to avoid conflicting changes later in the code when we need to add new things or features. The addition of the new command that will be invoked by the frontend will avoid this flaw. |
Hahihula
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's still fundamentally not working, you have terrible flaws in logic as well as code repetition and antiidiomatic approach, but it's much better than last time.
| } | ||
|
|
||
| impl Ord for MirrorEntry { | ||
| fn cmp(&self, other: &Self) -> Ordering { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better approach! But still ... Option already implements the Ord Trait. So it can be simplified like this:
match (self.latency, other.latency) {
(Some(a), Some(b)) => a.cmp(&b),
(Some(_), None) => Ordering::Less,
(None, Some(_)) => Ordering::Greater,
(None, None) => Ordering::Equal,
}
This 1) avoids unwrap() 2) ensures all possible cases are covered (match will not let you have unimplemented variants) 3) is clearly readable 4) pattern matching is the rust way of doing things ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src-tauri/src/lib/utils.rs
Outdated
| } | ||
| } | ||
| } | ||
| if head_latency_failed { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use else here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah but why go over the loop once again if the head failed in that attempt why not break it right there.
src-tauri/src/lib/utils.rs
Outdated
| } | ||
|
|
||
| /// Return URL -> score (lower is better). Unreachable mirrors get None. | ||
| pub async fn calculate_mirror_latency_map(mirrors: &[&str]) -> HashMap<String, Option<u32>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also as you now have the MirrorEntry type, with ordering implemented, I would expect you to realize that you can make select_single_mirror and select_best_mirror much better. If you use Vec in the calculate_mirror_latency_map function.
Is more idiomatic and more efficient, it's also more readable as you know you are working with MirrorEntry also thsi way you will avoind new alocation of the string keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src-tauri/src/cli/prompts.rs
Outdated
| )?) | ||
| // Only measure mirror latency if we actually need a value (or wizard wants to ask) | ||
| if interactive && (wizard_all || needs_value) { | ||
| let mut entries = calculate_mirror_latency_map(candidates).await.into_iter() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after you convert the calculate_mirror_latency_map so it returns Vec you can than
just entries.sort(); without the unnecessary rearranging everything with unnecessary allocations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src-tauri/src/gui/utils.rs
Outdated
| } | ||
| } | ||
|
|
||
| pub async fn get_best_mirror(mirror_latency_map: HashMap<String, Option<u32>>) -> Option<String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function will also benefit from converting mirror_latency_map to Vec
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removing this as we dont need it anymore as moving to MirrorEntry vector the original latency calculation returns it sorted
| value: mirror, | ||
| label: mirror, | ||
| this.sortMirrorsByPing(this.idf_mirrors); | ||
| this.loading_idfs = this.mirrorsStore.loading_idf_urls || this.mirrorsStore.loading_idf_latency; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the loading should be also reactive computed properties:
loading_idfs = mirrorsStore.loading_idf_urls || mirrorsStore.loading_idf_latency
``
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/store.js
Outdated
|
|
||
| computeLatencyInBackground() { | ||
| const now = Date.now(); | ||
| // IDF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i would really like if you can avoid this repetitive code ... maybe you can use something like:
const MIRROR_TYPES = ['idf', 'tools', 'pypi'];
state: () => {
const base = {};
for (const type of MIRROR_TYPES) {
base[`${type}_urls`] = [];
base[`${type}_latency_map`] = {};
base[`selected_${type}`] = '';
base[`loading_${type}_urls`] = false;
base[`loading_${type}_latency`] = false;
base[`${type}_last_updated`] = 0;
}
return {
...base,
latency_ttl_ms: 15 * 60 * 1000,
};
},
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please do the same for the rest of the useMirrorsStore ? You have the same repetitive patern all over it. My previos comment is clear hint how to achieve much less repetitive code.
| this.refreshListFromStore('pypi'); | ||
| // Subscribe to store updates and refresh progressively per-type | ||
| const unsub = this.mirrorsStore.$subscribe(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should avoid the $subscribe...use reactive computed properties
you can also avoid so much code repetition
Please read more about Vuejs reactivity https://vuejs.org/guide/essentials/reactivity-fundamentals.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
| let mirror = settings.idf_mirror.as_deref().unwrap_or(&default_mirror_str); | ||
| let mut mirror_to_use: String = mirror.to_string(); | ||
|
|
||
| if is_simple_installation && mirror == &default_mirror_str { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Care to explain this to me?
you are reading value from the localisation file:
let default_mirror_str = rust_i18n::t!("gui.installation.default_mirror").to_string();
and comparing it to this value?
How is this exactly supposed to work and in which languages?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙈🔫
|
|
||
| #[cfg(not(target_os = "windows"))] | ||
| #[tauri::command] | ||
| pub async fn start_installation_gui_cmd(app_handle: AppHandle) -> Result<(), String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are unnecessarily adding another level of indirection...
this function should never exist...
You are obviously trying to achieve the default value... this is usually done in Rust by implementing the default trait for the structure
Please refactor your code according to this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
This reverts commit 10b9c32.
|
So now the app state on rust side holds the mirror latencies and whenever they are needed anywhere that is checked first to avoid triggering the latency check again. Rest of the logic should be working fine @Hahihula |
| } | ||
| Err(e) => { | ||
| warn!("{}", e.to_string()); | ||
| head_latency_failed = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the break should be here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Hahihula
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, much better than last time. No more big logical errors. Still not mergable, but we are near.
src-tauri/src/cli/prompts.rs
Outdated
| let entries = calculate_mirrors_latency(candidates).await; | ||
| if let Some(entry) = entries.first() { | ||
| if entry.latency.is_none() { | ||
| info!("Selected {log_prefix} mirror: {} (timeout)", entry.url); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You just selected for the user mirror which timeouted and threat it as normal situation, with logging info ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed returning error if the top entry is none as that means some connection issue as vectors are sorted by latency and None (timeout) should be at the end not first entry
src-tauri/src/gui/utils.rs
Outdated
| } | ||
| } | ||
|
|
||
| pub async fn get_mirror_to_use(mirror_type: MirrorType, settings: &Settings, is_simple_installation: bool, app_handle: &AppHandle) -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
every other function accepting app_handle has it as firt argument, can you pleare acomodate your to that custom for sake of readibility?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| this.get_available_tools_mirrors(); | ||
| this.get_available_pypi_mirrors(); | ||
| // Ensure background bootstrap runs if user navigates directly here before app init | ||
| if ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this means that if you have mirror of one type but not the others becaus for example network disconected before you finished measuring, you will not refetch them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/store.js
Outdated
|
|
||
| computeLatencyInBackground() { | ||
| const now = Date.now(); | ||
| // IDF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please do the same for the rest of the useMirrorsStore ? You have the same repetitive patern all over it. My previos comment is clear hint how to achieve much less repetitive code.
| }, | ||
| }); | ||
|
|
||
| export const useMirrorsStore = defineStore("mirrors", { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try to deduplicate the code in this store
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Hahihula
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the Rust part seems to be ok, let's just cleanup the javascript part
src-tauri/src/cli/prompts.rs
Outdated
| set_value(config, entry.url.clone()); | ||
| } else { | ||
| // If the first entry is timeout or None there are no good mirrors to select try logging a proper message and return an error | ||
| info!("No good {log_prefix} mirrors found, please check your internet connection and try again§"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
|
|
||
| <script> | ||
| import { ref } from "vue"; | ||
| import { } from "vue"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?? What should this be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
originally i see ref import from master but not sure if its even used there but i reverted back to that to avoid any issues
| buildMirrorList(type) { | ||
| const urls = type === 'idf' ? this.mirrorsStore.idf_urls : type === 'tools' ? this.mirrorsStore.tools_urls : this.mirrorsStore.pypi_urls; | ||
| const entries = type === 'idf' ? this.mirrorsStore.idf_entries : type === 'tools' ? this.mirrorsStore.tools_entries : this.mirrorsStore.pypi_entries; | ||
| if (Array.isArray(entries) && entries.length > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use entries?.length > 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplified with new simplified code
| this.selected_idf_mirror = idf_mirrors.selected; | ||
| this.loading_idfs = false; | ||
| return false; | ||
| buildMirrorList(type) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function can be simplified using try catch block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
simplified not exactly try catch but kindly take a look if it is okay now
| this.selected_pypi_mirror = pypi_mirrors.selected; | ||
| this.loading_pypi = false; | ||
| return false; | ||
| getBestMirror(list) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using reduce this function is oneliner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| }, | ||
| maybeAutoSelectBest(type) { | ||
| if (!this.autoSelect[type]) return; | ||
| const list = type === 'idf' ? this.idf_mirrors : type === 'tools' ? this.tools_mirrors : this.pypi_mirrors; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this can be written more readably like: const list = this[${type}_mirrors];
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| const list = type === 'idf' ? this.idf_mirrors : type === 'tools' ? this.tools_mirrors : this.pypi_mirrors; | ||
| const best = this.getBestMirror(list); | ||
| if (!best) return; | ||
| const selectedKey = type === 'idf' ? 'selected_idf_mirror' : type === 'tools' ? 'selected_tools_mirror' : 'selected_pypi_mirror'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const storeKey = selected_${type}_mirror;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| }, | ||
| isDefaultMirror(mirror, type) { | ||
| return mirror === this.defaultMirrors[type]; | ||
| const selectedFromStore = type === 'idf' ? this.mirrorsStore.selected_idf : type === 'tools' ? this.mirrorsStore.selected_tools : this.mirrorsStore.selected_pypi; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar as abow this can be more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| }); | ||
|
|
||
| export const useMirrorsStore = defineStore("mirrors", { | ||
| state: () => ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unified the structure for all mirror types could make the store much more readable and maintainable.
for example like this:
mirrors: {
idf: {
urls: [],
entries: [],
selected: "",
loading_urls: false,
loading_latency: false,
last_updated: 0,
},
tools: {
urls: [],
entries: [],
selected: "",
loading_urls: false,
loading_latency: false,
last_updated: 0,
},
pypi: {
urls: [],
entries: [],
selected: "",
loading_urls: false,
loading_latency: false,
last_updated: 0,
},
},
it will also simplyfy the code in the rest of the store and the component...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Description
Ping test added for the mirrors. We first query the HEAD with a GET request and if that fails we try a normal GET to verify latency and connection
Testing
Tested the installation via cli, gui using both simple and wizard based flows
Checklist
Before submitting a Pull Request, please ensure the following: