socktop-webterm/docs/src/advanced/connector.md

437 lines
12 KiB
Markdown

# Socktop Connector Library
The `socktop_connector` library provides a high-level interface for connecting to socktop agents programmatically.
## Overview
The connector library allows you to:
- **Build custom monitoring tools** - Create your own dashboards and UIs
- **Integrate with existing systems** - Add socktop metrics to your applications
- **Automate monitoring** - Script-based system checks and alerts
- **WASM support** - Use in browser-based applications
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
socktop_connector = "1.50"
tokio = { version = "1", features = ["full"] }
```
## Quick Start
### Basic Connection
```rust
use socktop_connector::{connect_to_socktop_agent, AgentRequest, AgentResponse};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to agent
let mut connector = connect_to_socktop_agent("ws://localhost:3000/ws").await?;
// Request metrics
if let Ok(AgentResponse::Metrics(metrics)) = connector.request(AgentRequest::Metrics).await {
println!("Hostname: {}", metrics.hostname);
println!("CPU Usage: {:.1}%", metrics.cpu_total);
println!("Memory: {:.1} GB / {:.1} GB",
metrics.mem_used as f64 / 1_000_000_000.0,
metrics.mem_total as f64 / 1_000_000_000.0);
}
Ok(())
}
```
### With TLS
```rust
use socktop_connector::connect_to_socktop_agent_with_tls;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let connector = connect_to_socktop_agent_with_tls(
"wss://secure-host:3000/ws",
"/path/to/ca.pem",
false // Enable hostname verification
).await?;
// Use connector...
Ok(())
}
```
## Request Types
The connector supports several request types:
### Metrics Request
Get comprehensive system metrics:
```rust
use socktop_connector::{AgentRequest, AgentResponse};
match connector.request(AgentRequest::Metrics).await {
Ok(AgentResponse::Metrics(metrics)) => {
println!("CPU Total: {:.1}%", metrics.cpu_total);
// Per-core usage
for (i, usage) in metrics.cpu_per_core.iter().enumerate() {
println!("Core {}: {:.1}%", i, usage);
}
// CPU temperature
if let Some(temp) = metrics.cpu_temp_c {
println!("CPU Temperature: {:.1}°C", temp);
}
// Memory
println!("Memory Used: {} bytes", metrics.mem_used);
println!("Memory Total: {} bytes", metrics.mem_total);
// Swap
println!("Swap Used: {} bytes", metrics.swap_used);
println!("Swap Total: {} bytes", metrics.swap_total);
// Network interfaces
for net in &metrics.networks {
println!("Interface {}: ↓{}{}",
net.name, net.received, net.transmitted);
}
// GPU information
if let Some(gpus) = &metrics.gpus {
for gpu in gpus {
if let Some(name) = &gpu.name {
println!("GPU: {}", name);
println!(" Utilization: {:.1}%", gpu.utilization.unwrap_or(0.0));
if let Some(temp) = gpu.temp {
println!(" Temperature: {:.1}°C", temp);
}
}
}
}
}
Err(e) => eprintln!("Error: {}", e),
_ => unreachable!(),
}
```
### Process Request
Get process information:
```rust
match connector.request(AgentRequest::Processes).await {
Ok(AgentResponse::Processes(processes)) => {
println!("Total processes: {}", processes.process_count);
for proc in &processes.top_processes {
println!("PID {}: {} - CPU: {:.1}%, Mem: {} MB",
proc.pid,
proc.name,
proc.cpu_usage,
proc.mem_bytes / 1_000_000);
}
}
Err(e) => eprintln!("Error: {}", e),
_ => unreachable!(),
}
```
### Disk Request
Get disk information:
```rust
match connector.request(AgentRequest::Disks).await {
Ok(AgentResponse::Disks(disks)) => {
for disk in disks {
let used = disk.total - disk.available;
let used_gb = used as f64 / 1_000_000_000.0;
let total_gb = disk.total as f64 / 1_000_000_000.0;
let percent = (used as f64 / disk.total as f64) * 100.0;
println!("Disk {}: {:.1} GB / {:.1} GB ({:.1}%)",
disk.name, used_gb, total_gb, percent);
}
}
Err(e) => eprintln!("Error: {}", e),
_ => unreachable!(),
}
```
## Continuous Monitoring
Monitor metrics in a loop:
```rust
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut connector = connect_to_socktop_agent("ws://localhost:3000/ws").await?;
loop {
match connector.request(AgentRequest::Metrics).await {
Ok(AgentResponse::Metrics(metrics)) => {
println!("CPU: {:.1}%, Memory: {:.1}%",
metrics.cpu_total,
(metrics.mem_used as f64 / metrics.mem_total as f64) * 100.0
);
}
Err(e) => {
eprintln!("Connection error: {}", e);
break;
}
_ => unreachable!(),
}
sleep(Duration::from_secs(2)).await;
}
Ok(())
}
```
## Advanced Usage
### Custom Configuration
```rust
use socktop_connector::{ConnectorConfig, SocktopConnector};
let config = ConnectorConfig {
url: "ws://server:3000/ws".to_string(),
token: Some("secret-token".to_string()),
ca_cert_path: Some("/path/to/ca.pem".to_string()),
verify_tls: true,
};
let connector = SocktopConnector::connect_with_config(config).await?;
```
### Error Handling
```rust
use socktop_connector::{ConnectorError, Result};
async fn monitor() -> Result<()> {
let mut connector = connect_to_socktop_agent("ws://server:3000/ws").await?;
match connector.request(AgentRequest::Metrics).await {
Ok(response) => {
// Handle response
Ok(())
}
Err(ConnectorError::ConnectionClosed) => {
eprintln!("Connection closed, attempting reconnect...");
Err(ConnectorError::ConnectionClosed)
}
Err(e) => {
eprintln!("Error: {}", e);
Err(e)
}
}
}
```
## WASM Support
The connector supports WebAssembly for browser usage:
```toml
[dependencies]
socktop_connector = { version = "1.50", features = ["wasm"] }
```
```rust
use socktop_connector::connect_to_socktop_agent;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub async fn monitor_system(url: String) -> Result<JsValue, JsValue> {
let mut connector = connect_to_socktop_agent(&url)
.await
.map_err(|e| JsValue::from_str(&e.to_string()))?;
match connector.request(AgentRequest::Metrics).await {
Ok(AgentResponse::Metrics(metrics)) => {
Ok(JsValue::from_str(&format!("CPU: {:.1}%", metrics.cpu_total)))
}
Err(e) => Err(JsValue::from_str(&e.to_string())),
_ => Err(JsValue::from_str("Unexpected response")),
}
}
```
## Building Custom Applications
### Example: Simple Dashboard
```rust
use socktop_connector::*;
use tokio::time::{interval, Duration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let servers = vec![
("web", "ws://web.example.com:3000/ws"),
("db", "ws://db.example.com:3000/ws"),
("cache", "ws://cache.example.com:3000/ws"),
];
let mut connectors = Vec::new();
for (name, url) in servers {
match connect_to_socktop_agent(url).await {
Ok(conn) => connectors.push((name, conn)),
Err(e) => eprintln!("Failed to connect to {}: {}", name, e),
}
}
let mut tick = interval(Duration::from_secs(2));
loop {
tick.tick().await;
for (name, connector) in &mut connectors {
if let Ok(AgentResponse::Metrics(m)) = connector.request(AgentRequest::Metrics).await {
println!("[{}] CPU: {:.1}%, Mem: {:.1}%",
name,
m.cpu_total,
(m.mem_used as f64 / m.mem_total as f64) * 100.0
);
}
}
println!("---");
}
}
```
### Example: Alert System
```rust
use socktop_connector::*;
async fn check_alerts(mut connector: SocktopConnector) -> Result<(), Box<dyn std::error::Error>> {
match connector.request(AgentRequest::Metrics).await {
Ok(AgentResponse::Metrics(metrics)) => {
// CPU alert
if metrics.cpu_total > 90.0 {
eprintln!("ALERT: CPU usage at {:.1}%", metrics.cpu_total);
}
// Memory alert
let mem_percent = (metrics.mem_used as f64 / metrics.mem_total as f64) * 100.0;
if mem_percent > 90.0 {
eprintln!("ALERT: Memory usage at {:.1}%", mem_percent);
}
// Disk alert
if let Ok(AgentResponse::Disks(disks)) = connector.request(AgentRequest::Disks).await {
for disk in disks {
let used_percent = ((disk.total - disk.available) as f64 / disk.total as f64) * 100.0;
if used_percent > 90.0 {
eprintln!("ALERT: Disk {} at {:.1}%", disk.name, used_percent);
}
}
}
}
Err(e) => eprintln!("Error fetching metrics: {}", e),
_ => {}
}
Ok(())
}
```
## Data Types
Key types provided by the library:
- `Metrics` - System metrics (CPU, memory, network, GPU, etc.)
- `ProcessMetricsResponse` - Process information
- `DiskInfo` - Disk usage information
- `NetworkInfo` - Network interface statistics
- `GpuInfo` - GPU metrics
- `JournalEntry` - Systemd journal entries
- `AgentRequest` - Request types
- `AgentResponse` - Response types
See the [crate documentation](https://docs.rs/socktop_connector) for complete API reference.
## Performance Considerations
The connector is lightweight and efficient:
- **Protocol Buffers** - Efficient binary serialization
- **Gzip compression** - Reduced bandwidth usage
- **Async I/O** - Non-blocking operations
- **Connection reuse** - Single WebSocket for multiple requests
Typical resource usage:
- **Memory**: ~1-5 MB per connection
- **CPU**: < 0.1% during idle
- **Bandwidth**: ~1-5 KB per metrics request
## Troubleshooting
### Connection Errors
```rust
match connect_to_socktop_agent(url).await {
Err(ConnectorError::ConnectionFailed(e)) => {
eprintln!("Connection failed: {}", e);
// Retry logic here
}
Err(ConnectorError::InvalidUrl) => {
eprintln!("Invalid URL format");
}
Err(e) => eprintln!("Other error: {}", e),
Ok(conn) => { /* Success */ }
}
```
### TLS Errors
```rust
// Disable TLS verification for testing (not recommended)
use socktop_connector::{ConnectorConfig, SocktopConnector};
let config = ConnectorConfig {
url: "wss://server:3000/ws".to_string(),
verify_tls: false,
..Default::default()
};
```
## Examples Repository
More examples available in the socktop repository:
- `examples/simple_monitor.rs` - Basic monitoring
- `examples/multi_server.rs` - Monitor multiple servers
- `examples/alert_system.rs` - Threshold-based alerts
- `examples/wasm_demo/` - Browser-based monitoring
## API Reference
Full API documentation: [docs.rs/socktop_connector](https://docs.rs/socktop_connector)
## Next Steps
- [Agent Direct Integration](./agent-integration.md) - Embed agent in your app
- [General Usage](../usage/general.md) - Using the TUI client
- [Configuration](../usage/configuration.md) - Configuration options
<!-- TODO: Add more documentation -->
<!-- TODO: Add WebSocket reconnection examples -->
<!-- TODO: Add rate limiting guidance -->
<!-- TODO: Add batch request examples -->
<!-- TODO: Add Prometheus exporter example -->