Fix build and runtime issues
This commit includes: - Fixed XDG path handling to use place_runtime_file instead of get_runtime_path - Updated JSON deserialization for Tokio async compatibility in both client and daemon - Added missing dirs-next dependency for home directory access - Fixed return values in several functions - Created display module for client UI formatting - Fixed command-line argument conflicts in daemonmain
parent
f286cc3271
commit
bf4f757ef2
|
|
@ -15,4 +15,4 @@ tracing = { workspace = true }
|
|||
tracing-subscriber = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
xdg = { workspace = true }
|
||||
rustyline = "12.0"
|
||||
rustyline = "11.0"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
//! Display utilities for the Cypraea client.
|
||||
//!
|
||||
//! This module contains functions for formatting and displaying information
|
||||
//! from the Cypraea daemon.
|
||||
|
||||
use std::io::{self, Write};
|
||||
use cypraea_common::protocol::SessionInfo;
|
||||
|
||||
/// Format a session list for display.
|
||||
pub fn format_session_list(sessions: &[SessionInfo]) -> String {
|
||||
if sessions.is_empty() {
|
||||
return "No active sessions.\n".to_string();
|
||||
}
|
||||
|
||||
let mut result = String::new();
|
||||
result.push_str("Available sessions:\n");
|
||||
result.push_str("------------------\n");
|
||||
|
||||
for session in sessions {
|
||||
result.push_str(&format!(
|
||||
"- {} (created: {}, last used: {}, cmds: {}, {})\n",
|
||||
session.id,
|
||||
session.created_at.format("%Y-%m-%d %H:%M:%S"),
|
||||
session.last_used.format("%Y-%m-%d %H:%M:%S"),
|
||||
session.command_count,
|
||||
if session.active { "active" } else { "idle" }
|
||||
));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Format session information for display.
|
||||
pub fn format_session_info(session: &SessionInfo) -> String {
|
||||
let mut result = String::new();
|
||||
result.push_str(&format!("Session: {}\n", session.id));
|
||||
result.push_str(&format!("Working directory: {}\n", session.cwd));
|
||||
result.push_str(&format!("Created: {}\n", session.created_at.format("%Y-%m-%d %H:%M:%S")));
|
||||
result.push_str(&format!("Last used: {}\n", session.last_used.format("%Y-%m-%d %H:%M:%S")));
|
||||
result.push_str(&format!("Commands executed: {}\n", session.command_count));
|
||||
result.push_str(&format!("Status: {}\n", if session.active { "active" } else { "idle" }));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Print a message to stdout.
|
||||
pub fn print_message(msg: &str) -> io::Result<()> {
|
||||
print!("{}", msg);
|
||||
io::stdout().flush()
|
||||
}
|
||||
|
||||
/// Print a message to stderr.
|
||||
pub fn print_error(msg: &str) -> io::Result<()> {
|
||||
eprint!("{}", msg);
|
||||
io::stderr().flush()
|
||||
}
|
||||
|
|
@ -79,18 +79,30 @@ async fn main() -> Result<()> {
|
|||
|
||||
// Spawn a task to read messages from the daemon
|
||||
let read_task = tokio::spawn(async move {
|
||||
let mut stream = Deserializer::from_reader(reader).into_iter::<DaemonMessage>();
|
||||
|
||||
while let Some(msg_result) = stream.next() {
|
||||
match msg_result {
|
||||
Ok(msg) => {
|
||||
debug!("Received message: {:?}", msg);
|
||||
if tx.send(msg).await.is_err() {
|
||||
break;
|
||||
let mut buffer = String::new();
|
||||
|
||||
loop {
|
||||
// Read a line from the stream
|
||||
buffer.clear();
|
||||
match reader.read_line(&mut buffer).await {
|
||||
Ok(0) => break, // End of stream
|
||||
Ok(_) => {
|
||||
// Parse the message
|
||||
match serde_json::from_str::<DaemonMessage>(&buffer) {
|
||||
Ok(msg) => {
|
||||
debug!("Received message: {:?}", msg);
|
||||
if tx.send(msg).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Error parsing message: {}", e);
|
||||
// Continue trying to parse other messages
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Error parsing message: {}", e);
|
||||
error!("Error reading from daemon: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use xdg::BaseDirectories;
|
|||
pub fn socket_path() -> Result<PathBuf> {
|
||||
// Use XDG_RUNTIME_DIR if available, or fall back to a temporary directory
|
||||
let xdg = BaseDirectories::new().context("Failed to initialize XDG base directories")?;
|
||||
Ok(xdg.get_runtime_path().join("cypraea.sock"))
|
||||
Ok(xdg.place_runtime_file("cypraea.sock")?)
|
||||
}
|
||||
|
||||
/// Get the path to the Cypraea database directory.
|
||||
|
|
|
|||
|
|
@ -17,3 +17,4 @@ tracing = { workspace = true }
|
|||
tracing-subscriber = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
xdg = { workspace = true }
|
||||
dirs-next = "2.0"
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ impl Database {
|
|||
)
|
||||
.context("Failed to create commands table")?;
|
||||
|
||||
Ok()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Log a command execution.
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ struct Args {
|
|||
database: Option<String>,
|
||||
|
||||
/// Enable debug logging
|
||||
#[clap(short, long)]
|
||||
#[clap(short = 'v', long)]
|
||||
debug: bool,
|
||||
}
|
||||
|
||||
|
|
@ -70,5 +70,5 @@ async fn main() -> Result<()> {
|
|||
.context("Socket server error")?;
|
||||
|
||||
info!("Daemon shutting down");
|
||||
Ok()
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ pub struct Session {
|
|||
impl Session {
|
||||
/// Create a new session.
|
||||
pub fn new(id: String) -> Self {
|
||||
let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||
let home = dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||
let now = Utc::now();
|
||||
|
||||
Self {
|
||||
|
|
|
|||
|
|
@ -84,18 +84,38 @@ async fn handle_client(stream: UnixStream, session_manager: SessionManager) -> R
|
|||
});
|
||||
|
||||
// Process incoming messages
|
||||
let mut stream = Deserializer::from_reader(reader).into_iter::<ClientMessage>();
|
||||
|
||||
while let Some(msg_result) = stream.next() {
|
||||
let msg = msg_result.context("Failed to parse client message")?;
|
||||
debug!("Received message: {:?}", msg);
|
||||
|
||||
if let Err(e) = process_message(msg, &session_manager, tx.clone()).await {
|
||||
error!("Error processing message: {}", e);
|
||||
let error_msg = DaemonMessage::Error {
|
||||
message: e.to_string(),
|
||||
};
|
||||
tx.send(error_msg).await.ok();
|
||||
let mut buffer = String::new();
|
||||
loop {
|
||||
// Read a line from the stream
|
||||
buffer.clear();
|
||||
match reader.read_line(&mut buffer).await {
|
||||
Ok(0) => break, // End of stream
|
||||
Ok(_) => {
|
||||
// Parse the message
|
||||
match serde_json::from_str::<ClientMessage>(&buffer) {
|
||||
Ok(msg) => {
|
||||
debug!("Received message: {:?}", msg);
|
||||
if let Err(e) = process_message(msg, &session_manager, tx.clone()).await {
|
||||
error!("Error processing message: {}", e);
|
||||
let error_msg = DaemonMessage::Error {
|
||||
message: e.to_string(),
|
||||
};
|
||||
tx.send(error_msg).await.ok();
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to parse client message: {}", e);
|
||||
let error_msg = DaemonMessage::Error {
|
||||
message: format!("Invalid message format: {}", e),
|
||||
};
|
||||
tx.send(error_msg).await.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Error reading from client: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue