Tenho seguinte código tauri v2 rust

use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use tauri::{AppHandle, Emitter};
use reqwest::Client;
use tokio::fs;
use tokio::io::AsyncWriteExt;
use std::time::{Duration, Instant};

#[derive(Deserialize, Clone)]
struct PatchEntry {
    file_name: String,
}

#[derive(Serialize, Clone)]
struct DownloadInfo {
    current_file: usize,
    total_files: usize,
    file_name: String,
    downloaded_bytes: u64,
    total_bytes: u64,
    speed: f64,
}

#[derive(Serialize, Clone)]
struct DownloadStatus {
    status: String,
    additional_info: Option<String>,
}

fn get_exe_dir() -> PathBuf {
    std::env::current_exe().unwrap().parent().unwrap().to_path_buf()
}

async fn dir_exists(path: &Path) -> Result<bool, std::io::Error> {
    match fs::metadata(path).await {
        Ok(metadata) => Ok(metadata.is_dir()),
        Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(false),
        Err(err) => Err(err),
    }
}

async fn read_patch_file(path: &Path) -> Result<Vec<PatchEntry>, String> {
    let content = fs::read_to_string(path).await.map_err(|e| e.to_string())?;
    let patches: Vec<PatchEntry> = serde_json::from_str(&content).map_err(|e| e.to_string())?;
    Ok(patches)
}

async fn emit_download_status(app_handle: &AppHandle, status: &str, additional_info: Option<String>,) -> Result<(), String> {
    app_handle.emit( "download_status", DownloadStatus { status: status.to_string(), additional_info, },).map_err(|e| e.to_string())
}

fn is_recoverable_error(_error: &str) -> bool {
    // Aqui você pode adicionar lógica para determinar se o erro é recuperável
    // Por simplicidade, vamos considerar todos os erros como recuperáveis
    true
}

async fn attempt_download_file(
    app_handle: &AppHandle,
    client: &Client,
    entry: &PatchEntry,
    url: &str,
    file_path: &Path,
    current_file: usize,
    total_files: usize,
) -> Result<(), String> {
    // Verificar se o arquivo já existe e obter o tamanho existente
    let existing_size = if file_path.exists() {
        fs::metadata(&file_path)
            .await
            .map_err(|e| e.to_string())?
            .len()
    } else {
        0
    };

    // Fazer uma requisição HEAD para obter o tamanho total do arquivo
    let head_response = client.head(url).send().await.map_err(|e| e.to_string())?;
    if !head_response.status().is_success() {
        return Err(format!(
            "Falha ao realizar HEAD para '{}': HTTP {}",
            entry.file_name,
            head_response.status()
        ));
    }

    let total_size = head_response
        .headers()
        .get("content-length")
        .and_then(|v| v.to_str().ok())
        .and_then(|s| s.parse::<u64>().ok())
        .unwrap_or(0);

    // Se o arquivo já estiver completamente baixado, pular o download
    if existing_size >= total_size && total_size > 0 {
        // Emitir informações de download para atualizar a UI
        app_handle.emit("download_info", DownloadInfo {
            current_file,
            total_files,
            file_name: entry.file_name.clone(),
            downloaded_bytes: existing_size,
            total_bytes: total_size,
            speed: 0.0,
        }).map_err(|e| e.to_string())?;

        return Ok(());
    }

    // Configurar a requisição GET com o cabeçalho Range para retomar o download
    let mut request = client.get(url);
    if existing_size > 0 {
        request = request.header("Range", format!("bytes={}-", existing_size));
    }

    let mut response = request.send().await.map_err(|e| e.to_string())?;

    if !response.status().is_success()
        && response.status() != reqwest::StatusCode::PARTIAL_CONTENT
    {
        return Err(format!(
            "Falha ao baixar '{}': HTTP {}",
            entry.file_name,
            response.status()
        ));
    }

    // Abrir o arquivo no modo apropriado (append ou create)
    use tokio::fs::OpenOptions;

    let mut file = if existing_size > 0 {
        OpenOptions::new()
            .append(true)
            .open(&file_path)
            .await
            .map_err(|e| e.to_string())?
    } else {
        fs::File::create(&file_path).await.map_err(|e| e.to_string())?
    };

    let mut downloaded_bytes = existing_size;
    let start_time = Instant::now();

    // Emitir status "Start"
    emit_download_status(app_handle, "Start", None).await?;

    let mut last_emit_time = Instant::now();
    let mut downloading_message_sent = false;

    let total_size = if total_size == 0 { existing_size } else { total_size };

    while let Some(chunk) = response.chunk().await.map_err(|e| e.to_string())? {
        file.write_all(&chunk).await.map_err(|e| e.to_string())?;
        downloaded_bytes += chunk.len() as u64;

        let now = Instant::now();
        if now.duration_since(last_emit_time) >= Duration::from_millis(200) {
            if !downloading_message_sent {
                emit_download_status(app_handle, "Downloading", None).await?;
                downloading_message_sent = true;
            }

            let elapsed_secs = start_time.elapsed().as_secs_f64();
            let speed = if elapsed_secs > 0.0 {
                (downloaded_bytes - existing_size) as f64 / elapsed_secs
            } else {
                0.0
            };

            app_handle.emit("download_info", DownloadInfo {
                current_file,
                total_files,
                file_name: entry.file_name.clone(),
                downloaded_bytes,
                total_bytes: total_size,
                speed,
            }).map_err(|e| e.to_string())?;
            last_emit_time = now;
        }
    }

    // Garantir que todos os dados foram gravados
    file.flush().await.map_err(|e| e.to_string())?;

    Ok(())
}

