Add AI generated zliij plugin scafold
This commit is contained in:
parent
5e5fde190a
commit
e679896ca0
18
zellij_socktop_plugin/Cargo.toml
Normal file
18
zellij_socktop_plugin/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "zellij_socktop_plugin"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
zellij-tile = "0.40.0"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
socktop_connector = { version = "0.1.5", default-features = false, features = ["wasm"] }
|
||||||
|
|
||||||
|
[dependencies.chrono]
|
||||||
|
version = "0.4"
|
||||||
|
default-features = false
|
||||||
|
features = ["clock", "std", "wasmbind"]
|
||||||
101
zellij_socktop_plugin/README.md
Normal file
101
zellij_socktop_plugin/README.md
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# Zellij Socktop Plugin
|
||||||
|
|
||||||
|
A Zellij plugin that displays real-time system metrics from a socktop agent.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
1. **Build the plugin:**
|
||||||
|
```bash
|
||||||
|
cargo build --target wasm32-wasi --release
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Install in Zellij:**
|
||||||
|
```bash
|
||||||
|
# Copy the WASM file to Zellij plugins directory
|
||||||
|
mkdir -p ~/.config/zellij/plugins
|
||||||
|
cp target/wasm32-wasi/release/zellij_socktop_plugin.wasm ~/.config/zellij/plugins/socktop.wasm
|
||||||
|
cp plugin.yaml ~/.config/zellij/plugins/
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Use in Zellij layout:**
|
||||||
|
```yaml
|
||||||
|
# ~/.config/zellij/layouts/socktop.yaml
|
||||||
|
template:
|
||||||
|
direction: Horizontal
|
||||||
|
parts:
|
||||||
|
- direction: Vertical
|
||||||
|
borderless: true
|
||||||
|
split_size:
|
||||||
|
Fixed: 1
|
||||||
|
run:
|
||||||
|
plugin:
|
||||||
|
location: "file:~/.config/zellij/plugins/socktop.wasm"
|
||||||
|
configuration:
|
||||||
|
server_url: "ws://localhost:3000/ws"
|
||||||
|
- direction: Vertical
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Launch Zellij with the layout:**
|
||||||
|
```bash
|
||||||
|
zellij --layout socktop
|
||||||
|
```
|
||||||
|
|
||||||
|
## Plugin Features
|
||||||
|
|
||||||
|
- **Real-time Metrics**: Displays CPU and memory usage
|
||||||
|
- **Auto-refresh**: Updates every 2 seconds
|
||||||
|
- **Reconnection**: Press 'r' to reconnect to socktop agent
|
||||||
|
- **Configurable**: Set custom server URL in plugin config
|
||||||
|
- **Error Handling**: Shows connection status and errors
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
- `server_url`: WebSocket URL for socktop agent (default: `ws://localhost:3000/ws`)
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
- **`r`** - Reconnect to socktop agent
|
||||||
|
- Plugin updates automatically every 2 seconds
|
||||||
|
|
||||||
|
## Development Notes
|
||||||
|
|
||||||
|
This is a scaffold implementation. To make it fully functional:
|
||||||
|
|
||||||
|
1. **Async Operations**: Zellij plugins have limitations with async operations. You may need to:
|
||||||
|
- Use a different async runtime or approach
|
||||||
|
- Handle WebSocket connections in a background thread
|
||||||
|
- Use message passing between threads
|
||||||
|
|
||||||
|
2. **Error Handling**: Add more robust error handling for:
|
||||||
|
- Network connectivity issues
|
||||||
|
- Invalid server URLs
|
||||||
|
- Agent unavailability
|
||||||
|
|
||||||
|
3. **UI Improvements**:
|
||||||
|
- Add more detailed metrics display
|
||||||
|
- Implement scrolling for large datasets
|
||||||
|
- Add color coding for status indicators
|
||||||
|
|
||||||
|
4. **Performance**:
|
||||||
|
- Implement caching to reduce agent requests
|
||||||
|
- Add configurable update intervals
|
||||||
|
- Optimize WASM binary size
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- `zellij-tile`: Zellij plugin framework
|
||||||
|
- `socktop_connector`: WebSocket connector with WASM support
|
||||||
|
- `serde`: JSON serialization
|
||||||
|
- `chrono`: Time handling (WASM-compatible)
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Add WASM target
|
||||||
|
rustup target add wasm32-wasi
|
||||||
|
|
||||||
|
# Build for WASM
|
||||||
|
cargo build --target wasm32-wasi --release
|
||||||
|
|
||||||
|
# The plugin will be at: target/wasm32-wasi/release/zellij_socktop_plugin.wasm
|
||||||
|
```
|
||||||
11
zellij_socktop_plugin/plugin.yaml
Normal file
11
zellij_socktop_plugin/plugin.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
name: "socktop"
|
||||||
|
version: "0.1.0"
|
||||||
|
authors: ["Your Name <your@email.com>"]
|
||||||
|
plugin: true
|
||||||
|
permissions:
|
||||||
|
- ReadApplicationState
|
||||||
|
configuration:
|
||||||
|
server_url:
|
||||||
|
type: "string"
|
||||||
|
default: "ws://localhost:3000/ws"
|
||||||
|
description: "WebSocket URL for socktop agent"
|
||||||
186
zellij_socktop_plugin/src/lib.rs
Normal file
186
zellij_socktop_plugin/src/lib.rs
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
use zellij_tile::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use socktop_connector::{ConnectorConfig, AgentRequest, SocktopConnector, AgentResponse};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct State {
|
||||||
|
connector: Option<SocktopConnector>,
|
||||||
|
metrics_data: Option<String>,
|
||||||
|
connection_status: String,
|
||||||
|
error_message: Option<String>,
|
||||||
|
update_counter: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut STATE: State = State {
|
||||||
|
connector: None,
|
||||||
|
metrics_data: None,
|
||||||
|
connection_status: String::new(),
|
||||||
|
error_message: None,
|
||||||
|
update_counter: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
register_plugin!(State);
|
||||||
|
|
||||||
|
impl ZellijPlugin for State {
|
||||||
|
fn load(&mut self, configuration: BTreeMap<String, String>) {
|
||||||
|
// Get server URL from plugin config or use default
|
||||||
|
let server_url = configuration
|
||||||
|
.get("server_url")
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| "ws://localhost:3000/ws".to_string());
|
||||||
|
|
||||||
|
// Initialize connector configuration
|
||||||
|
let config = ConnectorConfig::new(&server_url);
|
||||||
|
let connector = SocktopConnector::new(config);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
STATE.connector = Some(connector);
|
||||||
|
STATE.connection_status = "Connecting...".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up periodic updates
|
||||||
|
set_timeout(1.0); // Update every second
|
||||||
|
|
||||||
|
// Start initial connection
|
||||||
|
self.connect_to_socktop();
|
||||||
|
|
||||||
|
request_permission(&[
|
||||||
|
PermissionType::ReadApplicationState,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, event: Event) -> bool {
|
||||||
|
match event {
|
||||||
|
Event::Timer(_) => {
|
||||||
|
unsafe {
|
||||||
|
STATE.update_counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request metrics every update cycle
|
||||||
|
self.fetch_metrics();
|
||||||
|
|
||||||
|
// Set next timer
|
||||||
|
set_timeout(2.0); // Update every 2 seconds
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Event::Key(key) => {
|
||||||
|
match key {
|
||||||
|
Key::Char('r') => {
|
||||||
|
// Reconnect on 'r' key press
|
||||||
|
self.connect_to_socktop();
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, rows: usize, cols: usize) {
|
||||||
|
unsafe {
|
||||||
|
let mut output = Vec::new();
|
||||||
|
|
||||||
|
// Header
|
||||||
|
output.push("╭─ Socktop Metrics Plugin ─╮".to_string());
|
||||||
|
output.push(format!("│ Status: {:<18} │", STATE.connection_status));
|
||||||
|
output.push("├──────────────────────────╯".to_string());
|
||||||
|
|
||||||
|
// Metrics display
|
||||||
|
if let Some(ref metrics) = STATE.metrics_data {
|
||||||
|
output.push("│ System Metrics:".to_string());
|
||||||
|
output.push(format!("│ {}", metrics));
|
||||||
|
} else if let Some(ref error) = STATE.error_message {
|
||||||
|
output.push("│ Error:".to_string());
|
||||||
|
output.push(format!("│ {}", error));
|
||||||
|
} else {
|
||||||
|
output.push("│ Waiting for data...".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
output.push("│".to_string());
|
||||||
|
output.push(format!("│ Updates: {} │ Press 'r' to reconnect", STATE.update_counter));
|
||||||
|
output.push("╰──────────────────────────╯".to_string());
|
||||||
|
|
||||||
|
// Print lines within terminal bounds
|
||||||
|
for (i, line) in output.iter().enumerate() {
|
||||||
|
if i < rows {
|
||||||
|
println!("{}", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn connect_to_socktop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if let Some(ref mut connector) = STATE.connector {
|
||||||
|
STATE.connection_status = "Connecting...".to_string();
|
||||||
|
STATE.error_message = None;
|
||||||
|
|
||||||
|
// In a real implementation, you'd use async/await here
|
||||||
|
// For this scaffold, we'll simulate the connection
|
||||||
|
// Note: Zellij plugins have limitations with async operations
|
||||||
|
STATE.connection_status = "Connected".to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_metrics(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if let Some(ref mut connector) = STATE.connector {
|
||||||
|
// In a real implementation, you would:
|
||||||
|
// 1. Make an async call to connector.request(AgentRequest::Metrics)
|
||||||
|
// 2. Handle the response and update STATE.metrics_data
|
||||||
|
// 3. Handle errors and update STATE.error_message
|
||||||
|
|
||||||
|
// For this scaffold, we'll simulate a response
|
||||||
|
match STATE.update_counter % 4 {
|
||||||
|
0 => {
|
||||||
|
STATE.metrics_data = Some("CPU: 45.2%, Memory: 67.8%".to_string());
|
||||||
|
STATE.connection_status = "Active".to_string();
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
STATE.metrics_data = Some("CPU: 32.1%, Memory: 71.3%".to_string());
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
STATE.metrics_data = Some("CPU: 58.7%, Memory: 69.1%".to_string());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
STATE.metrics_data = Some("CPU: 41.9%, Memory: 72.4%".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
STATE.error_message = Some("No connector available".to_string());
|
||||||
|
STATE.connection_status = "Disconnected".to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Async helper for real WebSocket operations (commented out for scaffold)
|
||||||
|
/*
|
||||||
|
async fn connect_and_fetch(connector: &mut SocktopConnector) -> Result<String, String> {
|
||||||
|
// Connect to socktop agent
|
||||||
|
connector.connect().await
|
||||||
|
.map_err(|e| format!("Connection failed: {}", e))?;
|
||||||
|
|
||||||
|
// Request metrics
|
||||||
|
let response = connector.request(AgentRequest::Metrics).await
|
||||||
|
.map_err(|e| format!("Metrics request failed: {}", e))?;
|
||||||
|
|
||||||
|
// Format response
|
||||||
|
match response {
|
||||||
|
AgentResponse::Metrics(metrics) => {
|
||||||
|
Ok(format!("CPU: {:.1}%, Mem: {:.1}%, Host: {}",
|
||||||
|
metrics.cpu_total,
|
||||||
|
(metrics.mem_used as f64 / metrics.mem_total as f64) * 100.0,
|
||||||
|
metrics.hostname
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => Err("Unexpected response type".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
Loading…
Reference in New Issue
Block a user