Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 127 additions & 117 deletions sandcrate-backend/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,55 +69,37 @@ async fn get_plugins(
})
)
})?;
let plugins_dir = FsPath::new("../assets/plugins");
let mut plugins = Vec::new();

if let Ok(entries) = fs::read_dir(plugins_dir) {
for entry in entries {
if let Ok(entry) = entry {
let path = entry.path();
if let Some(extension) = path.extension() {
if extension == "wasm" {
if let Ok(metadata) = fs::metadata(&path) {
let filename = path.file_name()
.and_then(|n| n.to_str())
.unwrap_or("unknown")
.to_string();

let name = filename.replace(".wasm", "");
let id = name.clone();

let created_at = metadata.created()
.ok()
.and_then(|time| time.duration_since(std::time::UNIX_EPOCH).ok())
.map(|duration| {
chrono::DateTime::from_timestamp(duration.as_secs() as i64, 0)
.unwrap_or_default()
.format("%Y-%m-%d %H:%M:%S")
.to_string()
})
.unwrap_or_else(|| "Unknown".to_string());

plugins.push(Plugin {
id,
name,
filename,
size: metadata.len(),
created_at,
status: "ready".to_string(),
});
}
}
}
}
// Get plugins from database using the service
match state.plugin_service.list_plugins(None, None).await {
Ok(db_plugins) => {
let plugins = db_plugins.into_iter().map(|p| Plugin {
id: p.id.to_string(),
name: p.name,
filename: p.filename,
size: p.file_size as u64,
created_at: p.created_at.format("%Y-%m-%d %H:%M:%S").to_string(),
status: format!("{:?}", p.status),
}).collect();

Ok(Json(ApiResponse {
success: true,
data: Some(PluginList { plugins }),
error: None,
}))
}
Err(e) => {
eprintln!("Error fetching plugins from database: {}", e);
Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ApiResponse {
success: false,
data: None,
error: Some("Failed to fetch plugins from database".to_string()),
})
))
}
}

Ok(Json(ApiResponse {
success: true,
data: Some(PluginList { plugins }),
error: None,
}))
}

async fn get_plugin(
Expand All @@ -136,66 +118,65 @@ async fn get_plugin(
})
)
})?;
let plugins_dir = FsPath::new("../assets/plugins");
let plugin_path = plugins_dir.join(format!("{}.wasm", plugin_id));

if !plugin_path.exists() {
return Ok((
StatusCode::NOT_FOUND,
Json(ApiResponse::<Plugin> {
success: false,
data: None,
error: Some(format!("Plugin '{}' not found", plugin_id)),
})
).into_response());
}
// Parse UUID from plugin_id
use uuid::Uuid;
let plugin_uuid = match Uuid::parse_str(&plugin_id) {
Ok(uuid) => uuid,
Err(_) => {
return Ok((
StatusCode::BAD_REQUEST,
Json(ApiResponse::<Plugin> {
success: false,
data: None,
error: Some("Invalid plugin ID format".to_string()),
})
).into_response());
}
};

if let Ok(metadata) = fs::metadata(&plugin_path) {
let filename = plugin_path.file_name()
.and_then(|n| n.to_str())
.unwrap_or("unknown")
.to_string();

let name = filename.replace(".wasm", "");
let id = name.clone();

let created_at = metadata.created()
.ok()
.and_then(|time| time.duration_since(std::time::UNIX_EPOCH).ok())
.map(|duration| {
chrono::DateTime::from_timestamp(duration.as_secs() as i64, 0)
.unwrap_or_default()
.format("%Y-%m-%d %H:%M:%S")
.to_string()
})
.unwrap_or_else(|| "Unknown".to_string());

let plugin = Plugin {
id,
name,
filename,
size: metadata.len(),
created_at,
status: "ready".to_string(),
};

Ok((
StatusCode::OK,
Json(ApiResponse {
success: true,
data: Some(plugin),
error: None,
})
).into_response())
} else {
Ok((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ApiResponse::<Plugin> {
success: false,
data: None,
error: Some("Failed to read plugin metadata".to_string()),
})
).into_response())
// Get plugin from database using the service
match state.plugin_service.get_plugin_by_id(plugin_uuid).await {
Ok(Some(db_plugin)) => {
let plugin = Plugin {
id: db_plugin.id.to_string(),
name: db_plugin.name,
filename: db_plugin.filename,
size: db_plugin.file_size as u64,
created_at: db_plugin.created_at.format("%Y-%m-%d %H:%M:%S").to_string(),
status: format!("{:?}", db_plugin.status),
};

Ok((
StatusCode::OK,
Json(ApiResponse {
success: true,
data: Some(plugin),
error: None,
})
).into_response())
}
Ok(None) => {
Ok((
StatusCode::NOT_FOUND,
Json(ApiResponse::<Plugin> {
success: false,
data: None,
error: Some(format!("Plugin '{}' not found", plugin_id)),
})
).into_response())
}
Err(e) => {
eprintln!("Error fetching plugin from database: {}", e);
Ok((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ApiResponse::<Plugin> {
success: false,
data: None,
error: Some("Failed to fetch plugin from database".to_string()),
})
).into_response())
}
}
}

Expand All @@ -218,24 +199,53 @@ async fn execute_plugin(
})?;
let start_time = std::time::Instant::now();

let plugins_dir = FsPath::new("../assets/plugins");
let plugin_path = plugins_dir.join(format!("{}.wasm", plugin_id));
// Parse UUID from plugin_id
use uuid::Uuid;
let plugin_uuid = match Uuid::parse_str(&plugin_id) {
Ok(uuid) => uuid,
Err(_) => {
return Ok((
StatusCode::BAD_REQUEST,
Json(ApiResponse::<PluginExecutionResponse> {
success: false,
data: None,
error: Some("Invalid plugin ID format".to_string()),
})
).into_response());
}
};

if !plugin_path.exists() {
return Ok((
StatusCode::NOT_FOUND,
Json(ApiResponse::<PluginExecutionResponse> {
success: false,
data: None,
error: Some(format!("Plugin '{}' not found", plugin_id)),
})
).into_response());
}
// Get plugin from database
let db_plugin = match state.plugin_service.get_plugin_by_id(plugin_uuid).await {
Ok(Some(plugin)) => plugin,
Ok(None) => {
return Ok((
StatusCode::NOT_FOUND,
Json(ApiResponse::<PluginExecutionResponse> {
success: false,
data: None,
error: Some(format!("Plugin '{}' not found", plugin_id)),
})
).into_response());
}
Err(e) => {
eprintln!("Error fetching plugin from database: {}", e);
return Ok((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ApiResponse::<PluginExecutionResponse> {
success: false,
data: None,
error: Some("Failed to fetch plugin from database".to_string()),
})
).into_response());
}
};

let parameters = request.parameters;
let timeout = request.timeout;

let plugin_path_str = plugin_path.to_str().unwrap_or("");
// Use the file_path from the database
let plugin_path_str = &db_plugin.file_path;
let execution_result = plugin::run_plugin_with_params(
plugin_path_str,
parameters,
Expand Down
4 changes: 2 additions & 2 deletions sandcrate-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ mod api;
mod auth;
pub mod plugin;
mod websocket;
mod database;
mod services;
pub mod database;
pub mod services;

use std::net::SocketAddr;
use std::sync::Arc;
Expand Down
5 changes: 5 additions & 0 deletions sandcrate-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ edition = "2021"

[dependencies]
sandcrate-backend = { path = "../sandcrate-backend" }
clap = { version = "4.4", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"
dotenv = "0.15"
uuid = { version = "1.0", features = ["v4", "serde"] }
Loading
Loading