Replace Transmission with qBittorrent for torrent statistics
All checks were successful
Build and Release / build-and-release (push) Successful in 1m27s
All checks were successful
Build and Release / build-and-release (push) Successful in 1m27s
Update collector to use qBittorrent Web API instead of Transmission RPC. Query qBittorrent through VPN namespace using existing passwordless sudo permissions for ip netns exec commands. - Change service name from transmission-vpn to openvpn-vpn-download - Replace get_transmission_stats() with get_qbittorrent_stats() - Use curl through VPN namespace to access qBittorrent API at localhost:8080 - Parse qBittorrent JSON response for state, dlspeed, upspeed - Count active torrents (downloading, uploading, stalledDL, stalledUP) - Update version to v0.1.246
This commit is contained in:
parent
477724b4f4
commit
1cb6abf58a
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -279,7 +279,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
||||
|
||||
[[package]]
|
||||
name = "cm-dashboard"
|
||||
version = "0.1.244"
|
||||
version = "0.1.245"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -301,7 +301,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cm-dashboard-agent"
|
||||
version = "0.1.244"
|
||||
version = "0.1.245"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -325,7 +325,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cm-dashboard-shared"
|
||||
version = "0.1.244"
|
||||
version = "0.1.245"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cm-dashboard-agent"
|
||||
version = "0.1.245"
|
||||
version = "0.1.246"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@ -167,8 +167,8 @@ impl SystemdCollector {
|
||||
}
|
||||
}
|
||||
|
||||
if service_name == "transmission-vpn" && status_info.active_state == "active" {
|
||||
if let Some((active_count, download_mbps, upload_mbps)) = self.get_transmission_stats() {
|
||||
if service_name == "openvpn-vpn-download" && status_info.active_state == "active" {
|
||||
if let Some((active_count, download_mbps, upload_mbps)) = self.get_qbittorrent_stats() {
|
||||
let metrics = Vec::new();
|
||||
|
||||
sub_services.push(SubServiceData {
|
||||
@ -887,68 +887,55 @@ impl SystemdCollector {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get aggregate transmission torrent statistics
|
||||
/// Get aggregate qBittorrent torrent statistics
|
||||
/// Returns: (active_count, download_mbps, upload_mbps)
|
||||
fn get_transmission_stats(&self) -> Option<(u32, f32, f32)> {
|
||||
let rpc_url = "http://localhost:9091/transmission/rpc";
|
||||
|
||||
// Create HTTP client with timeout
|
||||
let client = reqwest::blocking::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(5))
|
||||
.build()
|
||||
fn get_qbittorrent_stats(&self) -> Option<(u32, f32, f32)> {
|
||||
// Query qBittorrent API through VPN namespace
|
||||
let output = Command::new("timeout")
|
||||
.args(&[
|
||||
"5",
|
||||
"sudo",
|
||||
"ip",
|
||||
"netns",
|
||||
"exec",
|
||||
"vpn",
|
||||
"curl",
|
||||
"-s",
|
||||
"--max-time",
|
||||
"4",
|
||||
"http://localhost:8080/api/v2/torrents/info"
|
||||
])
|
||||
.output()
|
||||
.ok()?;
|
||||
|
||||
// First request to get session ID (transmission requires this for CSRF protection)
|
||||
let session_id = match client.post(rpc_url).send() {
|
||||
Ok(resp) => {
|
||||
resp.headers()
|
||||
.get("X-Transmission-Session-Id")
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.map(|s| s.to_string())
|
||||
}
|
||||
Err(_) => return None,
|
||||
}?;
|
||||
if !output.status.success() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Request torrent list with session ID
|
||||
let request_body = serde_json::json!({
|
||||
"method": "torrent-get",
|
||||
"arguments": {
|
||||
"fields": ["status", "rateDownload", "rateUpload"]
|
||||
}
|
||||
});
|
||||
|
||||
let response = client
|
||||
.post(rpc_url)
|
||||
.header("X-Transmission-Session-Id", session_id)
|
||||
.json(&request_body)
|
||||
.send()
|
||||
.ok()?;
|
||||
|
||||
let json: serde_json::Value = response.json().ok()?;
|
||||
|
||||
// Parse torrent data and calculate aggregates
|
||||
let torrent_list = json["arguments"]["torrents"].as_array()?;
|
||||
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||
let torrents: Vec<serde_json::Value> = serde_json::from_str(&output_str).ok()?;
|
||||
|
||||
let mut active_count = 0u32;
|
||||
let mut total_download_bps = 0.0f64;
|
||||
let mut total_upload_bps = 0.0f64;
|
||||
|
||||
for torrent in torrent_list {
|
||||
let status_code = torrent["status"].as_i64().unwrap_or(0);
|
||||
let rate_download = torrent["rateDownload"].as_f64().unwrap_or(0.0);
|
||||
let rate_upload = torrent["rateUpload"].as_f64().unwrap_or(0.0);
|
||||
for torrent in torrents {
|
||||
let state = torrent["state"].as_str().unwrap_or("");
|
||||
let dlspeed = torrent["dlspeed"].as_f64().unwrap_or(0.0);
|
||||
let upspeed = torrent["upspeed"].as_f64().unwrap_or(0.0);
|
||||
|
||||
// Status codes: 0=stopped, 4=downloading, 6=seeding
|
||||
// Count as active if downloading or seeding
|
||||
if status_code == 4 || status_code == 6 {
|
||||
// States: downloading, uploading, stalledDL, stalledUP, queuedDL, queuedUP, pausedDL, pausedUP
|
||||
// Count as active if downloading or uploading (seeding)
|
||||
if state.contains("downloading") || state.contains("uploading") ||
|
||||
state == "stalledDL" || state == "stalledUP" {
|
||||
active_count += 1;
|
||||
}
|
||||
|
||||
total_download_bps += rate_download;
|
||||
total_upload_bps += rate_upload;
|
||||
total_download_bps += dlspeed;
|
||||
total_upload_bps += upspeed;
|
||||
}
|
||||
|
||||
// Convert bytes/s to MB/s
|
||||
// qBittorrent returns bytes/s, convert to MB/s
|
||||
let download_mbps = (total_download_bps / 1024.0 / 1024.0) as f32;
|
||||
let upload_mbps = (total_upload_bps / 1024.0 / 1024.0) as f32;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cm-dashboard"
|
||||
version = "0.1.245"
|
||||
version = "0.1.246"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cm-dashboard-shared"
|
||||
version = "0.1.245"
|
||||
version = "0.1.246"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user