use crate::http::context::{AppContext, OpenApiResult, bad_request}; use crate::io::fs as io_fs; use poem_openapi::{Object, OpenApi, Tags, payload::Json}; use serde::Deserialize; use std::sync::Arc; #[derive(Tags)] enum IoTags { Io, } #[derive(Deserialize, Object)] struct FilePathPayload { pub path: String, } #[derive(Deserialize, Object)] struct WriteFilePayload { pub path: String, pub content: String, } #[derive(Deserialize, Object)] struct SearchPayload { query: String, } #[derive(Deserialize, Object)] struct ExecShellPayload { pub command: String, pub args: Vec, } pub struct IoApi { pub ctx: Arc, } #[OpenApi(tag = "IoTags::Io")] impl IoApi { /// Read a file from the currently open project and return its contents. #[oai(path = "/io/fs/read", method = "post")] async fn read_file(&self, payload: Json) -> OpenApiResult> { let content = io_fs::read_file(payload.0.path, &self.ctx.state) .await .map_err(bad_request)?; Ok(Json(content)) } /// Write a file to the currently open project, creating parent directories if needed. #[oai(path = "/io/fs/write", method = "post")] async fn write_file(&self, payload: Json) -> OpenApiResult> { io_fs::write_file(payload.0.path, payload.0.content, &self.ctx.state) .await .map_err(bad_request)?; Ok(Json(true)) } /// List files and folders in a directory within the currently open project. #[oai(path = "/io/fs/list", method = "post")] async fn list_directory( &self, payload: Json, ) -> OpenApiResult>> { let entries = io_fs::list_directory(payload.0.path, &self.ctx.state) .await .map_err(bad_request)?; Ok(Json(entries)) } /// List files and folders at an absolute path (not scoped to the project root). #[oai(path = "/io/fs/list/absolute", method = "post")] async fn list_directory_absolute( &self, payload: Json, ) -> OpenApiResult>> { let entries = io_fs::list_directory_absolute(payload.0.path) .await .map_err(bad_request)?; Ok(Json(entries)) } /// Get the user's home directory. #[oai(path = "/io/fs/home", method = "get")] async fn get_home_directory(&self) -> OpenApiResult> { let home = io_fs::get_home_directory().map_err(bad_request)?; Ok(Json(home)) } /// Search the currently open project for files containing the provided query string. #[oai(path = "/io/search", method = "post")] async fn search_files( &self, payload: Json, ) -> OpenApiResult>> { let results = crate::io::search::search_files(payload.0.query, &self.ctx.state) .await .map_err(bad_request)?; Ok(Json(results)) } /// Execute an allowlisted shell command in the currently open project. #[oai(path = "/io/shell/exec", method = "post")] async fn exec_shell( &self, payload: Json, ) -> OpenApiResult> { let output = crate::io::shell::exec_shell(payload.0.command, payload.0.args, &self.ctx.state) .await .map_err(bad_request)?; Ok(Json(output)) } }