114 lines
3.5 KiB
Rust
114 lines
3.5 KiB
Rust
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<String>,
|
|
}
|
|
|
|
pub struct IoApi {
|
|
pub ctx: Arc<AppContext>,
|
|
}
|
|
|
|
#[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<FilePathPayload>) -> OpenApiResult<Json<String>> {
|
|
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<WriteFilePayload>) -> OpenApiResult<Json<bool>> {
|
|
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<FilePathPayload>,
|
|
) -> OpenApiResult<Json<Vec<io_fs::FileEntry>>> {
|
|
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<FilePathPayload>,
|
|
) -> OpenApiResult<Json<Vec<io_fs::FileEntry>>> {
|
|
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<Json<String>> {
|
|
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<SearchPayload>,
|
|
) -> OpenApiResult<Json<Vec<crate::io::search::SearchResult>>> {
|
|
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<ExecShellPayload>,
|
|
) -> OpenApiResult<Json<crate::io::shell::CommandOutput>> {
|
|
let output =
|
|
crate::io::shell::exec_shell(payload.0.command, payload.0.args, &self.ctx.state)
|
|
.await
|
|
.map_err(bad_request)?;
|
|
Ok(Json(output))
|
|
}
|
|
}
|