mirror of
https://github.com/OpenListTeam/OpenList-Desktop.git
synced 2025-11-25 11:18:32 +08:00
refactor: increase timeout for rclone API requests and refactor some files
This commit is contained in:
@@ -114,7 +114,7 @@ async fn is_rclone_running() -> bool {
|
|||||||
|
|
||||||
let response = client
|
let response = client
|
||||||
.get(format!("{RCLONE_API_BASE}/"))
|
.get(format!("{RCLONE_API_BASE}/"))
|
||||||
.timeout(Duration::from_secs(1))
|
.timeout(Duration::from_secs(3))
|
||||||
.send()
|
.send()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ use std::fs;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde_json::json;
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde_json::{Value, json};
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
use super::http_api::get_process_list;
|
use super::http_api::get_process_list;
|
||||||
@@ -15,102 +16,101 @@ use crate::utils::api::{CreateProcessResponse, ProcessConfig, get_api_key, get_s
|
|||||||
use crate::utils::args::split_args_vec;
|
use crate::utils::args::split_args_vec;
|
||||||
use crate::utils::path::{get_app_logs_dir, get_rclone_binary_path};
|
use crate::utils::path::{get_app_logs_dir, get_rclone_binary_path};
|
||||||
|
|
||||||
|
struct RcloneApi {
|
||||||
|
client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RcloneApi {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
client: Client::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post_json<T: DeserializeOwned>(
|
||||||
|
&self,
|
||||||
|
endpoint: &str,
|
||||||
|
body: Option<Value>,
|
||||||
|
) -> Result<T, String> {
|
||||||
|
let url = format!("{RCLONE_API_BASE}/{endpoint}");
|
||||||
|
let mut req = self.client.post(&url).header("Authorization", RCLONE_AUTH);
|
||||||
|
if let Some(b) = body {
|
||||||
|
req = req.json(&b).header("Content-Type", "application/json");
|
||||||
|
}
|
||||||
|
let resp = req
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Request failed: {e}"))?;
|
||||||
|
let status = resp.status();
|
||||||
|
if status.is_success() {
|
||||||
|
resp.json::<T>()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to parse JSON: {e}"))
|
||||||
|
} else {
|
||||||
|
let txt = resp.text().await.unwrap_or_default();
|
||||||
|
Err(format!("API error {status}: {txt}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post_text(&self, endpoint: &str) -> Result<String, String> {
|
||||||
|
let url = format!("{RCLONE_API_BASE}/{endpoint}");
|
||||||
|
let resp = self
|
||||||
|
.client
|
||||||
|
.post(&url)
|
||||||
|
.header("Authorization", RCLONE_AUTH)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Request failed: {e}"))?;
|
||||||
|
let status = resp.status();
|
||||||
|
if status.is_success() {
|
||||||
|
resp.text()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to read text: {e}"))
|
||||||
|
} else {
|
||||||
|
let txt = resp.text().await.unwrap_or_default();
|
||||||
|
Err(format!("API error {status}: {txt}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn rclone_list_config(
|
pub async fn rclone_list_config(
|
||||||
remote_type: String,
|
remote_type: String,
|
||||||
_state: State<'_, AppState>,
|
_state: State<'_, AppState>,
|
||||||
) -> Result<serde_json::Value, String> {
|
) -> Result<Value, String> {
|
||||||
let client = Client::new();
|
let api = RcloneApi::new();
|
||||||
let response = client
|
let text = api.post_text("config/dump").await?;
|
||||||
.post(format!("{RCLONE_API_BASE}/config/dump"))
|
let all: Value = serde_json::from_str(&text).map_err(|e| format!("Invalid JSON: {}", e))?;
|
||||||
.header("Authorization", RCLONE_AUTH)
|
let remotes = match (remote_type.as_str(), all.as_object()) {
|
||||||
.send()
|
("", _) => all.clone(),
|
||||||
.await
|
(t, Some(map)) => {
|
||||||
.map_err(|e| format!("Failed to send request: {e}"))?;
|
let filtered = map
|
||||||
if response.status().is_success() {
|
.iter()
|
||||||
let response_text = response
|
.filter_map(|(name, cfg)| {
|
||||||
.text()
|
cfg.get("type")
|
||||||
.await
|
.and_then(Value::as_str)
|
||||||
.map_err(|e| format!("Failed to read response text: {e}"))?;
|
.filter(|&ty| ty == t)
|
||||||
let json: serde_json::Value = serde_json::from_str(&response_text)
|
.map(|_| (name.clone(), cfg.clone()))
|
||||||
.map_err(|e| format!("Failed to parse JSON: {e}"))?;
|
})
|
||||||
let remotes = if remote_type.is_empty() {
|
.collect();
|
||||||
json.clone()
|
Value::Object(filtered)
|
||||||
} else if let Some(obj) = json.as_object() {
|
}
|
||||||
let mut filtered_map = serde_json::Map::new();
|
_ => Value::Object(Default::default()),
|
||||||
for (remote_name, remote_config) in obj {
|
};
|
||||||
if let Some(config_obj) = remote_config.as_object()
|
Ok(remotes)
|
||||||
&& let Some(remote_type_value) = config_obj.get("type")
|
|
||||||
&& let Some(type_str) = remote_type_value.as_str()
|
|
||||||
&& type_str == remote_type
|
|
||||||
{
|
|
||||||
filtered_map.insert(remote_name.clone(), remote_config.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
serde_json::Value::Object(filtered_map)
|
|
||||||
} else {
|
|
||||||
serde_json::Value::Object(serde_json::Map::new())
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(remotes)
|
|
||||||
} else {
|
|
||||||
Err(format!(
|
|
||||||
"Failed to list Rclone config: {}",
|
|
||||||
response.status()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn rclone_list_remotes() -> Result<Vec<String>, String> {
|
pub async fn rclone_list_remotes() -> Result<Vec<String>, String> {
|
||||||
let client = Client::new();
|
let api = RcloneApi::new();
|
||||||
|
let resp: RcloneRemoteListResponse = api.post_json("config/listremotes", None).await?;
|
||||||
let response = client
|
Ok(resp.remotes)
|
||||||
.post(format!("{RCLONE_API_BASE}/config/listremotes"))
|
|
||||||
.header("Authorization", RCLONE_AUTH)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Failed to list remotes: {e}"))?;
|
|
||||||
|
|
||||||
if response.status().is_success() {
|
|
||||||
let remote_list: RcloneRemoteListResponse = response
|
|
||||||
.json()
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Failed to parse remote list response: {e}"))?;
|
|
||||||
Ok(remote_list.remotes)
|
|
||||||
} else {
|
|
||||||
let error_text = response
|
|
||||||
.text()
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|_| "Unknown error".to_string());
|
|
||||||
Err(format!("Failed to list remotes: {error_text}"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn rclone_list_mounts() -> Result<RcloneMountListResponse, String> {
|
pub async fn rclone_list_mounts() -> Result<RcloneMountListResponse, String> {
|
||||||
let client = Client::new();
|
let api = RcloneApi::new();
|
||||||
|
api.post_json("mount/listmounts", None).await
|
||||||
let response = client
|
|
||||||
.post(format!("{RCLONE_API_BASE}/mount/listmounts"))
|
|
||||||
.header("Authorization", RCLONE_AUTH)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Failed to list mounts: {e}"))?;
|
|
||||||
|
|
||||||
if response.status().is_success() {
|
|
||||||
let mount_list: RcloneMountListResponse = response
|
|
||||||
.json()
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Failed to parse mount list response: {e}"))?;
|
|
||||||
Ok(mount_list)
|
|
||||||
} else {
|
|
||||||
let error_text = response
|
|
||||||
.text()
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|_| "Unknown error".to_string());
|
|
||||||
Err(format!("Failed to list mounts: {error_text}"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -120,37 +120,15 @@ pub async fn rclone_create_remote(
|
|||||||
config: RcloneWebdavConfig,
|
config: RcloneWebdavConfig,
|
||||||
_state: State<'_, AppState>,
|
_state: State<'_, AppState>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
let client = Client::new();
|
let api = RcloneApi::new();
|
||||||
|
let req = RcloneCreateRemoteRequest {
|
||||||
let create_request = RcloneCreateRemoteRequest {
|
name,
|
||||||
name: name.clone(),
|
r#type,
|
||||||
r#type: r#type.clone(),
|
parameters: config,
|
||||||
parameters: crate::conf::rclone::RcloneWebdavConfig {
|
|
||||||
url: config.url.clone(),
|
|
||||||
vendor: config.vendor.clone(),
|
|
||||||
user: config.user.clone(),
|
|
||||||
pass: config.pass.clone(),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
api.post_json::<Value>("config/create", Some(json!(req)))
|
||||||
let response = client
|
|
||||||
.post(format!("{RCLONE_API_BASE}/config/create"))
|
|
||||||
.header("Authorization", RCLONE_AUTH)
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.json(&create_request)
|
|
||||||
.send()
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Failed to create remote config: {e}"))?;
|
.map(|_| true)
|
||||||
|
|
||||||
if response.status().is_success() {
|
|
||||||
Ok(true)
|
|
||||||
} else {
|
|
||||||
let error_text = response
|
|
||||||
.text()
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|_| "Unknown error".to_string());
|
|
||||||
Err(format!("Failed to create remote config: {error_text}"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -160,26 +138,11 @@ pub async fn rclone_update_remote(
|
|||||||
config: RcloneWebdavConfig,
|
config: RcloneWebdavConfig,
|
||||||
_state: State<'_, AppState>,
|
_state: State<'_, AppState>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
let client = Client::new();
|
let api = RcloneApi::new();
|
||||||
|
let body = json!({ "name": name, "type": r#type, "parameters": config });
|
||||||
let response = client
|
api.post_json::<Value>("config/update", Some(body))
|
||||||
.post(format!("{RCLONE_API_BASE}/config/update"))
|
|
||||||
.header("Authorization", RCLONE_AUTH)
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.json(&json!({ "name": name, "type": r#type, "parameters": config }))
|
|
||||||
.send()
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Failed to update remote config: {e}"))?;
|
.map(|_| true)
|
||||||
|
|
||||||
if response.status().is_success() {
|
|
||||||
Ok(true)
|
|
||||||
} else {
|
|
||||||
let error_text = response
|
|
||||||
.text()
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|_| "Unknown error".to_string());
|
|
||||||
Err(format!("Failed to update remote config: {error_text}"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -187,26 +150,11 @@ pub async fn rclone_delete_remote(
|
|||||||
name: String,
|
name: String,
|
||||||
_state: State<'_, AppState>,
|
_state: State<'_, AppState>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
let client = Client::new();
|
let api = RcloneApi::new();
|
||||||
|
let body = json!({ "name": name });
|
||||||
let response = client
|
api.post_json::<Value>("config/delete", Some(body))
|
||||||
.post(format!("{RCLONE_API_BASE}/config/delete"))
|
|
||||||
.header("Authorization", RCLONE_AUTH)
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.json(&json!({ "name": name }))
|
|
||||||
.send()
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Failed to delete remote config: {e}"))?;
|
.map(|_| true)
|
||||||
|
|
||||||
if response.status().is_success() {
|
|
||||||
Ok(true)
|
|
||||||
} else {
|
|
||||||
let error_text = response
|
|
||||||
.text()
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|_| "Unknown error".to_string());
|
|
||||||
Err(format!("Failed to delete remote config: {error_text}"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -214,26 +162,10 @@ pub async fn rclone_mount_remote(
|
|||||||
mount_request: RcloneMountRequest,
|
mount_request: RcloneMountRequest,
|
||||||
_state: State<'_, AppState>,
|
_state: State<'_, AppState>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
let client = Client::new();
|
let api = RcloneApi::new();
|
||||||
|
api.post_json::<Value>("mount/mount", Some(json!(mount_request)))
|
||||||
let response = client
|
|
||||||
.post(format!("{RCLONE_API_BASE}/mount/mount"))
|
|
||||||
.header("Authorization", RCLONE_AUTH)
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.json(&mount_request)
|
|
||||||
.send()
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Failed to mount remote: {e}"))?;
|
.map(|_| true)
|
||||||
|
|
||||||
if response.status().is_success() {
|
|
||||||
Ok(true)
|
|
||||||
} else {
|
|
||||||
let error_text = response
|
|
||||||
.text()
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|_| "Unknown error".to_string());
|
|
||||||
Err(format!("Failed to mount remote: {error_text}"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -241,26 +173,10 @@ pub async fn rclone_unmount_remote(
|
|||||||
mount_point: String,
|
mount_point: String,
|
||||||
_state: State<'_, AppState>,
|
_state: State<'_, AppState>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
let client = Client::new();
|
let api = RcloneApi::new();
|
||||||
|
api.post_json::<Value>("mount/unmount", Some(json!({ "mountPoint": mount_point })))
|
||||||
let response = client
|
|
||||||
.post(format!("{RCLONE_API_BASE}/mount/unmount"))
|
|
||||||
.header("Authorization", RCLONE_AUTH)
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.json(&json!({ "mountPoint": mount_point }))
|
|
||||||
.send()
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Failed to unmount remote: {e}"))?;
|
.map(|_| true)
|
||||||
|
|
||||||
if response.status().is_success() {
|
|
||||||
Ok(true)
|
|
||||||
} else {
|
|
||||||
let error_text = response
|
|
||||||
.text()
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|_| "Unknown error".to_string());
|
|
||||||
Err(format!("Failed to unmount remote: {error_text}"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
|||||||
@@ -16,48 +16,31 @@ fn get_app_dir() -> Result<PathBuf, String> {
|
|||||||
Ok(app_dir)
|
Ok(app_dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_openlist_binary_path() -> Result<PathBuf, String> {
|
fn get_binary_path(binary: &str, service_name: &str) -> Result<PathBuf, String> {
|
||||||
let app_dir = get_app_dir()?;
|
let mut name = binary.to_string();
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
let binary_name = if cfg!(target_os = "windows") {
|
name.push_str(".exe");
|
||||||
"openlist.exe"
|
|
||||||
} else {
|
|
||||||
"openlist"
|
|
||||||
};
|
|
||||||
let binary_path = app_dir.join(binary_name);
|
|
||||||
|
|
||||||
if !binary_path.exists() {
|
|
||||||
return Err(format!(
|
|
||||||
"OpenList service binary not found at: {binary_path:?}"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(binary_path)
|
let path = get_app_dir()?.join(&name);
|
||||||
|
if !path.exists() {
|
||||||
|
return Err(format!(
|
||||||
|
"{service_name} service binary not found at: {path:?}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_openlist_binary_path() -> Result<PathBuf, String> {
|
||||||
|
get_binary_path("openlist", "OpenList")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_rclone_binary_path() -> Result<PathBuf, String> {
|
pub fn get_rclone_binary_path() -> Result<PathBuf, String> {
|
||||||
let app_dir = get_app_dir()?;
|
get_binary_path("rclone", "Rclone")
|
||||||
|
|
||||||
let binary_name = if cfg!(target_os = "windows") {
|
|
||||||
"rclone.exe"
|
|
||||||
} else {
|
|
||||||
"rclone"
|
|
||||||
};
|
|
||||||
let binary_path = app_dir.join(binary_name);
|
|
||||||
|
|
||||||
if !binary_path.exists() {
|
|
||||||
return Err(format!(
|
|
||||||
"Rclone service binary not found at: {binary_path:?}"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(binary_path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_app_config_dir() -> Result<PathBuf, String> {
|
pub fn get_app_config_dir() -> Result<PathBuf, String> {
|
||||||
let app_dir = get_app_dir()?;
|
get_app_dir()
|
||||||
fs::create_dir_all(&app_dir).map_err(|e| e.to_string())?;
|
|
||||||
Ok(app_dir)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn app_config_file_path() -> Result<PathBuf, String> {
|
pub fn app_config_file_path() -> Result<PathBuf, String> {
|
||||||
@@ -65,8 +48,7 @@ pub fn app_config_file_path() -> Result<PathBuf, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_app_logs_dir() -> Result<PathBuf, String> {
|
pub fn get_app_logs_dir() -> Result<PathBuf, String> {
|
||||||
let app_dir = get_app_dir()?;
|
let logs = get_app_dir()?.join("logs");
|
||||||
let logs_dir = app_dir.join("logs");
|
fs::create_dir_all(&logs).map_err(|e| e.to_string())?;
|
||||||
fs::create_dir_all(&logs_dir).map_err(|e| e.to_string())?;
|
Ok(logs)
|
||||||
Ok(logs_dir)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user