use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::{UnixListener, UnixStream};
use tokio::signal;
use tracing::{error, info};
#[derive(Debug, Serialize, Deserialize)]
pub struct CompletionRequest {
pub buffer: String,
pub cursor: usize,
#[serde(default = "default_version")]
pub version: u8,
}
fn default_version() -> u8 {
1
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Suggestion {
pub text: String,
pub description: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CompletionResponse {
pub suggestions: Vec<Suggestion>,
}
#[derive(Debug, Serialize)]
pub struct ErrorResponse {
pub error: String,
}
pub async fn start(socket_path: &str) -> Result<()> {
let _ = std::fs::remove_file(socket_path);
let listener = UnixListener::bind(socket_path)
.context(format!("Failed to bind to socket: {}", socket_path))?;
info!("Daemon listening on {}", socket_path);
let shutdown = signal::ctrl_c();
tokio::pin!(shutdown);
loop {
tokio::select! {
result = listener.accept() => {
match result {
Ok((stream, _addr)) => {
tokio::spawn(async move {
if let Err(e) = handle_connection(stream).await {
error!("Connection error: {}", e);
}
});
}
Err(e) => {
error!("Failed to accept connection: {}", e);
}
}
}
_ = &mut shutdown => {
info!("Received shutdown signal, cleaning up...");
break;
}
}
}
let _ = std::fs::remove_file(socket_path);
info!("Daemon shut down gracefully");
Ok(())
}
async fn handle_connection(stream: UnixStream) -> Result<()> {
let (reader, mut writer) = stream.into_split();
let mut reader = BufReader::new(reader);
let mut line = String::new();
reader
.read_line(&mut line)
.await
.context("Failed to read request")?;
let request: CompletionRequest = match serde_json::from_str(&line) {
Ok(req) => req,
Err(e) => {
let error_response = ErrorResponse {
error: format!("Invalid JSON: {}", e),
};
let response = serde_json::to_string(&error_response)?;
writer.write_all(response.as_bytes()).await?;
writer.write_all(b"\n").await?;
return Ok(());
}
};
info!(
"Received request: buffer='{}', cursor={}",
request.buffer, request.cursor
);
let suggestions = generate_suggestions(&request);
let response = CompletionResponse { suggestions };
let response_json = serde_json::to_string(&response)?;
writer.write_all(response_json.as_bytes()).await?;
writer.write_all(b"\n").await?;
writer.flush().await?;
Ok(())
}
fn generate_suggestions(request: &CompletionRequest) -> Vec<Suggestion> {
let _ = request;
Vec::new()
}