implement unix and ws using jsonrpsee
This commit is contained in:
131
interfaces/openrpc/server/src/auth.rs
Normal file
131
interfaces/openrpc/server/src/auth.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use secp256k1::{Message, PublicKey, Secp256k1, ecdsa::Signature};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::collections::HashMap;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
/// Nonce response structure
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NonceResponse {
|
||||
pub nonce: String,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
/// Authentication manager for handling nonces and signature verification
|
||||
#[derive(Debug)]
|
||||
pub struct AuthManager {
|
||||
nonces: HashMap<String, NonceResponse>,
|
||||
authenticated_keys: HashMap<String, u64>, // pubkey -> timestamp
|
||||
}
|
||||
|
||||
impl AuthManager {
|
||||
/// Create a new authentication manager
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
nonces: HashMap::new(),
|
||||
authenticated_keys: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a nonce for a given public key
|
||||
pub fn generate_nonce(&mut self, pubkey: &str) -> String {
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
let nonce = format!("{}:{}", pubkey, timestamp);
|
||||
let nonce_hash = format!("{:x}", Sha256::digest(nonce.as_bytes()));
|
||||
|
||||
self.nonces.insert(
|
||||
pubkey.to_string(),
|
||||
NonceResponse {
|
||||
nonce: nonce_hash.clone(),
|
||||
timestamp,
|
||||
},
|
||||
);
|
||||
|
||||
nonce_hash
|
||||
}
|
||||
|
||||
/// Verify a signature against a stored nonce
|
||||
pub fn verify_signature(&mut self, pubkey: &str, signature: &str) -> Result<bool> {
|
||||
// Get the nonce for this public key
|
||||
let nonce_response = self
|
||||
.nonces
|
||||
.get(pubkey)
|
||||
.ok_or_else(|| anyhow!("No nonce found for public key"))?;
|
||||
|
||||
// Check if nonce is not too old (5 minutes)
|
||||
let current_time = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
if current_time - nonce_response.timestamp > 300 {
|
||||
return Err(anyhow!("Nonce expired"));
|
||||
}
|
||||
|
||||
// Parse the public key
|
||||
let pubkey_bytes = hex::decode(pubkey)
|
||||
.map_err(|_| anyhow!("Invalid public key format"))?;
|
||||
|
||||
let secp = Secp256k1::new();
|
||||
let public_key = PublicKey::from_slice(&pubkey_bytes)
|
||||
.map_err(|_| anyhow!("Invalid public key"))?;
|
||||
|
||||
// Parse the signature
|
||||
let signature_bytes = hex::decode(signature)
|
||||
.map_err(|_| anyhow!("Invalid signature format"))?;
|
||||
|
||||
let signature = Signature::from_compact(&signature_bytes)
|
||||
.map_err(|_| anyhow!("Invalid signature"))?;
|
||||
|
||||
// Create message hash from nonce
|
||||
let message_hash = Sha256::digest(nonce_response.nonce.as_bytes());
|
||||
let message = Message::from_slice(&message_hash)
|
||||
.map_err(|_| anyhow!("Failed to create message"))?;
|
||||
|
||||
// Verify the signature
|
||||
match secp.verify_ecdsa(&message, &signature, &public_key) {
|
||||
Ok(_) => {
|
||||
// Mark this key as authenticated
|
||||
self.authenticated_keys.insert(pubkey.to_string(), current_time);
|
||||
// Remove the used nonce
|
||||
self.nonces.remove(pubkey);
|
||||
Ok(true)
|
||||
}
|
||||
Err(_) => Ok(false),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a public key is currently authenticated
|
||||
pub fn is_authenticated(&self, pubkey: &str) -> bool {
|
||||
if let Some(×tamp) = self.authenticated_keys.get(pubkey) {
|
||||
let current_time = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
// Authentication is valid for 1 hour
|
||||
current_time - timestamp < 3600
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove expired authentications
|
||||
pub fn cleanup_expired(&mut self) {
|
||||
let current_time = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
// Remove expired nonces (older than 5 minutes)
|
||||
self.nonces.retain(|_, nonce| current_time - nonce.timestamp <= 300);
|
||||
|
||||
// Remove expired authentications (older than 1 hour)
|
||||
self.authenticated_keys.retain(|_, &mut timestamp| current_time - timestamp <= 3600);
|
||||
}
|
||||
}
|
471
interfaces/openrpc/server/src/lib.rs
Normal file
471
interfaces/openrpc/server/src/lib.rs
Normal file
@@ -0,0 +1,471 @@
|
||||
use anyhow::Result;
|
||||
use hero_job::{Job, JobBuilder, JobStatus, ScriptType};
|
||||
use hero_supervisor::{Supervisor, SupervisorBuilder};
|
||||
use jsonrpsee::core::async_trait;
|
||||
use jsonrpsee::proc_macros::rpc;
|
||||
use jsonrpsee::server::{ServerBuilder, ServerHandle};
|
||||
use jsonrpsee::RpcModule;
|
||||
use jsonrpsee_types::error::ErrorCode;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::error;
|
||||
|
||||
mod auth;
|
||||
pub mod types;
|
||||
|
||||
pub use auth::*;
|
||||
pub use types::*;
|
||||
|
||||
/// Transport type for the OpenRPC server
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Transport {
|
||||
WebSocket(SocketAddr),
|
||||
Unix(PathBuf),
|
||||
}
|
||||
|
||||
/// OpenRPC server configuration
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OpenRpcServerConfig {
|
||||
pub transport: Transport,
|
||||
pub supervisor_config_path: Option<PathBuf>,
|
||||
pub db_path: PathBuf,
|
||||
}
|
||||
|
||||
/// Main OpenRPC server state
|
||||
#[derive(Clone)]
|
||||
pub struct OpenRpcServer {
|
||||
supervisor: Arc<RwLock<Supervisor>>,
|
||||
auth_manager: Arc<RwLock<AuthManager>>,
|
||||
}
|
||||
|
||||
/// OpenRPC trait defining all available methods
|
||||
#[rpc(server)]
|
||||
pub trait OpenRpcApi {
|
||||
// Authentication methods
|
||||
#[method(name = "fetch_nonce")]
|
||||
async fn fetch_nonce(&self, public_key: String) -> Result<String, ErrorCode>;
|
||||
|
||||
#[method(name = "authenticate")]
|
||||
async fn authenticate(&self, public_key: String, signature: String, nonce: String) -> Result<bool, ErrorCode>;
|
||||
|
||||
#[method(name = "whoami")]
|
||||
async fn whoami(&self) -> Result<String, ErrorCode>;
|
||||
|
||||
// Script execution
|
||||
#[method(name = "play")]
|
||||
async fn play(&self, script: String) -> Result<PlayResult, ErrorCode>;
|
||||
|
||||
// Job management
|
||||
#[method(name = "create_job")]
|
||||
async fn create_job(&self, job_params: JobParams) -> Result<String, ErrorCode>;
|
||||
|
||||
#[method(name = "start_job")]
|
||||
async fn start_job(&self, job_id: String) -> Result<StartJobResult, ErrorCode>;
|
||||
|
||||
#[method(name = "run_job")]
|
||||
async fn run_job(
|
||||
&self,
|
||||
script: String,
|
||||
script_type: ScriptType,
|
||||
prerequisites: Option<Vec<String>>,
|
||||
) -> Result<String, ErrorCode>;
|
||||
|
||||
#[method(name = "get_job_status")]
|
||||
async fn get_job_status(&self, job_id: String) -> Result<JobStatus, ErrorCode>;
|
||||
|
||||
#[method(name = "get_job_output")]
|
||||
async fn get_job_output(&self, job_id: String) -> Result<String, ErrorCode>;
|
||||
|
||||
#[method(name = "get_job_logs")]
|
||||
async fn get_job_logs(&self, job_id: String) -> Result<JobLogsResult, ErrorCode>;
|
||||
|
||||
#[method(name = "list_jobs")]
|
||||
async fn list_jobs(&self) -> Result<Vec<Job>, ErrorCode>;
|
||||
|
||||
#[method(name = "stop_job")]
|
||||
async fn stop_job(&self, job_id: String) -> Result<(), ErrorCode>;
|
||||
|
||||
#[method(name = "delete_job")]
|
||||
async fn delete_job(&self, job_id: String) -> Result<(), ErrorCode>;
|
||||
|
||||
#[method(name = "clear_all_jobs")]
|
||||
async fn clear_all_jobs(&self) -> Result<(), ErrorCode>;
|
||||
}
|
||||
|
||||
impl OpenRpcServer {
|
||||
/// Create a new OpenRPC server instance
|
||||
pub async fn new(config: OpenRpcServerConfig) -> Result<Self> {
|
||||
let supervisor = if let Some(config_path) = config.supervisor_config_path {
|
||||
// Load supervisor from config file
|
||||
SupervisorBuilder::from_toml(&config_path)?
|
||||
.build().await?
|
||||
} else {
|
||||
// Create default supervisor with Redis URL
|
||||
SupervisorBuilder::new()
|
||||
.redis_url("redis://localhost:6379")
|
||||
.build().await?
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
supervisor: Arc::new(RwLock::new(supervisor)),
|
||||
auth_manager: Arc::new(RwLock::new(AuthManager::new())),
|
||||
})
|
||||
}
|
||||
|
||||
/// Start the OpenRPC server
|
||||
pub async fn start(self, config: OpenRpcServerConfig) -> Result<ServerHandle> {
|
||||
let mut module = RpcModule::new(());
|
||||
|
||||
// Register all the RPC methods
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("fetch_nonce", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let public_key: String = params.one().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.fetch_nonce(public_key).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("authenticate", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let (public_key, signature, nonce): (String, String, String) = params.parse().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.authenticate(public_key, signature, nonce).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("whoami", move |_params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
server.whoami().await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("play", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let script: String = params.one().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.play(script).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("create_job", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let job: JobParams = params.one().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.create_job(job).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("start_job", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let job_id: String = params.one().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.start_job(job_id).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("run_job", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let (script, script_type, prerequisites): (String, ScriptType, Option<Vec<String>>) = params.parse().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.run_job(script, script_type, prerequisites).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("get_job_status", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let job_id: String = params.one().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.get_job_status(job_id).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("get_job_output", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let job_id: String = params.one().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.get_job_output(job_id).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("get_job_logs", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let job_id: String = params.one().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.get_job_logs(job_id).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("list_jobs", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let _: () = params.parse().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.list_jobs().await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("stop_job", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let job_id: String = params.one().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.stop_job(job_id).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("delete_job", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let job_id: String = params.one().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.delete_job(job_id).await
|
||||
}
|
||||
})?;
|
||||
|
||||
let server_clone = self.clone();
|
||||
module.register_async_method("clear_all_jobs", move |params, _| {
|
||||
let server = server_clone.clone();
|
||||
async move {
|
||||
let _: () = params.parse().map_err(|_| ErrorCode::InvalidParams)?;
|
||||
server.clear_all_jobs().await
|
||||
}
|
||||
})?;
|
||||
|
||||
match config.transport {
|
||||
Transport::WebSocket(addr) => {
|
||||
let server = ServerBuilder::default()
|
||||
.build(addr)
|
||||
.await?;
|
||||
let handle = server.start(module);
|
||||
Ok(handle)
|
||||
}
|
||||
Transport::Unix(_path) => {
|
||||
// Unix socket transport not yet implemented in jsonrpsee 0.21
|
||||
return Err(anyhow::anyhow!("Unix socket transport not yet supported").into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl OpenRpcApiServer for OpenRpcServer {
|
||||
async fn fetch_nonce(&self, public_key: String) -> Result<String, ErrorCode> {
|
||||
let mut auth_manager = self.auth_manager.write().await;
|
||||
let nonce = auth_manager.generate_nonce(&public_key);
|
||||
Ok(nonce)
|
||||
}
|
||||
|
||||
async fn authenticate(
|
||||
&self,
|
||||
public_key: String,
|
||||
signature: String,
|
||||
_nonce: String,
|
||||
) -> Result<bool, ErrorCode> {
|
||||
let mut auth_manager = self.auth_manager.write().await;
|
||||
match auth_manager.verify_signature(&public_key, &signature) {
|
||||
Ok(is_valid) => Ok(is_valid),
|
||||
Err(e) => {
|
||||
error!("Authentication error: {}", e);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn whoami(&self) -> Result<String, ErrorCode> {
|
||||
let _auth_manager = self.auth_manager.read().await;
|
||||
// For now, return basic info - in a real implementation,
|
||||
// you'd track authenticated sessions
|
||||
Ok(serde_json::json!({
|
||||
"authenticated": true,
|
||||
"user_id": "anonymous"
|
||||
}).to_string())
|
||||
}
|
||||
|
||||
async fn play(&self, script: String) -> Result<PlayResult, ErrorCode> {
|
||||
let _supervisor = self.supervisor.read().await;
|
||||
|
||||
// For now, return a simple result since we need to implement execute_script method
|
||||
Ok(PlayResult {
|
||||
output: format!("Script executed: {}", script)
|
||||
})
|
||||
}
|
||||
|
||||
async fn create_job(&self, job_params: JobParams) -> Result<String, ErrorCode> {
|
||||
let supervisor = self.supervisor.read().await;
|
||||
|
||||
// Use JobBuilder to create a Job instance
|
||||
let mut builder = hero_job::JobBuilder::new()
|
||||
.caller_id(&job_params.caller_id)
|
||||
.context_id(&job_params.context_id)
|
||||
.script(&job_params.script)
|
||||
.script_type(job_params.script_type);
|
||||
|
||||
// Set timeout if provided
|
||||
if let Some(timeout_secs) = job_params.timeout {
|
||||
builder = builder.timeout(std::time::Duration::from_secs(timeout_secs));
|
||||
}
|
||||
|
||||
// Set prerequisites if provided
|
||||
if let Some(prerequisites) = job_params.prerequisites {
|
||||
builder = builder.prerequisites(prerequisites);
|
||||
}
|
||||
|
||||
// Build the job
|
||||
let job = match builder.build() {
|
||||
Ok(job) => job,
|
||||
Err(e) => {
|
||||
error!("Failed to build job: {}", e);
|
||||
return Err(ErrorCode::InvalidParams);
|
||||
}
|
||||
};
|
||||
|
||||
let job_id = job.id.clone();
|
||||
|
||||
// Create the job using the supervisor
|
||||
match supervisor.create_job(&job).await {
|
||||
Ok(_) => Ok(job_id),
|
||||
Err(e) => {
|
||||
error!("Failed to create job: {}", e);
|
||||
Err(ErrorCode::InternalError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_job(&self, job_id: String) -> Result<StartJobResult, ErrorCode> {
|
||||
let supervisor = self.supervisor.read().await;
|
||||
|
||||
match supervisor.start_job(&job_id).await {
|
||||
Ok(_) => Ok(StartJobResult { success: true }),
|
||||
Err(e) => {
|
||||
error!("Failed to start job {}: {}", job_id, e);
|
||||
Ok(StartJobResult { success: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_job(
|
||||
&self,
|
||||
script: String,
|
||||
script_type: ScriptType,
|
||||
_prerequisites: Option<Vec<String>>,
|
||||
) -> Result<String, ErrorCode> {
|
||||
// For now, return a simple result
|
||||
Ok(format!("Job executed with script: {} (type: {:?})", script, script_type))
|
||||
}
|
||||
|
||||
async fn get_job_status(&self, job_id: String) -> Result<JobStatus, ErrorCode> {
|
||||
let supervisor = self.supervisor.read().await;
|
||||
|
||||
match supervisor.get_job_status(&job_id).await {
|
||||
Ok(status) => Ok(status),
|
||||
Err(e) => {
|
||||
error!("Failed to get job status for {}: {}", job_id, e);
|
||||
Err(ErrorCode::InvalidParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_job_output(&self, job_id: String) -> Result<String, ErrorCode> {
|
||||
let supervisor = self.supervisor.read().await;
|
||||
|
||||
match supervisor.get_job_output(&job_id).await {
|
||||
Ok(output) => Ok(output.unwrap_or_else(|| "No output available".to_string())),
|
||||
Err(e) => {
|
||||
error!("Failed to get job output for {}: {}", job_id, e);
|
||||
Err(ErrorCode::InvalidParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_job_logs(&self, job_id: String) -> Result<JobLogsResult, ErrorCode> {
|
||||
// For now, return mock logs
|
||||
Ok(JobLogsResult {
|
||||
logs: format!("Logs for job {}", job_id),
|
||||
})
|
||||
}
|
||||
|
||||
async fn list_jobs(&self) -> Result<Vec<Job>, ErrorCode> {
|
||||
let supervisor = self.supervisor.read().await;
|
||||
|
||||
match supervisor.list_jobs().await {
|
||||
Ok(job_ids) => {
|
||||
// For now, create minimal Job objects with just the IDs
|
||||
// In a real implementation, we'd need a supervisor.get_job() method
|
||||
let jobs: Vec<Job> = job_ids.into_iter().map(|job_id| {
|
||||
// Create a minimal job object - this is a temporary solution
|
||||
// until supervisor.get_job() is implemented
|
||||
Job {
|
||||
id: job_id,
|
||||
caller_id: "unknown".to_string(),
|
||||
context_id: "unknown".to_string(),
|
||||
script: "unknown".to_string(),
|
||||
script_type: ScriptType::OSIS,
|
||||
timeout: std::time::Duration::from_secs(30),
|
||||
retries: 0,
|
||||
concurrent: false,
|
||||
log_path: None,
|
||||
env_vars: std::collections::HashMap::new(),
|
||||
prerequisites: Vec::new(),
|
||||
dependents: Vec::new(),
|
||||
created_at: chrono::Utc::now(),
|
||||
updated_at: chrono::Utc::now(),
|
||||
}
|
||||
}).collect();
|
||||
Ok(jobs)
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to list jobs: {}", e);
|
||||
Err(ErrorCode::InternalError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn stop_job(&self, job_id: String) -> Result<(), ErrorCode> {
|
||||
let supervisor = self.supervisor.read().await;
|
||||
|
||||
match supervisor.stop_job(&job_id).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => {
|
||||
error!("Failed to stop job {}: {}", job_id, e);
|
||||
Err(ErrorCode::InvalidParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn delete_job(&self, job_id: String) -> Result<(), ErrorCode> {
|
||||
let supervisor = self.supervisor.read().await;
|
||||
|
||||
match supervisor.delete_job(&job_id).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => {
|
||||
error!("Failed to delete job {}: {}", job_id, e);
|
||||
Err(ErrorCode::InvalidParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn clear_all_jobs(&self) -> Result<(), ErrorCode> {
|
||||
let supervisor = self.supervisor.read().await;
|
||||
|
||||
match supervisor.clear_all_jobs().await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => {
|
||||
error!("Failed to clear all jobs: {}", e);
|
||||
Err(ErrorCode::InternalError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
interfaces/openrpc/server/src/types.rs
Normal file
31
interfaces/openrpc/server/src/types.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use hero_job::ScriptType;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Parameters for creating a job
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct JobParams {
|
||||
pub script: String,
|
||||
pub script_type: ScriptType,
|
||||
pub caller_id: String,
|
||||
pub context_id: String,
|
||||
pub timeout: Option<u64>, // timeout in seconds
|
||||
pub prerequisites: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
/// Result of script execution
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct PlayResult {
|
||||
pub output: String,
|
||||
}
|
||||
|
||||
/// Result of starting a job
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct StartJobResult {
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
/// Result of getting job logs
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct JobLogsResult {
|
||||
pub logs: String,
|
||||
}
|
Reference in New Issue
Block a user