Files
decypharr/pkg/rclone/stats.go
Mukhtar Akere 8696db42d2 - Add more rclone supports
- Add rclone log viewer
- Add more stats to Stats page
- Fix some minor bugs
2025-08-18 01:57:02 +01:00

185 lines
4.8 KiB
Go

package rclone
import (
"encoding/json"
"fmt"
)
type TransferringStat struct {
Bytes int64 `json:"bytes"`
ETA int64 `json:"eta"`
Name string `json:"name"`
Speed float64 `json:"speed"`
Size int64 `json:"size"`
Progress float64 `json:"progress"`
}
type VersionResponse struct {
Arch string `json:"arch"`
Version string `json:"version"`
OS string `json:"os"`
}
type CoreStatsResponse struct {
Bytes int64 `json:"bytes"`
Checks int `json:"checks"`
DeletedDirs int `json:"deletedDirs"`
Deletes int `json:"deletes"`
ElapsedTime float64 `json:"elapsedTime"`
Errors int `json:"errors"`
Eta int `json:"eta"`
Speed float64 `json:"speed"`
TotalBytes int64 `json:"totalBytes"`
TotalChecks int `json:"totalChecks"`
TotalTransfers int `json:"totalTransfers"`
TransferTime float64 `json:"transferTime"`
Transfers int `json:"transfers"`
Transferring []TransferringStat `json:"transferring,omitempty"`
}
type MemoryStats struct {
Sys int `json:"Sys"`
TotalAlloc int64 `json:"TotalAlloc"`
}
type BandwidthStats struct {
BytesPerSecond int64 `json:"bytesPerSecond"`
Rate string `json:"rate"`
}
// Stats represents rclone statistics
type Stats struct {
Enabled bool `json:"enabled"`
Ready bool `json:"server_ready"`
Core CoreStatsResponse `json:"core"`
Memory MemoryStats `json:"memory"`
Mount map[string]*MountInfo `json:"mount"`
Bandwidth BandwidthStats `json:"bandwidth"`
Version VersionResponse `json:"version"`
}
// GetStats retrieves statistics from the rclone RC server
func (m *Manager) GetStats() (*Stats, error) {
stats := &Stats{}
stats.Ready = m.IsReady()
stats.Enabled = true
coreStats, err := m.GetCoreStats()
if err == nil {
stats.Core = *coreStats
}
// Get memory usage
memStats, err := m.GetMemoryUsage()
if err == nil {
stats.Memory = *memStats
}
// Get bandwidth stats
bwStats, err := m.GetBandwidthStats()
if err == nil && bwStats != nil {
stats.Bandwidth = *bwStats
} else {
fmt.Println("Failed to get rclone stats", err)
}
// Get version info
versionResp, err := m.GetVersion()
if err == nil {
stats.Version = *versionResp
}
// Get mount info
stats.Mount = m.GetAllMounts()
return stats, nil
}
func (m *Manager) GetCoreStats() (*CoreStatsResponse, error) {
if !m.IsReady() {
return nil, fmt.Errorf("rclone RC server not ready")
}
req := RCRequest{
Command: "core/stats",
}
resp, err := m.makeRequest(req, false)
if err != nil {
return nil, fmt.Errorf("failed to get core stats: %w", err)
}
defer resp.Body.Close()
var coreStats CoreStatsResponse
if err := json.NewDecoder(resp.Body).Decode(&coreStats); err != nil {
return nil, fmt.Errorf("failed to decode core stats response: %w", err)
}
return &coreStats, nil
}
// GetMemoryUsage returns memory usage statistics
func (m *Manager) GetMemoryUsage() (*MemoryStats, error) {
if !m.IsReady() {
return nil, fmt.Errorf("rclone RC server not ready")
}
req := RCRequest{
Command: "core/memstats",
}
resp, err := m.makeRequest(req, false)
if err != nil {
return nil, fmt.Errorf("failed to get memory stats: %w", err)
}
defer resp.Body.Close()
var memStats MemoryStats
if err := json.NewDecoder(resp.Body).Decode(&memStats); err != nil {
return nil, fmt.Errorf("failed to decode memory stats response: %w", err)
}
return &memStats, nil
}
// GetBandwidthStats returns bandwidth usage for all transfers
func (m *Manager) GetBandwidthStats() (*BandwidthStats, error) {
if !m.IsReady() {
return nil, fmt.Errorf("rclone RC server not ready")
}
req := RCRequest{
Command: "core/bwlimit",
}
resp, err := m.makeRequest(req, false)
if err != nil {
// Bandwidth stats might not be available, return empty
return nil, nil
}
defer resp.Body.Close()
var bwStats BandwidthStats
if err := json.NewDecoder(resp.Body).Decode(&bwStats); err != nil {
return nil, fmt.Errorf("failed to decode bandwidth stats response: %w", err)
}
return &bwStats, nil
}
// GetVersion returns rclone version information
func (m *Manager) GetVersion() (*VersionResponse, error) {
if !m.IsReady() {
return nil, fmt.Errorf("rclone RC server not ready")
}
req := RCRequest{
Command: "core/version",
}
resp, err := m.makeRequest(req, false)
if err != nil {
return nil, fmt.Errorf("failed to get version: %w", err)
}
defer resp.Body.Close()
var versionResp VersionResponse
if err := json.NewDecoder(resp.Body).Decode(&versionResp); err != nil {
return nil, fmt.Errorf("failed to decode version response: %w", err)
}
return &versionResp, nil
}