async fn download_file(
    app_handle: &AppHandle,
    client: &Client,
    entry: &PatchEntry,
    download_dir: &Path,
    current_file: usize,
    total_files: usize,
) -> Result<(), String> {
    let url = format!("https://hil-speed.hetzner.com/{}", entry.file_name);
    let file_path = download_dir.join(&entry.file_name);

    loop {
        match attempt_download_file(
            app_handle,
            client,
            entry,
            &url,
            &file_path,
            current_file,
            total_files,
        )
        .await
        {
            Ok(()) => {
                // Download concluído com sucesso
                return Ok(());
            }
            Err(e) => {
                if is_recoverable_error(&e) {
                    // Iniciar contagem regressiva para reconexão
                    let mut countdown = 15;
                    emit_download_status(
                        app_handle,
                        "ConnectionLost",
                        Some(countdown.to_string()),
                    )
                    .await?;

                    while countdown > 0 {
                        tokio::time::sleep(Duration::from_secs(1)).await;
                        countdown -= 1;

                        emit_download_status(
                            app_handle,
                            "Reconnecting",
                            Some(countdown.to_string()),
                        )
                        .await?;
                    }

                    // Após a contagem regressiva, tentar retomar o download
                    continue;
                } else {
                    // Erro não recuperável
                    let error_message = format!("Erro ao baixar '{}': {}", entry.file_name, e);
                    eprintln!("{}", error_message);
                    emit_download_status(app_handle, "Error", Some(error_message.clone()))
                        .await?;
                    return Err(error_message);
                }
            }
        }
    }
}

async fn check_server_connection(client: &Client, url: &str) -> Result<(), String> {
    let response = client.get(url).send().await.map_err(|e| e.to_string())?;
    if response.status().is_success() {
        Ok(())
    } else {
        Err(format!(
            "Falha ao conectar ao servidor: HTTP {}",
            response.status()
        ))
    }
}

