Repository: TabbyML/tabby
File: crates/tabby-common/src/registry.rs (Rust)

Code before:
    // partition_urls is used for model download address
    // if the model is partitioned, the addresses of each partition will be listed here,
    // if there is only one partition, it will be the same as `urls`.
    //
    // will first try to the `urls`, if not found, will try this `partition_urls`.
    //
    // must make sure the first address is the entrypoint
    #[serde(skip_serializing_if = "Option::is_none")]
    pub partition_urls: Option<Vec<PartitionModelUrl>>,
}

#[derive(Serialize, Deserialize)]
pub struct PartitionModelUrl {
    pub urls: Vec<String>,
    pub sha256: String,
}

fn models_json_file(registry: &str) -> PathBuf {
    models_dir().join(registry).join("models.json")
}

async fn load_remote_registry(registry: &str) -> Result<Vec<ModelInfo>> {
    // Create a client with custom timeout.
    // There have been instances where requests did not adhere to the default timeout,
    // resulting in requests hanging indefinitely.
    // Therefore, it's necessary to specify a custom timeout.
    let client = reqwest::Client::builder()
        .timeout(std::time::Duration::from_secs(5))
        .build()
        .context("Failed to build HTTP client")?;

    let model_info = client
        .get(format!(
            "https://raw.githubusercontent.com/{}/registry-tabby/main/models.json",
            registry
        ))
        .send()
        .await
        .context("Failed to download")?
        .json()
        .await
        .context("Failed to get JSON")?;

    let dir = models_dir().join(registry);
    // We don't want to fail if the TabbyML directory already exists,
    // which is exactly, what `create_dir_all` will do, see
    // https://doc.rust-lang.org/std/fs/fn.create_dir.html#errors.
    if !dir.exists() {
        fs::create_dir_all(&dir).context(format!("Failed to create dir {dir:?}"))?;
    }
    serdeconv::to_json_file(&model_info, models_json_file(registry))

Review comment (suggestion):
```suggestion
    // Create an HTTP client with a custom timeout.
    // This is necessary because the default timeout settings can sometimes cause requests to hang indefinitely.
    // To prevent such issues, we specify a custom timeout duration.
```

Code after:
    // partition_urls is used for model download address
    // if the model is partitioned, the addresses of each partition will be listed here,
    // if there is only one partition, it will be the same as `urls`.
    //
    // will first try to the `urls`, if not found, will try this `partition_urls`.
    //
    // must make sure the first address is the entrypoint
    #[serde(skip_serializing_if = "Option::is_none")]
    pub partition_urls: Option<Vec<PartitionModelUrl>>,
}

#[derive(Serialize, Deserialize)]
pub struct PartitionModelUrl {
    pub urls: Vec<String>,
    pub sha256: String,
}

fn models_json_file(registry: &str) -> PathBuf {
    models_dir().join(registry).join("models.json")
}

async fn load_remote_registry(registry: &str) -> Result<Vec<ModelInfo>> {
    // Create an HTTP client with a custom timeout.
    // This is necessary because the default timeout settings can sometimes cause requests to hang indefinitely.
    // To prevent such issues, we specify a custom timeout duration.
    let client = reqwest::Client::builder()
        .timeout(std::time::Duration::from_secs(5))
        .build()
        .context("Failed to build HTTP client")?;

    let model_info = client
        .get(format!(
            "https://raw.githubusercontent.com/{}/registry-tabby/main/models.json",
            registry
        ))
        .send()
        .await
        .context("Failed to download")?
        .json()
        .await
        .context("Failed to get JSON")?;

    let dir = models_dir().join(registry);
    // We don't want to fail if the TabbyML directory already exists,
    // which is exactly, what `create_dir_all` will do, see
    // https://doc.rust-lang.org/std/fs/fn.create_dir.html#errors.
    if !dir.exists() {
        fs::create_dir_all(&dir).context(format!("Failed to create dir {dir:?}"))?;
    }
    serdeconv::to_json_file(&model_info, models_json_file(registry))
        .context("Failed to convert JSON to file")?;