Initial project import
This commit is contained in:
1357
src/lib.rs
Normal file
1357
src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
133
src/main.rs
Normal file
133
src/main.rs
Normal 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(())
|
||||
}
|
||||
Reference in New Issue
Block a user