#[tauri::command]
pub async fn start_downloads(app_handle: AppHandle) -> Result<(), String> {
    let exe_dir = get_exe_dir();

    // Definir caminhos
    let patch_file_path = exe_dir.join("patch.json");
    let download_dir = exe_dir.join("patchs");

    // Verificar se o diretório de download existe, criar se não existir
    if !dir_exists(&download_dir).await.map_err(|e| e.to_string())? {
        fs::create_dir_all(&download_dir)
            .await
            .map_err(|e| e.to_string())?;
    }

    // Ler os patches do arquivo JSON
    let patches = read_patch_file(&patch_file_path).await?;

    let client = Client::new();
    let total_files = patches.len();

    // Emitir status de conexão
    emit_download_status(&app_handle, "Connecting", None).await?;

    let server_url = "https://hil-speed.hetzner.com/";
    if let Err(err) = check_server_connection(&client, server_url).await {
        let error_message = format!("Erro ao conectar ao servidor: {}", err);
        eprintln!("{}", error_message);
        emit_download_status(&app_handle, "Error", Some(error_message.clone()))
            .await?;
        return Err(error_message);
    }

    emit_download_status(&app_handle, "Connected", None).await?;

    for (idx, entry) in patches.iter().enumerate() {
        let current_file = idx + 1;
        if let Err(err) = download_file(
            &app_handle,
            &client,
            entry,
            &download_dir,
            current_file,
            total_files,
        )
        .await
        {
            let error_message = format!("Erro ao baixar '{}': {}", entry.file_name, err);
            eprintln!("{}", error_message);
            emit_download_status(&app_handle, "Error", Some(error_message.clone()))
                .await?;
            return Err(error_message);
        }
    }

    // Emitir status de conclusão
    emit_download_status(&app_handle, "Completed", None).await?;

    Ok(())
}

No react eu tenho

import { useEffect, useState } from "react";
import { listen } from "@tauri-apps/api/event";
import { invoke } from "@tauri-apps/api/core";

