From 24ca03db637cfcb66a2fdeb4fe2a1407ca3b7d69 Mon Sep 17 00:00:00 2001 From: mahesh bhatiya Date: Tue, 29 Jul 2025 00:44:39 +0530 Subject: [PATCH 1/2] feat: add plugin execution functionality with WASM support Add complete plugin execution system - Implement POST /api/plugins/:id/execute endpoint - Add WASM plugin execution with parameter support - Create execution modal with JSON parameter input - Display execution results with timing information - Support custom timeout and parameter passing --- sandcrate-backend/src/api.rs | 21 +- sandcrate-backend/src/bin/execute_plugin.rs | 47 +++ sandcrate-backend/src/lib.rs | 2 +- .../src/components/ErrorBoundary.tsx | 3 +- sandcrate-react/src/components/Sidebar.tsx | 2 +- sandcrate-react/src/pages/Auth.tsx | 2 +- sandcrate-react/src/pages/Plugins.tsx | 340 +++++++++++++++--- 7 files changed, 364 insertions(+), 53 deletions(-) create mode 100644 sandcrate-backend/src/bin/execute_plugin.rs diff --git a/sandcrate-backend/src/api.rs b/sandcrate-backend/src/api.rs index 8576589..cc2f02e 100644 --- a/sandcrate-backend/src/api.rs +++ b/sandcrate-backend/src/api.rs @@ -4,7 +4,7 @@ use axum::{ http::StatusCode, response::{IntoResponse, Response}, }; -use serde::{Serialize, Deserialize}; +use serde::Serialize; use std::sync::Arc; use std::fs; use std::path::Path as FsPath; @@ -58,7 +58,7 @@ struct ErrorResponse { async fn get_plugins( State(_config): State>, ) -> Json> { - let plugins_dir = FsPath::new("assets/plugins"); + let plugins_dir = FsPath::new("../assets/plugins"); let mut plugins = Vec::new(); if let Ok(entries) = fs::read_dir(plugins_dir) { @@ -110,9 +110,10 @@ async fn get_plugins( } async fn get_plugin( + State(_config): State>, Path(plugin_id): Path, ) -> Response { - let plugins_dir = FsPath::new("assets/plugins"); + let plugins_dir = FsPath::new("../assets/plugins"); let plugin_path = plugins_dir.join(format!("{}.wasm", plugin_id)); if !plugin_path.exists() { @@ -176,13 +177,14 @@ async fn get_plugin( } async fn execute_plugin( + State(_config): State>, Path(plugin_id): Path, - Json(request): Json, + Json(request): Json, ) -> Response { let start_time = std::time::Instant::now(); // Find the plugin file - let plugins_dir = FsPath::new("assets/plugins"); + let plugins_dir = FsPath::new("../assets/plugins"); let plugin_path = plugins_dir.join(format!("{}.wasm", plugin_id)); if !plugin_path.exists() { @@ -196,12 +198,16 @@ async fn execute_plugin( ).into_response(); } + // Extract parameters from the request + let parameters = request.get("parameters").cloned(); + let timeout = request.get("timeout").and_then(|v| v.as_u64()); + // Execute the plugin with parameters and timeout let plugin_path_str = plugin_path.to_str().unwrap_or(""); let execution_result = plugin::run_plugin_with_params( plugin_path_str, - request.parameters, - request.timeout + parameters, + timeout ); let execution_time = start_time.elapsed(); @@ -249,4 +255,5 @@ pub fn routes() -> Router> { Router::new() .route("/plugins", get(get_plugins)) .route("/plugins/:id", get(get_plugin)) + .route("/plugins/:id/execute", post(execute_plugin)) } diff --git a/sandcrate-backend/src/bin/execute_plugin.rs b/sandcrate-backend/src/bin/execute_plugin.rs new file mode 100644 index 0000000..18dfacc --- /dev/null +++ b/sandcrate-backend/src/bin/execute_plugin.rs @@ -0,0 +1,47 @@ +use std::env; +use std::path::Path; +use sandcrate_backend::plugin; + +fn main() -> Result<(), Box> { + let args: Vec = env::args().collect(); + + if args.len() != 2 { + println!("Usage: {} ", args[0]); + println!("Example: {} sandcrate-plugin", args[0]); + return Ok(()); + } + + let plugin_name = &args[1]; + let plugin_path = format!("assets/plugins/{}.wasm", plugin_name); + + if !Path::new(&plugin_path).exists() { + println!("❌ Plugin '{}' not found at {}", plugin_name, plugin_path); + println!("Available plugins:"); + + let plugins = plugin::list_plugins(); + if plugins.is_empty() { + println!(" No plugins found in assets/plugins directory"); + } else { + for plugin in plugins { + println!(" - {}", plugin); + } + } + return Ok(()); + } + + println!("🚀 Executing plugin: {}", plugin_name); + println!("📁 Path: {}", plugin_path); + println!("---"); + + match plugin::run_plugin(&plugin_path) { + Ok(result) => { + println!("✅ Plugin executed successfully!"); + println!("📋 Result: {}", result); + } + Err(e) => { + println!("❌ Plugin execution failed: {}", e); + } + } + + Ok(()) +} \ No newline at end of file diff --git a/sandcrate-backend/src/lib.rs b/sandcrate-backend/src/lib.rs index aa232a3..280d370 100644 --- a/sandcrate-backend/src/lib.rs +++ b/sandcrate-backend/src/lib.rs @@ -1,6 +1,6 @@ mod api; mod auth; -mod plugin; +pub mod plugin; use std::net::SocketAddr; use std::sync::Arc; diff --git a/sandcrate-react/src/components/ErrorBoundary.tsx b/sandcrate-react/src/components/ErrorBoundary.tsx index e52ca49..d5f0c32 100644 --- a/sandcrate-react/src/components/ErrorBoundary.tsx +++ b/sandcrate-react/src/components/ErrorBoundary.tsx @@ -1,4 +1,5 @@ -import React, { Component, ErrorInfo, ReactNode } from 'react'; +import { Component } from 'react'; +import type { ErrorInfo, ReactNode } from 'react'; interface Props { children: ReactNode; diff --git a/sandcrate-react/src/components/Sidebar.tsx b/sandcrate-react/src/components/Sidebar.tsx index d9a0aab..8edda7f 100644 --- a/sandcrate-react/src/components/Sidebar.tsx +++ b/sandcrate-react/src/components/Sidebar.tsx @@ -53,7 +53,7 @@ export const Sidebar: React.FC = () => {

{user?.name}

-

{user?.email}

+

{user?.username}

+ + + {/* Content */} +
+ {/* Parameters Input */} +
+ +