fix: Fix some logic
1) Now code checking lockal rclone before install it 2) fix function to install rclone on device if it doesn`t exists
This commit is contained in:
1 parent
a8af4b4abf
commit
5c26c57efe
1 file changed
+43
-169
+43
-169
@@ -13,7 +13,8 @@ pub struct RcloneApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RcloneApp {
|
impl RcloneApp {
|
||||||
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
|
pub async fn new() -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
|
// Сначала проверяем системный rclone
|
||||||
if let Some(system_rclone) = Self::check_system_rclone() {
|
if let Some(system_rclone) = Self::check_system_rclone() {
|
||||||
println!("Найден системный rclone: {:?}", system_rclone);
|
println!("Найден системный rclone: {:?}", system_rclone);
|
||||||
return Ok(Self {
|
return Ok(Self {
|
||||||
@@ -21,27 +22,29 @@ impl RcloneApp {
|
|||||||
using_system_rclone: true,
|
using_system_rclone: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
println!("Системный rclone не найден, использую встроенную версию");
|
|
||||||
|
|
||||||
|
// Проверяем в директории приложения
|
||||||
let app_dir = dirs::data_dir()
|
let app_dir = dirs::data_dir()
|
||||||
.ok_or("Не удалось найти папку для данных")?
|
.ok_or("Не удалось найти папку для данных")?
|
||||||
.join("rclone-ui");
|
.join("rclone-ui");
|
||||||
|
|
||||||
fs::create_dir_all(&app_dir)?;
|
|
||||||
let rclone_path = if cfg!(windows) {
|
let rclone_path = if cfg!(windows) {
|
||||||
app_dir.join("rclone.exe")
|
app_dir.join("rclone.exe")
|
||||||
} else {
|
} else {
|
||||||
app_dir.join("rclone")
|
app_dir.join("rclone")
|
||||||
};
|
};
|
||||||
|
|
||||||
/*if !rclone_path.exists() {
|
if rclone_path.exists() {
|
||||||
Self::extract_rclone(&rclone_path)?;
|
println!("Найден rclone в директории приложения: {:?}", rclone_path);
|
||||||
}*/
|
return Ok(Self {
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
rclone_path,
|
rclone_path,
|
||||||
using_system_rclone: false,
|
using_system_rclone: false,
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если ничего не найдено - устанавливаем
|
||||||
|
println!("rclone не найден. Начинаю установку...");
|
||||||
|
Self::install_latest_rclone().await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_system_rclone() -> Option<PathBuf> {
|
fn check_system_rclone() -> Option<PathBuf> {
|
||||||
@@ -59,119 +62,10 @@ impl RcloneApp {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/*fn extract_rclone(dest_path: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
async fn install_latest_rclone() -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
println!("Устанавливаю rclone в {:?}", dest_path);
|
|
||||||
|
|
||||||
let rclone_bytes = unsafe {
|
|
||||||
// unsafe блок, возвращающий значение
|
|
||||||
if cfg!(windows) {
|
|
||||||
include_bytes!("../bin/rclone.exe")
|
|
||||||
} else if cfg!(target_os = "linux") {
|
|
||||||
include_bytes!("../bin/rclone")
|
|
||||||
} else if cfg!(target_os = "macos") {
|
|
||||||
include_bytes!("../bin/rclone")
|
|
||||||
} else {
|
|
||||||
panic!("Неподдерживаемая ОС");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fs::write(dest_path, rclone_bytes)?;
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
{
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
let mut perms = fs::metadata(dest_path)?.permissions();
|
|
||||||
perms.set_mode(0o755);
|
|
||||||
fs::set_permissions(dest_path, perms)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("rclone успешно установлен!");
|
|
||||||
Ok(())
|
|
||||||
}*/
|
|
||||||
|
|
||||||
fn run_command(&self, args: &[&str]) -> Result<String, String> {
|
|
||||||
let output = Command::new(&self.rclone_path)
|
|
||||||
.args(args)
|
|
||||||
.output()
|
|
||||||
.map_err(|e| format!("Ошибка запуска: {}", e))?;
|
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
|
||||||
} else {
|
|
||||||
Err(String::from_utf8_lossy(&output.stderr).to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Асинхронная функция для проверки наличия и версии rclone
|
|
||||||
/// Возвращает:
|
|
||||||
/// 0 - rclone установлен и актуален
|
|
||||||
/// 1 - требуется установка или обновление
|
|
||||||
pub async fn check_rclone_status_async() -> Result<i32, Box<dyn std::error::Error>> {
|
|
||||||
if let Some(system_rclone) = RcloneApp::check_system_rclone() {
|
|
||||||
println!("Найден системный rclone: n{:?}", system_rclone);
|
|
||||||
|
|
||||||
let output = Command::new(&system_rclone)
|
|
||||||
.arg("version")
|
|
||||||
.output()
|
|
||||||
.map_err(|e| format!("Ошибка получения версии: {}", e))?;
|
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
let version_output = String::from_utf8_lossy(&output.stdout);
|
|
||||||
println!("Версия rclone: {}", version_output);
|
|
||||||
|
|
||||||
if is_version_recent(&version_output) {
|
|
||||||
return Ok(0);
|
|
||||||
} else {
|
|
||||||
println!("Версия rclone устарела, требуется обновление");
|
|
||||||
return Ok(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let app_dir = dirs::data_dir()
|
|
||||||
.ok_or("Не удалось найти папку для данных")?
|
|
||||||
.join("rclone-ui");
|
|
||||||
|
|
||||||
let rclone_path = if cfg!(windows) {
|
|
||||||
app_dir.join("rclone.exe")
|
|
||||||
} else {
|
|
||||||
app_dir.join("rclone")
|
|
||||||
};
|
|
||||||
|
|
||||||
if rclone_path.exists() {
|
|
||||||
println!("Найден rclone в директории приложения");
|
|
||||||
|
|
||||||
let output = Command::new(&rclone_path)
|
|
||||||
.arg("version")
|
|
||||||
.output()
|
|
||||||
.map_err(|e| format!("Ошибка получения версии: {}", e))?;
|
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
let version_output = String::from_utf8_lossy(&output.stdout);
|
|
||||||
|
|
||||||
if is_version_recent(&version_output) {
|
|
||||||
return Ok(0);
|
|
||||||
} else {
|
|
||||||
println!("Версия rclone в директории приложения устарела");
|
|
||||||
return Ok(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("rclone не найден, требуется установка");
|
|
||||||
Ok(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Вспомогательная функция для проверки актуальности версии
|
|
||||||
fn is_version_recent(version_output: &str) -> bool {
|
|
||||||
!version_output.contains("rclone v1.55")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Асинхронная функция для установки последней версии rclone из GitHub
|
|
||||||
pub async fn install_latest_rclone() -> Result<RcloneApp, Box<dyn std::error::Error>> {
|
|
||||||
println!("Начинаю установку последней версии rclone...");
|
println!("Начинаю установку последней версии rclone...");
|
||||||
|
|
||||||
|
// Определяем ОС и архитектуру
|
||||||
let os = if cfg!(target_os = "linux") {
|
let os = if cfg!(target_os = "linux") {
|
||||||
"linux"
|
"linux"
|
||||||
} else if cfg!(target_os = "macos") {
|
} else if cfg!(target_os = "macos") {
|
||||||
@@ -192,7 +86,7 @@ pub async fn install_latest_rclone() -> Result<RcloneApp, Box<dyn std::error::Er
|
|||||||
return Err("Неподдерживаемая архитектура".into());
|
return Err("Неподдерживаемая архитектура".into());
|
||||||
};
|
};
|
||||||
|
|
||||||
// Получаем актуальную версию через API GitHub
|
// Получаем информацию о последнем релизе
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let latest_release: serde_json::Value = client
|
let latest_release: serde_json::Value = client
|
||||||
.get("https://api.github.com/repos/rclone/rclone/releases/latest")
|
.get("https://api.github.com/repos/rclone/rclone/releases/latest")
|
||||||
@@ -205,31 +99,31 @@ pub async fn install_latest_rclone() -> Result<RcloneApp, Box<dyn std::error::Er
|
|||||||
let version = latest_release["tag_name"]
|
let version = latest_release["tag_name"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.ok_or("Не удалось получить версию")?
|
.ok_or("Не удалось получить версию")?
|
||||||
.trim_start_matches('v'); // Убираем 'v' из начала версии если есть
|
.trim_start_matches('v');
|
||||||
|
|
||||||
// Всегда используем .zip формат для всех ОС
|
// Формируем URL для скачивания
|
||||||
let download_url = format!(
|
let download_url = format!(
|
||||||
"https://github.com/rclone/rclone/releases/download/v{}/rclone-v{}-{}-{}.zip",
|
"https://github.com/rclone/rclone/releases/download/v{}/rclone-v{}-{}-{}.zip",
|
||||||
version, version, os, arch
|
version, version, os, arch
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("Скачиваю rclone с: {}", download_url);
|
println!("Скачиваю rclone версии {} с: {}", version, download_url);
|
||||||
|
|
||||||
|
// Скачиваем архив
|
||||||
let response = client.get(&download_url).send().await?;
|
let response = client.get(&download_url).send().await?;
|
||||||
|
|
||||||
if !response.status().is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(format!("Ошибка скачивания: HTTP {}", response.status()).into());
|
return Err(format!("Ошибка скачивания: HTTP {}", response.status()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let bytes = response.bytes().await?;
|
let bytes = response.bytes().await?;
|
||||||
|
|
||||||
|
// Создаем директорию приложения
|
||||||
let app_dir = dirs::data_dir()
|
let app_dir = dirs::data_dir()
|
||||||
.ok_or("Не удалось найти папку для данных")?
|
.ok_or("Не удалось найти папку для данных")?
|
||||||
.join("rclone-ui");
|
.join("rclone-ui");
|
||||||
|
|
||||||
fs::create_dir_all(&app_dir)?;
|
fs::create_dir_all(&app_dir)?;
|
||||||
|
|
||||||
// Определяем имя исполняемого файла в зависимости от ОС
|
// Определяем имя исполняемого файла
|
||||||
let rclone_filename = if cfg!(windows) {
|
let rclone_filename = if cfg!(windows) {
|
||||||
"rclone.exe"
|
"rclone.exe"
|
||||||
} else {
|
} else {
|
||||||
@@ -237,49 +131,20 @@ pub async fn install_latest_rclone() -> Result<RcloneApp, Box<dyn std::error::Er
|
|||||||
};
|
};
|
||||||
let rclone_path = app_dir.join(rclone_filename);
|
let rclone_path = app_dir.join(rclone_filename);
|
||||||
|
|
||||||
// Распаковываем zip архив (для всех ОС)
|
// Распаковываем архив
|
||||||
use std::io::Cursor;
|
|
||||||
use zip::read::ZipArchive;
|
use zip::read::ZipArchive;
|
||||||
|
|
||||||
let cursor = Cursor::new(bytes);
|
let cursor = Cursor::new(bytes);
|
||||||
let mut archive = ZipArchive::new(cursor)?;
|
let mut archive = ZipArchive::new(cursor)?;
|
||||||
|
|
||||||
let mut extracted = false;
|
let mut extracted = false;
|
||||||
|
|
||||||
for i in 0..archive.len() {
|
for i in 0..archive.len() {
|
||||||
let mut file = archive.by_index(i)?;
|
let mut file = archive.by_index(i)?;
|
||||||
let file_name = file.name().to_string(); // Сохраняем имя в отдельную переменную
|
let file_name = file.name().to_string();
|
||||||
|
|
||||||
// Ищем файл rclone или rclone.exe в архиве
|
|
||||||
if file_name.ends_with("rclone") || file_name.ends_with("rclone.exe") {
|
if file_name.ends_with("rclone") || file_name.ends_with("rclone.exe") {
|
||||||
// Определяем путь для распаковки
|
|
||||||
let output_path = if file_name.contains('/') || file_name.contains('\\') {
|
|
||||||
// Если файл в подпапке, создаем временный путь
|
|
||||||
let temp_path = app_dir.join("temp_rclone");
|
|
||||||
fs::create_dir_all(&temp_path)?;
|
|
||||||
temp_path.join(
|
|
||||||
file_name
|
|
||||||
.split(|c| c == '/' || c == '\\')
|
|
||||||
.last()
|
|
||||||
.unwrap_or(rclone_filename),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
app_dir.join(&file_name)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Распаковываем файл
|
|
||||||
let mut contents = Vec::new();
|
let mut contents = Vec::new();
|
||||||
std::io::copy(&mut file, &mut contents)?;
|
std::io::copy(&mut file, &mut contents)?;
|
||||||
fs::write(&output_path, contents)?;
|
fs::write(&rclone_path, contents)?;
|
||||||
|
|
||||||
// Перемещаем в нужное место если необходимо
|
|
||||||
if output_path != rclone_path {
|
|
||||||
if rclone_path.exists() {
|
|
||||||
fs::remove_file(&rclone_path)?;
|
|
||||||
}
|
|
||||||
fs::rename(output_path, &rclone_path)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
extracted = true;
|
extracted = true;
|
||||||
println!("Найден и распакован: {}", file_name);
|
println!("Найден и распакован: {}", file_name);
|
||||||
break;
|
break;
|
||||||
@@ -290,12 +155,6 @@ pub async fn install_latest_rclone() -> Result<RcloneApp, Box<dyn std::error::Er
|
|||||||
return Err("Не удалось найти исполняемый файл rclone в архиве".into());
|
return Err("Не удалось найти исполняемый файл rclone в архиве".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Удаляем временную папку если она была создана
|
|
||||||
let temp_path = app_dir.join("temp_rclone");
|
|
||||||
if temp_path.exists() {
|
|
||||||
fs::remove_dir_all(temp_path)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Устанавливаем права на выполнение для Unix систем
|
// Устанавливаем права на выполнение для Unix систем
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
{
|
{
|
||||||
@@ -316,13 +175,28 @@ pub async fn install_latest_rclone() -> Result<RcloneApp, Box<dyn std::error::Er
|
|||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
let version_output = String::from_utf8_lossy(&output.stdout);
|
let version_output = String::from_utf8_lossy(&output.stdout);
|
||||||
println!("Установленная версия rclone:\n{}", version_output);
|
println!("Установленная версия rclone:\n{}", version_output);
|
||||||
} else {
|
|
||||||
let error = String::from_utf8_lossy(&output.stderr);
|
|
||||||
return Err(format!("Ошибка при проверке версии rclone: {}", error).into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(RcloneApp {
|
Ok(Self {
|
||||||
rclone_path,
|
rclone_path,
|
||||||
using_system_rclone: false,
|
using_system_rclone: false,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_command(&self, args: &[&str]) -> Result<String, String> {
|
||||||
|
let output = Command::new(&self.rclone_path)
|
||||||
|
.args(args)
|
||||||
|
.output()
|
||||||
|
.map_err(|e| format!("Ошибка запуска: {}", e))?;
|
||||||
|
|
||||||
|
if output.status.success() {
|
||||||
|
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
||||||
|
} else {
|
||||||
|
Err(String::from_utf8_lossy(&output.stderr).to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn version(&self) -> Result<String, String> {
|
||||||
|
self.run_command(&["version"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user