function formatBytes(bytes: number) {
  if (bytes === 0) return "0 B";
  const k = 1024;
  const units = ["B", "KB", "MB", "GB", "TB", "PB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  const value = bytes / Math.pow(k, i);
  return `${value.toFixed(2)} ${units[i]}`;
}

enum DownloadStatusType {
  Connecting = "Connecting",
  Connected = "Connected",
  Start = "Start",
  Downloading = "Downloading",
  Completed = "Completed",
  ConnectionLost = "ConnectionLost",
  Reconnecting = "Reconnecting",
  Error = "Error",
}

interface DownloadStatus {
  status: DownloadStatusType;
  additional_info?: string;
}

interface DownloadInfo {
  current_file: number;
  total_files: number;
  file_name: string;
  downloaded_bytes: number;
  total_bytes: number;
  speed: number;
}

const DownloadManager = () => {
  const [message, setMessage] = useState("");
  const [currentFile, setCurrentFile] = useState(0);
  const [totalFiles, setTotalFiles] = useState(0);
  const [fileName, setFileName] = useState("");
  const [downloadedBytes, setDownloadedBytes] = useState(0);
  const [totalBytes, setTotalBytes] = useState(0);
  const [downloadSpeed, setDownloadSpeed] = useState(0);
  const [isDownloading, setIsDownloading] = useState(false);

  useEffect(() => {
    let unlistenStatus: (() => void) | null = null;
    let unlistenInfo: (() => void) | null = null;
    let unlistenSpeed: (() => void) | null = null;

    (async () => {
      unlistenStatus = await listen<DownloadStatus>("download_status", (event) => {
        const { status, additional_info } = event.payload;

        let newMessage = "";

        switch (status) {
          case DownloadStatusType.Connecting:
            newMessage = "Conectando ao servidor...";
            break;
          case DownloadStatusType.Connected:
            newMessage = "Conexão estabelecida com sucesso";
            break;
          case DownloadStatusType.Start:
            newMessage = "Iniciando download...";
            break;
          case DownloadStatusType.Downloading:
            newMessage = "Baixando arquivo";
            break;
          case DownloadStatusType.Completed:
            newMessage = "Atualizações concluídas com sucesso.";
            break;
          case DownloadStatusType.ConnectionLost:
          case DownloadStatusType.Reconnecting:
            newMessage = `Conexão perdida. Tentando reconectar em ${additional_info} segundos...`;
            break;
          case DownloadStatusType.Error:
            newMessage = `Erro: ${additional_info}`;
            break;
          default:
            newMessage = "Status desconhecido";
        }

        setMessage(newMessage);

        if (status === DownloadStatusType.Downloading) {
          setIsDownloading(true);
        } else if (status === DownloadStatusType.Completed || status === DownloadStatusType.Error) {
          setIsDownloading(false);
        }
      });

      unlistenInfo = await listen<DownloadInfo>("download_info", (event) => {
        const {
          current_file,
          total_files,
          file_name,
          downloaded_bytes,
          total_bytes,
          speed,
        } = event.payload;

        setCurrentFile(current_file);
        setTotalFiles(total_files);
        setFileName(file_name);
        setDownloadedBytes(downloaded_bytes);
        setTotalBytes(total_bytes);
        setDownloadSpeed(speed);
      });
    })();

    return () => {
      if (unlistenStatus) unlistenStatus();
      if (unlistenInfo) unlistenInfo();
      if (unlistenSpeed) unlistenSpeed();
    };
  }, [currentFile, totalFiles, downloadedBytes, totalBytes, downloadSpeed]);

  const startDownload = async () => {
    if (isDownloading) return;
    setIsDownloading(true);

    // Resetar o estado ao iniciar um novo download
    setMessage("");
    setCurrentFile(0);
    setTotalFiles(0);
    setFileName("");
    setDownloadedBytes(0);
    setTotalBytes(0);
    setDownloadSpeed(0);

    try {
      await invoke("start_downloads");
    } catch (error) {
      setMessage(`Erro ao iniciar o download: ${error}`);
      setIsDownloading(false);
    }
  };

  const progressPercent =
    downloadedBytes > 0 && totalBytes > 0 ? (downloadedBytes / totalBytes) * 100 : 0;

  return (
    <>
      <div className="absolute bottom-20 rounded-lg w-[71%] h-[8%] flex flex-col justify-between items-center">
        <button onClick={startDownload} className="bg-blue-500 text-white rounded p-2 mb-2">
          Iniciar Download
        </button>
      </div>
      <div className="absolute bottom-3 rounded-lg w-[71%] h-[8%] flex flex-col justify-between items-center">
        <div className="w-full flex items-center">
          <p className="text-[12px] font-bold text-opacity-[0.95] text-white flex-grow text-center">
            {message}
            {isDownloading && totalFiles > 0 && downloadedBytes > 0 && totalBytes > 0 && (
              <>
              <span className="mx-1">
                ( <span className="text-blue-400">{currentFile}</span> / {totalFiles} )
              </span>
                : <span className="text-orange-500">{fileName}</span>
                <span className="mx-1">
                  ( <span className="text-green-600">{formatBytes(downloadedBytes)}</span> / {formatBytes(totalBytes)} )
                </span>
              </>
            )}
          </p>
        </div>
        {isDownloading && totalFiles > 0 && downloadedBytes > 0 && totalBytes > 0 && (
          <div className="w-[30%] absolute h-6 flex justify-end items-center right-6 top-2">
            <span className="text-[11px] font-bold text-opacity-[0.95] text-yellow-600 text-right">
              {formatBytes(downloadSpeed)}ps
            </span>
          </div>
        )}
        <div className="w-[95%] bg-[#0E1622]/[0.95] text-green-600 rounded-md h-6 flex items-center shadow-inner shadow-gray-800">
          <div
            className="bg-[#1164CA]/[0.95] ml-1 rounded-md h-4"
            style={{ width: `${progressPercent}%` }}
          />
        </div>
      </div>
    </>
  );
};

export default DownloadManager;


os arquivos não estão sendo baixados, ele só fica tentando se reconectar mesmo tendo internet e o site funcionando normalmente