Initial project import

This commit is contained in:
Alexey Barabanov
2026-04-14 18:53:15 +03:00
commit 6400c258da
5 changed files with 2993 additions and 0 deletions

1357
src/lib.rs Normal file

File diff suppressed because it is too large Load Diff

133
src/main.rs Normal file
View File

@@ -0,0 +1,133 @@
use dotenv::dotenv;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use serde_json::Value;
use ae_anons::{SynologyClient, SynologyError};
#[tokio::main]
async fn main() -> Result<(), SynologyError> {
dotenv().ok();
let nas_fqdn = env::var("NAS_FQDN").expect("❌ Переменная NAS_FQDN не задана в .env");
let nas_user = env::var("NAS_USER").expect("❌ Переменная NAS_USER не задана в .env");
let nas_pass = env::var("NAS_PASS").expect("❌ Переменная NAS_PASS не задана в .env");
let nas_file = env::var("NAS_FILE").expect("❌ Переменная NAS_FILE не задана в .env");
let mut client = SynologyClient::new(&nas_fqdn);
client.login(&nas_user, &nas_pass).await?;
println!("✅ Logged in");
let info = client.get_info().await?;
println!("📡 Connected to: {}", info.hostname);
// Получаем имя файла и ожидаемый путь
let file_name_full = Path::new(&nas_file).file_name().unwrap().to_str().unwrap();
let search_name = file_name_full.replace(".osheet", "");
let expected_path = Path::new(&nas_file).parent().unwrap().to_str().unwrap();
// Преобразуем путь в формат API (Team Folder -> team-folders, убираем пробелы, приводим к нижнему регистру)
let api_format_path = expected_path
.replace("Team Folder", "team-folders")
.replace(" ", "");
let full_expected_path_api = format!("{}/{}", api_format_path, file_name_full);
println!("\n🔍 Looking for exact file: {}", full_expected_path_api);
println!(" (converted from: {})", nas_file);
// Ищем файл по имени
let search_result = client.search_file_by_name(&search_name).await?;
// Извлекаем все найденные файлы
let items = search_result["data"]["items"].as_array()
.ok_or_else(|| SynologyError::InvalidResponseFormat("No items in search result".to_string()))?;
if items.is_empty() {
return Err(SynologyError::Api {
code: 404,
message: Some(format!("File '{}' not found", file_name_full)),
});
}
// Ищем файл с точным совпадением пути (в формате API)
let exact_match: Vec<&Value> = items.iter()
.filter(|item| {
let display_path = item.get("display_path")
.and_then(|p| p.as_str())
.unwrap_or("");
display_path == full_expected_path_api
})
.collect();
if exact_match.is_empty() {
println!("\n⚠️ File not found at exact path: {}", full_expected_path_api);
println!(" Found {} file(s) with similar name:", items.len());
for (i, item) in items.iter().enumerate() {
let name = item.get("name")
.and_then(|n| n.as_str())
.unwrap_or("unknown");
let display_path = item.get("display_path")
.and_then(|p| p.as_str())
.unwrap_or("unknown");
let file_id = item.get("file_id")
.and_then(|id| id.as_str())
.unwrap_or("unknown");
println!(" {}. {} (at: {}, ID: {})", i + 1, name, display_path, file_id);
}
return Err(SynologyError::Api {
code: 400,
message: Some(format!("File not found at: {}", full_expected_path_api)),
});
}
if exact_match.len() > 1 {
println!("\n⚠️ Found {} files at the same location!", exact_match.len());
return Err(SynologyError::Api {
code: 400,
message: Some("Multiple files found at the same location".to_string()),
});
}
// Берём единственный подходящий файл
let file = exact_match[0];
let file_id = file["file_id"]
.as_str()
.ok_or_else(|| SynologyError::InvalidResponseFormat("Missing file_id".to_string()))?;
let actual_file_name = file["name"]
.as_str()
.ok_or_else(|| SynologyError::InvalidResponseFormat("Missing name".to_string()))?;
let actual_path = file["display_path"]
.as_str()
.unwrap_or("unknown");
println!(" 📄 Found exact match: {} at {}", actual_file_name, actual_path);
println!(" 📄 File ID: {}", file_id);
// Экспортируем файл
println!("\n📊 Exporting file...");
match client.export_by_file_id(file_id, actual_file_name).await {
Ok(data) => {
let output_path = format!("./{}_export.xlsx", search_name);
let mut file = File::create(&output_path)?;
file.write_all(&data)?;
println!(" ✅ Exported to: {} ({} bytes)", output_path, data.len());
}
Err(e) => {
println!(" ❌ Export failed: {}", e);
}
}
client.logout().await?;
println!("\n👋 Logged out");
Ok(())
}