Skip to main content
Glama
by 8b-is
rust_shell.rs18.8 kB
// Rust Shell - "The ultimate collaborative interface!" 🚀 // Cast to any screen, control any display, seamless voice transitions // "Why have one interface when you can have them ALL?" - Hue use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::{Mutex, RwLock}; // Display targets #[derive(Debug, Clone, Serialize, Deserialize)] pub enum DisplayTarget { AppleTV { name: String, address: String, }, Chromecast { name: String, uuid: String, }, Miracast { name: String, address: String, }, ESP32Display { name: String, address: String, width: u16, height: u16, }, WebDashboard { port: u16, }, Terminal, // Local terminal Voice, // Voice-only mode } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct OutputMode { pub verbosity: VerbosityLevel, pub format: OutputFormat, pub theme: String, pub screen_config: ScreenConfig, } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum VerbosityLevel { Verbose, // Full output for screens Normal, // Standard output Concise, // Reduced for small screens Minimal, // Voice mode - just essentials Silent, // Actions only, no output } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum OutputFormat { Text, HTML, Markdown, JSON, Graphics, // For capable displays Voice, // TTS-optimized } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ScreenConfig { pub width: u16, pub height: u16, pub color_depth: u8, pub refresh_rate: u8, pub capabilities: Vec<String>, // ["color", "touch", "audio"] } // The main shell structure pub struct RustShell { displays: Arc<RwLock<HashMap<String, DisplayTarget>>>, active_display: Arc<RwLock<Option<String>>>, pub output_mode: Arc<RwLock<OutputMode>>, mcp_interface: Arc<MCPInterface>, cast_manager: Arc<CastManager>, voice_detector: Arc<VoiceDetector>, command_history: Arc<Mutex<Vec<String>>>, context_state: Arc<RwLock<ContextState>>, } // MCP/Binary API Interface struct MCPInterface { socket: Arc<Mutex<Option<tokio::net::TcpStream>>>, binary_api: BinaryAPI, } type EndpointHandler = Box<dyn Fn(&[u8]) -> Vec<u8> + Send + Sync>; struct BinaryAPI { endpoints: HashMap<String, EndpointHandler>, } // Casting manager for different protocols struct CastManager { airplay: Option<AirPlayCaster>, chromecast: Option<ChromecastCaster>, miracast: Option<MiracastCaster>, esp32: Option<ESP32Caster>, web_server: Option<WebDashboardServer>, } // Voice detection and mode switching struct VoiceDetector { audio_active: Arc<RwLock<bool>>, last_voice_time: Arc<RwLock<std::time::Instant>>, } // Context awareness #[derive(Debug, Clone, Serialize, Deserialize)] struct ContextState { user_location: UserLocation, active_project: Option<String>, conversation_mode: ConversationMode, screen_arrangement: Vec<(String, DisplayTarget)>, } #[derive(Debug, Clone, Serialize, Deserialize)] enum UserLocation { AtDesk, Mobile, Remote, Voice, } #[derive(Debug, Clone, Serialize, Deserialize)] enum ConversationMode { Interactive, // Full interaction Monitoring, // Just watching Voice, // Voice commands Automated, // Running scripts } impl RustShell { pub async fn new() -> Result<Self> { Ok(Self { displays: Arc::new(RwLock::new(HashMap::new())), active_display: Arc::new(RwLock::new(None)), output_mode: Arc::new(RwLock::new(OutputMode::default())), mcp_interface: Arc::new(MCPInterface::new().await?), cast_manager: Arc::new(CastManager::new().await?), voice_detector: Arc::new(VoiceDetector::new()), command_history: Arc::new(Mutex::new(Vec::new())), context_state: Arc::new(RwLock::new(ContextState::default())), }) } /// Discover available displays pub async fn discover_displays(&self) -> Result<Vec<DisplayTarget>> { let mut discovered = Vec::new(); // Discover Apple TVs via Bonjour/mDNS if let Some(airplay) = &self.cast_manager.airplay { discovered.extend(airplay.discover().await?); } // Discover Chromecasts if let Some(chromecast) = &self.cast_manager.chromecast { discovered.extend(chromecast.discover().await?); } // Discover ESP32 displays on network if let Some(esp32) = &self.cast_manager.esp32 { discovered.extend(esp32.discover().await?); } // Always have terminal and voice discovered.push(DisplayTarget::Terminal); discovered.push(DisplayTarget::Voice); Ok(discovered) } /// Cast to a specific display pub async fn cast_to(&self, target: &DisplayTarget, content: &str) -> Result<()> { // Adapt output based on target let adapted_content = self.adapt_content_for_display(content, target).await?; match target { DisplayTarget::AppleTV { address, .. } => { self.cast_manager .airplay .as_ref() .context("AirPlay not available")? .cast(address, &adapted_content) .await? } DisplayTarget::Chromecast { uuid, .. } => { self.cast_manager .chromecast .as_ref() .context("Chromecast not available")? .cast(uuid, &adapted_content) .await? } DisplayTarget::ESP32Display { address, width, height, .. } => { // Format for small display let formatted = self.format_for_small_display(&adapted_content, *width, *height); self.cast_manager .esp32 .as_ref() .context("ESP32 caster not available")? .send(address, &formatted) .await? } DisplayTarget::WebDashboard { port: _ } => { // Update web dashboard self.cast_manager .web_server .as_ref() .context("Web server not running")? .update_dashboard(&adapted_content) .await? } DisplayTarget::Terminal => { println!("{}", adapted_content); } DisplayTarget::Voice => { // Convert to speech-friendly format let voice_text = self.make_voice_friendly(&adapted_content); self.speak(&voice_text).await?; } _ => {} } Ok(()) } /// Adapt content based on display capabilities async fn adapt_content_for_display( &self, content: &str, target: &DisplayTarget, ) -> Result<String> { let _mode = self.output_mode.read().await; match target { DisplayTarget::Voice => { // Ultra-concise for voice Ok(self.make_voice_friendly(content)) } DisplayTarget::ESP32Display { width, height, .. } => { // Format for tiny screen Ok(self.format_for_small_display(content, *width, *height)) } DisplayTarget::AppleTV { .. } | DisplayTarget::Chromecast { .. } => { // Rich HTML for TV displays Ok(self.format_as_rich_html(content)) } _ => Ok(content.to_string()), } } /// Detect voice mode and adjust verbosity pub async fn detect_voice_transition(&self) -> Result<()> { let detector = &self.voice_detector; // Check if audio input is active let audio_active = detector.is_audio_active().await?; if audio_active { // Switch to minimal verbosity let mut mode = self.output_mode.write().await; mode.verbosity = VerbosityLevel::Minimal; mode.format = OutputFormat::Voice; // Update active display let mut active = self.active_display.write().await; *active = Some("voice".to_string()); println!("🎤 Voice mode activated - switching to concise output"); } Ok(()) } /// Execute command through MCP/Binary API pub async fn execute(&self, command: &str) -> Result<String> { // Parse command let parts: Vec<&str> = command.split_whitespace().collect(); if parts.is_empty() { return Ok(String::new()); } match parts[0] { "cast" => { // cast <target> <content> if parts.len() >= 2 { let target_name = parts[1]; let content = parts[2..].join(" "); self.cast_by_name(target_name, &content).await } else { Ok("Usage: cast <target> <content>".to_string()) } } "discover" => { // Discover available displays let displays = self.discover_displays().await?; Ok(format!( "Found {} displays:\n{:#?}", displays.len(), displays )) } "mode" => { // Switch output mode if parts.len() >= 2 { self.set_mode(parts[1]).await } else { Ok(format!( "Current mode: {:?}", self.output_mode.read().await.verbosity )) } } "dashboard" => { // Start web dashboard self.start_dashboard(8888).await?; Ok("Dashboard started on http://localhost:8888".to_string()) } _ => { // Forward to MCP self.mcp_interface.execute(command).await } } } /// Cast to display by name async fn cast_by_name(&self, name: &str, content: &str) -> Result<String> { let displays = self.displays.read().await; if let Some(target) = displays.get(name) { self.cast_to(target, content).await?; Ok(format!("Cast to {} complete", name)) } else { Ok(format!("Display '{}' not found", name)) } } /// Set output mode async fn set_mode(&self, mode_str: &str) -> Result<String> { let mut mode = self.output_mode.write().await; match mode_str { "verbose" => mode.verbosity = VerbosityLevel::Verbose, "normal" => mode.verbosity = VerbosityLevel::Normal, "concise" => mode.verbosity = VerbosityLevel::Concise, "minimal" => mode.verbosity = VerbosityLevel::Minimal, "voice" => { mode.verbosity = VerbosityLevel::Minimal; mode.format = OutputFormat::Voice; } _ => return Ok(format!("Unknown mode: {}", mode_str)), } Ok(format!("Mode set to: {}", mode_str)) } /// Start web dashboard async fn start_dashboard(&self, port: u16) -> Result<()> { // This would start a web server for the dashboard println!("Starting dashboard on port {}...", port); // Implementation would go here Ok(()) } /// Format content for small displays fn format_for_small_display(&self, content: &str, width: u16, height: u16) -> String { // Truncate and format for tiny screens let chars_per_line = (width / 8) as usize; // Assuming 8px char width let max_lines = (height / 16) as usize; // Assuming 16px line height content .lines() .take(max_lines) .map(|line| { if line.len() > chars_per_line { format!("{}...", &line[..chars_per_line.saturating_sub(3)]) } else { line.to_string() } }) .collect::<Vec<_>>() .join("\n") } /// Convert to voice-friendly format fn make_voice_friendly(&self, content: &str) -> String { // Remove special characters, simplify content .replace("```", "code block") .replace("##", "section") .replace("*", "") .replace("_", "") .lines() .filter(|line| !line.trim().is_empty()) .take(5) // Just key points .collect::<Vec<_>>() .join(". ") } /// Format as rich HTML for TV displays fn format_as_rich_html(&self, content: &str) -> String { format!( r#" <!DOCTYPE html> <html> <head> <style> body {{ font-family: 'SF Pro Display', -apple-system, sans-serif; background: linear-gradient(135deg, #1e3c72, #2a5298); color: white; padding: 50px; font-size: 24px; line-height: 1.6; }} pre {{ background: rgba(0,0,0,0.3); padding: 20px; border-radius: 10px; overflow-x: auto; }} h1 {{ font-size: 48px; margin-bottom: 30px; }} .terminal {{ font-family: 'SF Mono', monospace; background: black; color: #00ff00; padding: 30px; border-radius: 15px; box-shadow: 0 10px 40px rgba(0,0,0,0.5); }} </style> </head> <body> <div class="terminal"> <pre>{}</pre> </div> </body> </html> "#, html_escape::encode_text(content) ) } /// Speak text (would interface with TTS) async fn speak(&self, text: &str) -> Result<()> { println!("🔊 Speaking: {}", text); // TTS implementation would go here Ok(()) } } // Placeholder implementations for casters struct AirPlayCaster; struct ChromecastCaster; struct MiracastCaster; struct ESP32Caster; struct WebDashboardServer; impl AirPlayCaster { async fn discover(&self) -> Result<Vec<DisplayTarget>> { // Would use Bonjour/mDNS to discover Ok(vec![]) } async fn cast(&self, _address: &str, _content: &str) -> Result<()> { // Would implement AirPlay protocol Ok(()) } } impl ChromecastCaster { async fn discover(&self) -> Result<Vec<DisplayTarget>> { // Would use mDNS to discover Chromecasts Ok(vec![]) } async fn cast(&self, _uuid: &str, _content: &str) -> Result<()> { // Would implement Chromecast protocol Ok(()) } } impl MiracastCaster { async fn discover(&self) -> Result<Vec<DisplayTarget>> { Ok(vec![]) } } impl ESP32Caster { async fn discover(&self) -> Result<Vec<DisplayTarget>> { // Would scan for ESP32 devices Ok(vec![]) } async fn send(&self, _address: &str, _content: &str) -> Result<()> { // Would send via WiFi/BLE to ESP32 Ok(()) } } impl WebDashboardServer { async fn update_dashboard(&self, _content: &str) -> Result<()> { // Would update WebSocket clients Ok(()) } } impl CastManager { async fn new() -> Result<Self> { Ok(Self { airplay: Some(AirPlayCaster), chromecast: Some(ChromecastCaster), miracast: Some(MiracastCaster), esp32: Some(ESP32Caster), web_server: Some(WebDashboardServer), }) } } impl MCPInterface { async fn new() -> Result<Self> { Ok(Self { socket: Arc::new(Mutex::new(None)), binary_api: BinaryAPI { endpoints: HashMap::new(), }, }) } async fn execute(&self, command: &str) -> Result<String> { // Would forward to MCP server Ok(format!("MCP: {}", command)) } } impl VoiceDetector { fn new() -> Self { Self { audio_active: Arc::new(RwLock::new(false)), last_voice_time: Arc::new(RwLock::new(std::time::Instant::now())), } } async fn is_audio_active(&self) -> Result<bool> { Ok(*self.audio_active.read().await) } } impl Default for OutputMode { fn default() -> Self { Self { verbosity: VerbosityLevel::Normal, format: OutputFormat::Text, theme: "default".to_string(), screen_config: ScreenConfig { width: 1920, height: 1080, color_depth: 24, refresh_rate: 60, capabilities: vec!["color".to_string()], }, } } } impl Default for ContextState { fn default() -> Self { Self { user_location: UserLocation::AtDesk, active_project: None, conversation_mode: ConversationMode::Interactive, screen_arrangement: Vec::new(), } } } /// The main shell entry point pub async fn start_rust_shell() -> Result<()> { println!("🚀 Rust Shell - Ultimate Collaborative Interface\n"); println!("Cast to any screen, seamless voice transitions!\n"); let shell = RustShell::new().await?; // Discover displays println!("🔍 Discovering displays..."); let displays = shell.discover_displays().await?; println!("Found {} displays", displays.len()); // Main loop loop { // Check for voice transition shell.detect_voice_transition().await?; // Read command use std::io::{self, Write}; print!("rust-shell> "); io::stdout().flush()?; let mut input = String::new(); io::stdin().read_line(&mut input)?; let input = input.trim(); if input == "exit" { break; } // Execute command match shell.execute(input).await { Ok(output) => println!("{}", output), Err(e) => eprintln!("Error: {}", e), } } Ok(()) } // Extension for HTML escaping mod html_escape { pub fn encode_text(text: &str) -> String { text.replace('&', "&amp;") .replace('<', "&lt;") .replace('>', "&gt;") .replace('"', "&quot;") .replace('\'', "&#39;") } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8b-is/smart-tree'

If you have feedback or need assistance with the MCP directory API, please join our Discord server