rename client and move incomplete projects to research
This commit is contained in:
		
							
								
								
									
										38
									
								
								examples/flows/new_create_payment_intent_error.rhai
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								examples/flows/new_create_payment_intent_error.rhai
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | // Error handler for failed payment intent creation | ||||||
|  | // This script is triggered when a payment intent creation fails | ||||||
|  |  | ||||||
|  | print("❌ Payment Intent Creation Failed!"); | ||||||
|  | print("=================================="); | ||||||
|  |  | ||||||
|  | // The error data is available as 'parsed_error' | ||||||
|  | if parsed_error != () { | ||||||
|  |     print(`Error: ${parsed_error}`); | ||||||
|  |      | ||||||
|  |     // You can handle different types of errors | ||||||
|  |     if parsed_error.contains("authentication") { | ||||||
|  |         print("🔑 Authentication error - check API key"); | ||||||
|  |         // eval_file("flows/handle_auth_error.rhai"); | ||||||
|  |     } else if parsed_error.contains("insufficient_funds") { | ||||||
|  |         print("💰 Insufficient funds error"); | ||||||
|  |         // eval_file("flows/handle_insufficient_funds.rhai"); | ||||||
|  |     } else if parsed_error.contains("card_declined") { | ||||||
|  |         print("💳 Card declined error"); | ||||||
|  |         // eval_file("flows/handle_card_declined.rhai"); | ||||||
|  |     } else { | ||||||
|  |         print("⚠️ General payment error"); | ||||||
|  |         // eval_file("flows/handle_general_payment_error.rhai"); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Log the error for monitoring | ||||||
|  |     print("📊 Logging error for analytics..."); | ||||||
|  |     // eval_file("flows/log_payment_error.rhai"); | ||||||
|  |      | ||||||
|  |     // Notify relevant parties | ||||||
|  |     print("📧 Sending error notifications..."); | ||||||
|  |     // eval_file("flows/send_error_notification.rhai"); | ||||||
|  |      | ||||||
|  | } else { | ||||||
|  |     print("⚠️ No error data received"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | print("🔄 Error handling complete!"); | ||||||
							
								
								
									
										34
									
								
								examples/flows/new_create_payment_intent_response.rhai
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								examples/flows/new_create_payment_intent_response.rhai
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | // Response handler for successful payment intent creation | ||||||
|  | // This script is triggered when a payment intent is successfully created | ||||||
|  |  | ||||||
|  | print("✅ Payment Intent Created Successfully!"); | ||||||
|  | print("====================================="); | ||||||
|  |  | ||||||
|  | // The response data is available as 'parsed_data' | ||||||
|  | if parsed_data != () { | ||||||
|  |     print(`Payment Intent ID: ${parsed_data.id}`); | ||||||
|  |     print(`Amount: ${parsed_data.amount}`); | ||||||
|  |     print(`Currency: ${parsed_data.currency}`); | ||||||
|  |     print(`Status: ${parsed_data.status}`); | ||||||
|  |      | ||||||
|  |     if parsed_data.client_secret != () { | ||||||
|  |         print(`Client Secret: ${parsed_data.client_secret}`); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // You can now trigger additional workflows | ||||||
|  |     print("🔄 Triggering next steps..."); | ||||||
|  |      | ||||||
|  |     // Example: Send confirmation email | ||||||
|  |     // eval_file("flows/send_payment_confirmation_email.rhai"); | ||||||
|  |      | ||||||
|  |     // Example: Update user account | ||||||
|  |     // eval_file("flows/update_user_payment_status.rhai"); | ||||||
|  |      | ||||||
|  |     // Example: Log analytics event | ||||||
|  |     // eval_file("flows/log_payment_analytics.rhai"); | ||||||
|  |      | ||||||
|  | } else { | ||||||
|  |     print("⚠️ No response data received"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | print("🎉 Payment intent response processing complete!"); | ||||||
| @@ -8,11 +8,11 @@ tokio = { version = "1", features = ["macros", "rt-multi-thread", "time", "sync" | |||||||
| url = "2" # For parsing Redis URL | url = "2" # For parsing Redis URL | ||||||
| tracing = "0.1" # For logging | tracing = "0.1" # For logging | ||||||
| tracing-subscriber = { version = "0.3", features = ["env-filter"] } | tracing-subscriber = { version = "0.3", features = ["env-filter"] } | ||||||
| log = "0.4" # rhai_client uses log crate | log = "0.4" # rhai_dispatcher uses log crate | ||||||
| rustyline = { version = "13.0.0", features = ["derive"] } # For enhanced REPL input | rustyline = { version = "13.0.0", features = ["derive"] } # For enhanced REPL input | ||||||
| tempfile = "3.8" # For creating temporary files for editing | tempfile = "3.8" # For creating temporary files for editing | ||||||
| 
 | 
 | ||||||
| rhai_client = { path = "../client" } | rhai_dispatcher = { path = "../client" } | ||||||
| anyhow = "1.0" # For simpler error handling | anyhow = "1.0" # For simpler error handling | ||||||
| 
 | 
 | ||||||
| rhailib_worker = { path = "../worker", package = "rhailib_worker" } | rhailib_worker = { path = "../worker", package = "rhailib_worker" } | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| use anyhow::Context; | use anyhow::Context; | ||||||
| use rhai_client::{RhaiClient, RhaiClientError, RhaiTaskDetails}; | use rhai_dispatcher::{RhaiDispatcher, RhaiDispatcherError, RhaiTaskDetails}; | ||||||
| use std::env; | use std::env; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| @@ -17,7 +17,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|         .with_env_filter( |         .with_env_filter( | ||||||
|             EnvFilter::from_default_env() |             EnvFilter::from_default_env() | ||||||
|                 .add_directive("connect_and_play=info".parse().unwrap()) |                 .add_directive("connect_and_play=info".parse().unwrap()) | ||||||
|                 .add_directive("rhai_client=info".parse().unwrap()), |                 .add_directive("rhai_dispatcher=info".parse().unwrap()), | ||||||
|         ) |         ) | ||||||
|         .init(); |         .init(); | ||||||
| 
 | 
 | ||||||
| @@ -94,12 +94,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|     tokio::time::sleep(Duration::from_secs(1)).await; |     tokio::time::sleep(Duration::from_secs(1)).await; | ||||||
| 
 | 
 | ||||||
|     println!( |     println!( | ||||||
|         "Initializing RhaiClient for Redis at {} to target worker '{}'...", |         "Initializing RhaiDispatcher for Redis at {} to target worker '{}'...", | ||||||
|         redis_url, worker_name |         redis_url, worker_name | ||||||
|     ); |     ); | ||||||
|     let client = RhaiClient::new(&redis_url) |     let client = RhaiDispatcher::new(&redis_url) | ||||||
|         .with_context(|| format!("Failed to create RhaiClient for Redis URL: {}", redis_url))?; |         .with_context(|| format!("Failed to create RhaiDispatcher for Redis URL: {}", redis_url))?; | ||||||
|     println!("RhaiClient initialized."); |     println!("RhaiDispatcher initialized."); | ||||||
| 
 | 
 | ||||||
|     let script = "let a = 10; let b = 32; let message = \"Hello from example script!\"; message + \" Result: \" + (a + b)"; |     let script = "let a = 10; let b = 32; let message = \"Hello from example script!\"; message + \" Result: \" + (a + b)"; | ||||||
|     println!("\nSending script:\n```rhai\n{}\n```", script); |     println!("\nSending script:\n```rhai\n{}\n```", script); | ||||||
| @@ -125,28 +125,28 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         Err(e) => match e { |         Err(e) => match e { | ||||||
|             RhaiClientError::Timeout(task_id) => { |             RhaiDispatcherError::Timeout(task_id) => { | ||||||
|                 eprintln!( |                 eprintln!( | ||||||
|                     "\nError: Script execution timed out for task_id: {}.", |                     "\nError: Script execution timed out for task_id: {}.", | ||||||
|                     task_id |                     task_id | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|             RhaiClientError::RedisError(redis_err) => { |             RhaiDispatcherError::RedisError(redis_err) => { | ||||||
|                 eprintln!( |                 eprintln!( | ||||||
|                     "\nError: Redis communication failed: {}. Check Redis connection and server status.", |                     "\nError: Redis communication failed: {}. Check Redis connection and server status.", | ||||||
|                     redis_err |                     redis_err | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|             RhaiClientError::SerializationError(serde_err) => { |             RhaiDispatcherError::SerializationError(serde_err) => { | ||||||
|                 eprintln!( |                 eprintln!( | ||||||
|                     "\nError: Failed to serialize/deserialize task data: {}.", |                     "\nError: Failed to serialize/deserialize task data: {}.", | ||||||
|                     serde_err |                     serde_err | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|             RhaiClientError::TaskNotFound(task_id) => { |             RhaiDispatcherError::TaskNotFound(task_id) => { | ||||||
|                 eprintln!("\nError: Task {} not found after submission.", task_id); |                 eprintln!("\nError: Task {} not found after submission.", task_id); | ||||||
|             } /* All RhaiClientError variants are handled, so _ arm is not strictly needed
 |             } /* All RhaiDispatcherError variants are handled, so _ arm is not strictly needed
 | ||||||
|               unless RhaiClientError becomes non-exhaustive in the future. */ |               unless RhaiDispatcherError becomes non-exhaustive in the future. */ | ||||||
|         }, |         }, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| use anyhow::Context; | use anyhow::Context; | ||||||
| use rhai_client::{RhaiClient, RhaiClientBuilder, RhaiClientError}; | use rhai_dispatcher::{RhaiDispatcher, RhaiDispatcherBuilder, RhaiDispatcherError}; | ||||||
| use rustyline::error::ReadlineError; | use rustyline::error::ReadlineError; | ||||||
| use rustyline::{Config, DefaultEditor, EditMode}; | use rustyline::{Config, DefaultEditor, EditMode}; | ||||||
| use std::env; | use std::env; | ||||||
| @@ -12,7 +12,7 @@ use tracing_subscriber::EnvFilter; | |||||||
| // Default timeout for script execution
 | // Default timeout for script execution
 | ||||||
| const DEFAULT_SCRIPT_TIMEOUT_SECONDS: u64 = 30; | const DEFAULT_SCRIPT_TIMEOUT_SECONDS: u64 = 30; | ||||||
| 
 | 
 | ||||||
| async fn execute_script(client: &RhaiClient, circle_name: &str, script_content: String) { | async fn execute_script(client: &RhaiDispatcher, circle_name: &str, script_content: String) { | ||||||
|     if script_content.trim().is_empty() { |     if script_content.trim().is_empty() { | ||||||
|         println!("Script is empty, not sending."); |         println!("Script is empty, not sending."); | ||||||
|         return; |         return; | ||||||
| @@ -47,25 +47,25 @@ async fn execute_script(client: &RhaiClient, circle_name: &str, script_content: | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         Err(e) => match e { |         Err(e) => match e { | ||||||
|             RhaiClientError::Timeout(task_id) => { |             RhaiDispatcherError::Timeout(task_id) => { | ||||||
|                 eprintln!( |                 eprintln!( | ||||||
|                     "Error: Script execution timed out for task_id: {}.", |                     "Error: Script execution timed out for task_id: {}.", | ||||||
|                     task_id |                     task_id | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|             RhaiClientError::RedisError(redis_err) => { |             RhaiDispatcherError::RedisError(redis_err) => { | ||||||
|                 eprintln!( |                 eprintln!( | ||||||
|                     "Error: Redis communication failed: {}. Check Redis connection and server status.", |                     "Error: Redis communication failed: {}. Check Redis connection and server status.", | ||||||
|                     redis_err |                     redis_err | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|             RhaiClientError::SerializationError(serde_err) => { |             RhaiDispatcherError::SerializationError(serde_err) => { | ||||||
|                 eprintln!( |                 eprintln!( | ||||||
|                     "Error: Failed to serialize/deserialize task data: {}.", |                     "Error: Failed to serialize/deserialize task data: {}.", | ||||||
|                     serde_err |                     serde_err | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|             RhaiClientError::TaskNotFound(task_id) => { |             RhaiDispatcherError::TaskNotFound(task_id) => { | ||||||
|                 eprintln!( |                 eprintln!( | ||||||
|                     "Error: Task {} not found after submission (this should be rare).", |                     "Error: Task {} not found after submission (this should be rare).", | ||||||
|                     task_id |                     task_id | ||||||
| @@ -81,15 +81,15 @@ async fn run_repl(redis_url: String, circle_name: String) -> anyhow::Result<()> | |||||||
|         circle_name, redis_url |         circle_name, redis_url | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     let client = RhaiClientBuilder::new() |     let client = RhaiDispatcherBuilder::new() | ||||||
|         .redis_url(&redis_url) |         .redis_url(&redis_url) | ||||||
|         .caller_id("ui_repl") // Set a caller_id
 |         .caller_id("ui_repl") // Set a caller_id
 | ||||||
|         .build() |         .build() | ||||||
|         .with_context(|| format!("Failed to create RhaiClient for Redis URL: {}", redis_url))?; |         .with_context(|| format!("Failed to create RhaiDispatcher for Redis URL: {}", redis_url))?; | ||||||
| 
 | 
 | ||||||
|     // No explicit connect() needed for rhai_client, connection is handled per-operation or pooled.
 |     // No explicit connect() needed for rhai_dispatcher, connection is handled per-operation or pooled.
 | ||||||
|     println!( |     println!( | ||||||
|         "RhaiClient initialized. Ready to send scripts to worker '{}'.", |         "RhaiDispatcher initialized. Ready to send scripts to worker '{}'.", | ||||||
|         circle_name |         circle_name | ||||||
|     ); |     ); | ||||||
|     println!( |     println!( | ||||||
| @@ -212,7 +212,7 @@ async fn run_repl(redis_url: String, circle_name: String) -> anyhow::Result<()> | |||||||
|         // Failed to save history, not critical
 |         // Failed to save history, not critical
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // No explicit disconnect for RhaiClient as it manages connections internally.
 |     // No explicit disconnect for RhaiDispatcher as it manages connections internally.
 | ||||||
|     println!("Exited REPL."); |     println!("Exited REPL."); | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
| @@ -223,7 +223,7 @@ async fn main() -> anyhow::Result<()> { | |||||||
|         .with_env_filter( |         .with_env_filter( | ||||||
|             EnvFilter::from_default_env() |             EnvFilter::from_default_env() | ||||||
|                 .add_directive("ui_repl=info".parse()?) |                 .add_directive("ui_repl=info".parse()?) | ||||||
|                 .add_directive("rhai_client=info".parse()?), |                 .add_directive("rhai_dispatcher=info".parse()?), | ||||||
|         ) |         ) | ||||||
|         .init(); |         .init(); | ||||||
| 
 | 
 | ||||||
| @@ -1,11 +1,11 @@ | |||||||
| [package] | [package] | ||||||
| name = "rhai_client" | name = "rhai_dispatcher" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| edition = "2021" | edition = "2021" | ||||||
| 
 | 
 | ||||||
| [[bin]] | [[bin]] | ||||||
| name = "client" | name = "dispatcher" | ||||||
| path = "cmd/client.rs" | path = "cmd/dispatcher.rs" | ||||||
| 
 | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
| clap = { version = "4.4", features = ["derive"] } | clap = { version = "4.4", features = ["derive"] } | ||||||
| @@ -4,7 +4,7 @@ The `rhai-client` crate provides a fluent builder-based interface for submitting | |||||||
| 
 | 
 | ||||||
| ## Features | ## Features | ||||||
| 
 | 
 | ||||||
| -   **Fluent Builder API**: A `RhaiClientBuilder` for easy client configuration and a `PlayRequestBuilder` for constructing and submitting script execution requests. | -   **Fluent Builder API**: A `RhaiDispatcherBuilder` for easy client configuration and a `PlayRequestBuilder` for constructing and submitting script execution requests. | ||||||
| -   **Asynchronous Operations**: Built with `tokio` for non-blocking I/O. | -   **Asynchronous Operations**: Built with `tokio` for non-blocking I/O. | ||||||
| -   **Request-Reply Pattern**: Submits tasks and awaits results on a dedicated reply queue, eliminating the need for polling. | -   **Request-Reply Pattern**: Submits tasks and awaits results on a dedicated reply queue, eliminating the need for polling. | ||||||
| -   **Configurable Timeouts**: Set timeouts for how long the client should wait for a task to complete. | -   **Configurable Timeouts**: Set timeouts for how long the client should wait for a task to complete. | ||||||
| @@ -13,8 +13,8 @@ The `rhai-client` crate provides a fluent builder-based interface for submitting | |||||||
| 
 | 
 | ||||||
| ## Core Components | ## Core Components | ||||||
| 
 | 
 | ||||||
| -   **`RhaiClientBuilder`**: A builder to construct a `RhaiClient`. Requires a `caller_id` and Redis URL. | -   **`RhaiDispatcherBuilder`**: A builder to construct a `RhaiDispatcher`. Requires a `caller_id` and Redis URL. | ||||||
| -   **`RhaiClient`**: The main client for interacting with the task system. It's used to create `PlayRequestBuilder` instances. | -   **`RhaiDispatcher`**: The main client for interacting with the task system. It's used to create `PlayRequestBuilder` instances. | ||||||
| -   **`PlayRequestBuilder`**: A fluent builder for creating and dispatching a script execution request. You can set: | -   **`PlayRequestBuilder`**: A fluent builder for creating and dispatching a script execution request. You can set: | ||||||
|     -   `worker_id`: The ID of the worker queue to send the task to. |     -   `worker_id`: The ID of the worker queue to send the task to. | ||||||
|     -   `script` or `script_path`: The Rhai script to execute. |     -   `script` or `script_path`: The Rhai script to execute. | ||||||
| @@ -24,11 +24,11 @@ The `rhai-client` crate provides a fluent builder-based interface for submitting | |||||||
|     -   `submit()`: Submits the request and returns immediately (fire-and-forget). |     -   `submit()`: Submits the request and returns immediately (fire-and-forget). | ||||||
|     -   `await_response()`: Submits the request and waits for the result or a timeout. |     -   `await_response()`: Submits the request and waits for the result or a timeout. | ||||||
| -   **`RhaiTaskDetails`**: A struct representing the details of a task, including its script, status (`pending`, `processing`, `completed`, `error`), output, and error messages. | -   **`RhaiTaskDetails`**: A struct representing the details of a task, including its script, status (`pending`, `processing`, `completed`, `error`), output, and error messages. | ||||||
| -   **`RhaiClientError`**: An enum for various errors, such as Redis errors, serialization issues, or task timeouts. | -   **`RhaiDispatcherError`**: An enum for various errors, such as Redis errors, serialization issues, or task timeouts. | ||||||
| 
 | 
 | ||||||
| ## How It Works | ## How It Works | ||||||
| 
 | 
 | ||||||
| 1.  A `RhaiClient` is created using the `RhaiClientBuilder`, configured with a `caller_id` and Redis URL. | 1.  A `RhaiDispatcher` is created using the `RhaiDispatcherBuilder`, configured with a `caller_id` and Redis URL. | ||||||
| 2.  A `PlayRequestBuilder` is created from the client. | 2.  A `PlayRequestBuilder` is created from the client. | ||||||
| 3.  The script, `worker_id`, and an optional `timeout` are configured on the builder. | 3.  The script, `worker_id`, and an optional `timeout` are configured on the builder. | ||||||
| 4.  When `await_response()` is called: | 4.  When `await_response()` is called: | ||||||
| @@ -48,7 +48,7 @@ The `rhai-client` crate provides a fluent builder-based interface for submitting | |||||||
| The following example demonstrates how to build a client, submit a script, and wait for the result. | The following example demonstrates how to build a client, submit a script, and wait for the result. | ||||||
| 
 | 
 | ||||||
| ```rust | ```rust | ||||||
| use rhai_client::{RhaiClientBuilder, RhaiClientError}; | use rhai_dispatcher::{RhaiDispatcherBuilder, RhaiDispatcherError}; | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| 
 | 
 | ||||||
| #[tokio::main] | #[tokio::main] | ||||||
| @@ -56,7 +56,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|     env_logger::init(); |     env_logger::init(); | ||||||
| 
 | 
 | ||||||
|     // 1. Build the client |     // 1. Build the client | ||||||
|     let client = RhaiClientBuilder::new() |     let client = RhaiDispatcherBuilder::new() | ||||||
|         .caller_id("my-app-instance-1") |         .caller_id("my-app-instance-1") | ||||||
|         .redis_url("redis://127.0.0.1/") |         .redis_url("redis://127.0.0.1/") | ||||||
|         .build()?; |         .build()?; | ||||||
| @@ -82,7 +82,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|                 log::info!("Output: {}", output); |                 log::info!("Output: {}", output); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         Err(RhaiClientError::Timeout(task_id)) => { |         Err(RhaiDispatcherError::Timeout(task_id)) => { | ||||||
|             log::error!("Task {} timed out.", task_id); |             log::error!("Task {} timed out.", task_id); | ||||||
|         } |         } | ||||||
|         Err(e) => { |         Err(e) => { | ||||||
| @@ -150,7 +150,7 @@ The client provides clear error messages for: | |||||||
| 
 | 
 | ||||||
| ### Dependencies | ### Dependencies | ||||||
| 
 | 
 | ||||||
| - `rhai_client`: Core client library for Redis-based script execution | - `rhai_dispatcher`: Core client library for Redis-based script execution | ||||||
| - `redis`: Redis client for task queue communication | - `redis`: Redis client for task queue communication | ||||||
| - `clap`: Command-line argument parsing | - `clap`: Command-line argument parsing | ||||||
| - `env_logger`: Logging infrastructure | - `env_logger`: Logging infrastructure | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| use clap::Parser; | use clap::Parser; | ||||||
| use rhai_client::{RhaiClient, RhaiClientBuilder}; | use rhai_dispatcher::{RhaiDispatcher, RhaiDispatcherBuilder}; | ||||||
| use log::{error, info}; | use log::{error, info}; | ||||||
| use std::io::{self, Write}; | use std::io::{self, Write}; | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| @@ -9,15 +9,15 @@ use std::time::Duration; | |||||||
| struct Args { | struct Args { | ||||||
|     /// Caller public key (caller ID)
 |     /// Caller public key (caller ID)
 | ||||||
|     #[arg(short = 'c', long = "caller-key", help = "Caller public key (your identity)")] |     #[arg(short = 'c', long = "caller-key", help = "Caller public key (your identity)")] | ||||||
|     caller_public_key: String, |     caller_id: String, | ||||||
| 
 | 
 | ||||||
|     /// Circle public key (context ID)
 |     /// Circle public key (context ID)
 | ||||||
|     #[arg(short = 'k', long = "circle-key", help = "Circle public key (execution context)")] |     #[arg(short = 'k', long = "circle-key", help = "Circle public key (execution context)")] | ||||||
|     circle_public_key: String, |     context_id: String, | ||||||
| 
 | 
 | ||||||
|     /// Worker public key (defaults to circle public key if not provided)
 |     /// Worker public key (defaults to circle public key if not provided)
 | ||||||
|     #[arg(short = 'w', long = "worker-key", help = "Worker public key (defaults to circle key)")] |     #[arg(short = 'w', long = "worker-key", help = "Worker public key (defaults to circle key)")] | ||||||
|     worker_public_key: Option<String>, |     worker_id: String, | ||||||
| 
 | 
 | ||||||
|     /// Redis URL
 |     /// Redis URL
 | ||||||
|     #[arg(short, long, default_value = "redis://localhost:6379", help = "Redis connection URL")] |     #[arg(short, long, default_value = "redis://localhost:6379", help = "Redis connection URL")] | ||||||
| @@ -50,8 +50,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
| 
 | 
 | ||||||
|     // Configure logging based on verbosity level
 |     // Configure logging based on verbosity level
 | ||||||
|     let log_config = match args.verbose { |     let log_config = match args.verbose { | ||||||
|         0 => "warn,rhai_client=info", |         0 => "warn,rhai_dispatcher=info", | ||||||
|         1 => "info,rhai_client=debug", |         1 => "info,rhai_dispatcher=debug", | ||||||
|         2 => "debug", |         2 => "debug", | ||||||
|         _ => "trace", |         _ => "trace", | ||||||
|     }; |     }; | ||||||
| @@ -67,21 +67,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|         env_logger::init(); |         env_logger::init(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Use worker key or default to circle key
 |     info!("🔗 Starting Rhai Dispatcher"); | ||||||
|     let worker_key = args.worker_public_key.unwrap_or_else(|| args.circle_public_key.clone()); |  | ||||||
| 
 |  | ||||||
|     info!("🔗 Starting Rhai Client"); |  | ||||||
|     info!("📋 Configuration:"); |     info!("📋 Configuration:"); | ||||||
|     info!("   Caller Key: {}", args.caller_public_key); |     info!("   Caller ID: {}", args.caller_id); | ||||||
|     info!("   Circle Key: {}", args.circle_public_key); |     info!("   Context ID: {}", args.context_id); | ||||||
|     info!("   Worker Key: {}", worker_key); |     info!("   Worker ID: {}", args.worker_id); | ||||||
|     info!("   Redis URL: {}", args.redis_url); |     info!("   Redis URL: {}", args.redis_url); | ||||||
|     info!("   Timeout: {}s", args.timeout); |     info!("   Timeout: {}s", args.timeout); | ||||||
|     info!(""); |     info!(""); | ||||||
| 
 | 
 | ||||||
|     // Create the Rhai client
 |     // Create the Rhai client
 | ||||||
|     let client = RhaiClientBuilder::new() |     let client = RhaiDispatcherBuilder::new() | ||||||
|         .caller_id(&args.caller_public_key) |         .caller_id(&args.caller_id) | ||||||
|  |         .worker_id(&args.worker_id) | ||||||
|  |         .context_id(&args.context_id) | ||||||
|         .redis_url(&args.redis_url) |         .redis_url(&args.redis_url) | ||||||
|         .build()?; |         .build()?; | ||||||
| 
 | 
 | ||||||
| @@ -91,26 +90,25 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|     if let Some(script_content) = args.script { |     if let Some(script_content) = args.script { | ||||||
|         // Execute inline script
 |         // Execute inline script
 | ||||||
|         info!("📜 Executing inline script"); |         info!("📜 Executing inline script"); | ||||||
|         execute_script(&client, &worker_key, script_content, args.timeout).await?; |         execute_script(&client, script_content, args.timeout).await?; | ||||||
|     } else if let Some(file_path) = args.file { |     } else if let Some(file_path) = args.file { | ||||||
|         // Execute script from file
 |         // Execute script from file
 | ||||||
|         info!("📁 Loading script from file: {}", file_path); |         info!("📁 Loading script from file: {}", file_path); | ||||||
|         let script_content = std::fs::read_to_string(&file_path) |         let script_content = std::fs::read_to_string(&file_path) | ||||||
|             .map_err(|e| format!("Failed to read script file '{}': {}", file_path, e))?; |             .map_err(|e| format!("Failed to read script file '{}': {}", file_path, e))?; | ||||||
|         execute_script(&client, &worker_key, script_content, args.timeout).await?; |         execute_script(&client, script_content, args.timeout).await?; | ||||||
|     } else { |     } else { | ||||||
|         // Interactive mode
 |         // Interactive mode
 | ||||||
|         info!("🎮 Entering interactive mode"); |         info!("🎮 Entering interactive mode"); | ||||||
|         info!("Type Rhai scripts and press Enter to execute. Type 'exit' or 'quit' to close."); |         info!("Type Rhai scripts and press Enter to execute. Type 'exit' or 'quit' to close."); | ||||||
|         run_interactive_mode(&client, &worker_key, args.timeout).await?; |         run_interactive_mode(&client, args.timeout).await?; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async fn execute_script( | async fn execute_script( | ||||||
|     client: &RhaiClient, |     client: &RhaiDispatcher, | ||||||
|     worker_key: &str, |  | ||||||
|     script: String, |     script: String, | ||||||
|     timeout_secs: u64, |     timeout_secs: u64, | ||||||
| ) -> Result<(), Box<dyn std::error::Error>> { | ) -> Result<(), Box<dyn std::error::Error>> { | ||||||
| @@ -120,7 +118,6 @@ async fn execute_script( | |||||||
|     
 |     
 | ||||||
|     match client |     match client | ||||||
|         .new_play_request() |         .new_play_request() | ||||||
|         .recipient_id(worker_key) |  | ||||||
|         .script(&script) |         .script(&script) | ||||||
|         .timeout(timeout) |         .timeout(timeout) | ||||||
|         .await_response() |         .await_response() | ||||||
| @@ -146,8 +143,7 @@ async fn execute_script( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async fn run_interactive_mode( | async fn run_interactive_mode( | ||||||
|     client: &RhaiClient, |     client: &RhaiDispatcher, | ||||||
|     worker_key: &str, |  | ||||||
|     timeout_secs: u64, |     timeout_secs: u64, | ||||||
| ) -> Result<(), Box<dyn std::error::Error>> { | ) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|     let timeout = Duration::from_secs(timeout_secs); |     let timeout = Duration::from_secs(timeout_secs); | ||||||
| @@ -174,7 +170,6 @@ async fn run_interactive_mode( | |||||||
|         
 |         
 | ||||||
|         match client |         match client | ||||||
|             .new_play_request() |             .new_play_request() | ||||||
|             .recipient_id(worker_key) |  | ||||||
|             .script(input) |             .script(input) | ||||||
|             .timeout(timeout) |             .timeout(timeout) | ||||||
|             .await_response() |             .await_response() | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| # Architecture of the `rhai_client` Crate | # Architecture of the `rhai_dispatcher` Crate | ||||||
| 
 | 
 | ||||||
| The `rhai_client` crate provides a Redis-based client library for submitting Rhai scripts to distributed worker services and awaiting their execution results. It implements a request-reply pattern using Redis as the message broker. | The `rhai_dispatcher` crate provides a Redis-based client library for submitting Rhai scripts to distributed worker services and awaiting their execution results. It implements a request-reply pattern using Redis as the message broker. | ||||||
| 
 | 
 | ||||||
| ## Core Architecture | ## Core Architecture | ||||||
| 
 | 
 | ||||||
| @@ -8,7 +8,7 @@ The client follows a builder pattern design with clear separation of concerns: | |||||||
| 
 | 
 | ||||||
| ```mermaid | ```mermaid | ||||||
| graph TD | graph TD | ||||||
|     A[RhaiClientBuilder] --> B[RhaiClient] |     A[RhaiDispatcherBuilder] --> B[RhaiDispatcher] | ||||||
|     B --> C[PlayRequestBuilder] |     B --> C[PlayRequestBuilder] | ||||||
|     C --> D[PlayRequest] |     C --> D[PlayRequest] | ||||||
|     D --> E[Redis Task Queue] |     D --> E[Redis Task Queue] | ||||||
| @@ -35,9 +35,9 @@ graph TD | |||||||
| 
 | 
 | ||||||
| ## Key Components | ## Key Components | ||||||
| 
 | 
 | ||||||
| ### 1. RhaiClientBuilder | ### 1. RhaiDispatcherBuilder | ||||||
| 
 | 
 | ||||||
| A builder pattern implementation for constructing `RhaiClient` instances with proper configuration validation. | A builder pattern implementation for constructing `RhaiDispatcher` instances with proper configuration validation. | ||||||
| 
 | 
 | ||||||
| **Responsibilities:** | **Responsibilities:** | ||||||
| - Configure Redis connection URL | - Configure Redis connection URL | ||||||
| @@ -47,9 +47,9 @@ A builder pattern implementation for constructing `RhaiClient` instances with pr | |||||||
| **Key Methods:** | **Key Methods:** | ||||||
| - `caller_id(id: &str)` - Sets the caller identifier | - `caller_id(id: &str)` - Sets the caller identifier | ||||||
| - `redis_url(url: &str)` - Configures Redis connection | - `redis_url(url: &str)` - Configures Redis connection | ||||||
| - `build()` - Creates the final `RhaiClient` instance | - `build()` - Creates the final `RhaiDispatcher` instance | ||||||
| 
 | 
 | ||||||
| ### 2. RhaiClient | ### 2. RhaiDispatcher | ||||||
| 
 | 
 | ||||||
| The main client interface that manages Redis connections and provides factory methods for creating play requests. | The main client interface that manages Redis connections and provides factory methods for creating play requests. | ||||||
| 
 | 
 | ||||||
| @@ -103,7 +103,7 @@ pub struct RhaiTaskDetails { | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| #### RhaiClientError | #### RhaiDispatcherError | ||||||
| Comprehensive error handling for various failure scenarios: | Comprehensive error handling for various failure scenarios: | ||||||
| - `RedisError` - Redis connection/operation failures | - `RedisError` - Redis connection/operation failures | ||||||
| - `SerializationError` - JSON serialization/deserialization issues | - `SerializationError` - JSON serialization/deserialization issues | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| use log::info; | use log::info; | ||||||
| use rhai_client::{RhaiClientBuilder, RhaiClientError}; | use rhai_dispatcher::{RhaiDispatcherBuilder, RhaiDispatcherError}; | ||||||
| use std::time::{Duration, Instant}; | use std::time::{Duration, Instant}; | ||||||
| 
 | 
 | ||||||
| #[tokio::main] | #[tokio::main] | ||||||
| @@ -9,11 +9,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|         .init(); |         .init(); | ||||||
| 
 | 
 | ||||||
|     // Build the client using the new builder pattern
 |     // Build the client using the new builder pattern
 | ||||||
|     let client = RhaiClientBuilder::new() |     let client = RhaiDispatcherBuilder::new() | ||||||
|         .caller_id("timeout-example-runner") |         .caller_id("timeout-example-runner") | ||||||
|         .redis_url("redis://127.0.0.1/") |         .redis_url("redis://127.0.0.1/") | ||||||
|         .build()?; |         .build()?; | ||||||
|     info!("RhaiClient created."); |     info!("RhaiDispatcher created."); | ||||||
| 
 | 
 | ||||||
|     let script_content = r#" |     let script_content = r#" | ||||||
|         // This script will never be executed by a worker because the recipient does not exist.
 |         // This script will never be executed by a worker because the recipient does not exist.
 | ||||||
| @@ -56,8 +56,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|             info!("Elapsed time: {:?}", elapsed); |             info!("Elapsed time: {:?}", elapsed); | ||||||
| 
 | 
 | ||||||
|             match e { |             match e { | ||||||
|                 RhaiClientError::Timeout(task_id) => { |                 RhaiDispatcherError::Timeout(task_id) => { | ||||||
|                     info!("Timeout Example PASSED: Correctly received RhaiClientError::Timeout for task_id: {}", task_id); |                     info!("Timeout Example PASSED: Correctly received RhaiDispatcherError::Timeout for task_id: {}", task_id); | ||||||
|                     // Ensure the elapsed time is close to the timeout duration
 |                     // Ensure the elapsed time is close to the timeout duration
 | ||||||
|                     // Allow for some buffer for processing
 |                     // Allow for some buffer for processing
 | ||||||
|                     assert!( |                     assert!( | ||||||
| @@ -75,11 +75,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|                 } |                 } | ||||||
|                 other_error => { |                 other_error => { | ||||||
|                     log::error!( |                     log::error!( | ||||||
|                         "Timeout Example FAILED: Expected RhaiClientError::Timeout, but got other error: {:?}", |                         "Timeout Example FAILED: Expected RhaiDispatcherError::Timeout, but got other error: {:?}", | ||||||
|                         other_error |                         other_error | ||||||
|                     ); |                     ); | ||||||
|                     Err(format!( |                     Err(format!( | ||||||
|                         "Expected RhaiClientError::Timeout, got other error: {:?}", |                         "Expected RhaiDispatcherError::Timeout, got other error: {:?}", | ||||||
|                         other_error |                         other_error | ||||||
|                     ) |                     ) | ||||||
|                     .into()) |                     .into()) | ||||||
| @@ -7,13 +7,13 @@ | |||||||
| //! ## Quick Start
 | //! ## Quick Start
 | ||||||
| //!
 | //!
 | ||||||
| //! ```rust
 | //! ```rust
 | ||||||
| //! use rhai_client::{RhaiClientBuilder, RhaiClientError};
 | //! use rhai_dispatcher::{RhaiDispatcherBuilder, RhaiDispatcherError};
 | ||||||
| //! use std::time::Duration;
 | //! use std::time::Duration;
 | ||||||
| //!
 | //!
 | ||||||
| //! #[tokio::main]
 | //! #[tokio::main]
 | ||||||
| //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
 | //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
 | ||||||
| //!     // Build the client
 | //!     // Build the client
 | ||||||
| //!     let client = RhaiClientBuilder::new()
 | //!     let client = RhaiDispatcherBuilder::new()
 | ||||||
| //!         .caller_id("my-app-instance-1")
 | //!         .caller_id("my-app-instance-1")
 | ||||||
| //!         .redis_url("redis://127.0.0.1/")
 | //!         .redis_url("redis://127.0.0.1/")
 | ||||||
| //!         .build()?;
 | //!         .build()?;
 | ||||||
| @@ -76,6 +76,8 @@ pub struct RhaiTaskDetails { | |||||||
|     pub caller_id: String, |     pub caller_id: String, | ||||||
|     #[serde(rename = "contextId")] |     #[serde(rename = "contextId")] | ||||||
|     pub context_id: String, |     pub context_id: String, | ||||||
|  |     #[serde(rename = "workerId")] | ||||||
|  |     pub worker_id: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Comprehensive error type for all possible failures in the Rhai client.
 | /// Comprehensive error type for all possible failures in the Rhai client.
 | ||||||
| @@ -83,7 +85,7 @@ pub struct RhaiTaskDetails { | |||||||
| /// This enum covers all error scenarios that can occur during client operations,
 | /// This enum covers all error scenarios that can occur during client operations,
 | ||||||
| /// from Redis connectivity issues to task execution timeouts.
 | /// from Redis connectivity issues to task execution timeouts.
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum RhaiClientError { | pub enum RhaiDispatcherError { | ||||||
|     /// Redis connection or operation error
 |     /// Redis connection or operation error
 | ||||||
|     RedisError(redis::RedisError), |     RedisError(redis::RedisError), | ||||||
|     /// JSON serialization/deserialization error
 |     /// JSON serialization/deserialization error
 | ||||||
| @@ -96,37 +98,37 @@ pub enum RhaiClientError { | |||||||
|     ContextIdMissing, |     ContextIdMissing, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<redis::RedisError> for RhaiClientError { | impl From<redis::RedisError> for RhaiDispatcherError { | ||||||
|     fn from(err: redis::RedisError) -> Self { |     fn from(err: redis::RedisError) -> Self { | ||||||
|         RhaiClientError::RedisError(err) |         RhaiDispatcherError::RedisError(err) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<serde_json::Error> for RhaiClientError { | impl From<serde_json::Error> for RhaiDispatcherError { | ||||||
|     fn from(err: serde_json::Error) -> Self { |     fn from(err: serde_json::Error) -> Self { | ||||||
|         RhaiClientError::SerializationError(err) |         RhaiDispatcherError::SerializationError(err) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl std::fmt::Display for RhaiClientError { | impl std::fmt::Display for RhaiDispatcherError { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|         match self { |         match self { | ||||||
|             RhaiClientError::RedisError(e) => write!(f, "Redis error: {}", e), |             RhaiDispatcherError::RedisError(e) => write!(f, "Redis error: {}", e), | ||||||
|             RhaiClientError::SerializationError(e) => write!(f, "Serialization error: {}", e), |             RhaiDispatcherError::SerializationError(e) => write!(f, "Serialization error: {}", e), | ||||||
|             RhaiClientError::Timeout(task_id) => { |             RhaiDispatcherError::Timeout(task_id) => { | ||||||
|                 write!(f, "Timeout waiting for task {} to complete", task_id) |                 write!(f, "Timeout waiting for task {} to complete", task_id) | ||||||
|             } |             } | ||||||
|             RhaiClientError::TaskNotFound(task_id) => { |             RhaiDispatcherError::TaskNotFound(task_id) => { | ||||||
|                 write!(f, "Task {} not found after submission", task_id) |                 write!(f, "Task {} not found after submission", task_id) | ||||||
|             } |             } | ||||||
|             RhaiClientError::ContextIdMissing => { |             RhaiDispatcherError::ContextIdMissing => { | ||||||
|                 write!(f, "Context ID is missing") |                 write!(f, "Context ID is missing") | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl std::error::Error for RhaiClientError {} | impl std::error::Error for RhaiDispatcherError {} | ||||||
| 
 | 
 | ||||||
| /// The main client for interacting with the Rhai task execution system.
 | /// The main client for interacting with the Rhai task execution system.
 | ||||||
| ///
 | ///
 | ||||||
| @@ -137,19 +139,21 @@ impl std::error::Error for RhaiClientError {} | |||||||
| /// # Example
 | /// # Example
 | ||||||
| ///
 | ///
 | ||||||
| /// ```rust
 | /// ```rust
 | ||||||
| /// use rhai_client::RhaiClientBuilder;
 | /// use rhai_dispatcher::RhaiDispatcherBuilder;
 | ||||||
| ///
 | ///
 | ||||||
| /// let client = RhaiClientBuilder::new()
 | /// let client = RhaiDispatcherBuilder::new()
 | ||||||
| ///     .caller_id("my-service")
 | ///     .caller_id("my-service")
 | ||||||
| ///     .redis_url("redis://localhost/")
 | ///     .redis_url("redis://localhost/")
 | ||||||
| ///     .build()?;
 | ///     .build()?;
 | ||||||
| /// ```
 | /// ```
 | ||||||
| pub struct RhaiClient { | pub struct RhaiDispatcher { | ||||||
|     redis_client: redis::Client, |     redis_client: redis::Client, | ||||||
|     caller_id: String, |     caller_id: String, | ||||||
|  |     worker_id: String, | ||||||
|  |     context_id: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Builder for constructing `RhaiClient` instances with proper configuration.
 | /// Builder for constructing `RhaiDispatcher` instances with proper configuration.
 | ||||||
| ///
 | ///
 | ||||||
| /// This builder ensures that all required configuration is provided before
 | /// This builder ensures that all required configuration is provided before
 | ||||||
| /// creating a client instance. It validates the configuration and provides
 | /// creating a client instance. It validates the configuration and provides
 | ||||||
| @@ -162,13 +166,15 @@ pub struct RhaiClient { | |||||||
| /// # Optional Configuration
 | /// # Optional Configuration
 | ||||||
| ///
 | ///
 | ||||||
| /// - `redis_url`: Redis connection URL (defaults to "redis://127.0.0.1/")
 | /// - `redis_url`: Redis connection URL (defaults to "redis://127.0.0.1/")
 | ||||||
| pub struct RhaiClientBuilder { | pub struct RhaiDispatcherBuilder { | ||||||
|     redis_url: Option<String>, |     redis_url: Option<String>, | ||||||
|     caller_id: String, |     caller_id: String, | ||||||
|  |     worker_id: String, | ||||||
|  |     context_id: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl RhaiClientBuilder { | impl RhaiDispatcherBuilder { | ||||||
|     /// Creates a new `RhaiClientBuilder` with default settings.
 |     /// Creates a new `RhaiDispatcherBuilder` with default settings.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// The builder starts with no Redis URL (will default to "redis://127.0.0.1/")
 |     /// The builder starts with no Redis URL (will default to "redis://127.0.0.1/")
 | ||||||
|     /// and an empty caller ID (which must be set before building).
 |     /// and an empty caller ID (which must be set before building).
 | ||||||
| @@ -176,6 +182,8 @@ impl RhaiClientBuilder { | |||||||
|         Self { |         Self { | ||||||
|             redis_url: None, |             redis_url: None, | ||||||
|             caller_id: "".to_string(), |             caller_id: "".to_string(), | ||||||
|  |             worker_id: "".to_string(), | ||||||
|  |             context_id: "".to_string(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -192,6 +200,31 @@ impl RhaiClientBuilder { | |||||||
|         self.caller_id = caller_id.to_string(); |         self.caller_id = caller_id.to_string(); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
|  |     /// Sets the circle ID for this client instance.
 | ||||||
|  |     ///
 | ||||||
|  |     /// The circle ID is used to identify which circle's context a task should be executed in.
 | ||||||
|  |     /// This is required at the time the client dispatches a script, but can be set on construction or on script dispatch.
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Arguments
 | ||||||
|  |     ///
 | ||||||
|  |     /// * `context_id` - A unique identifier for this client instance
 | ||||||
|  |     pub fn context_id(mut self, context_id: &str) -> Self { | ||||||
|  |         self.context_id = context_id.to_string(); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sets the worker ID for this client instance.
 | ||||||
|  |     ///
 | ||||||
|  |     /// The worker ID is used to identify which worker a task should be executed on.
 | ||||||
|  |     /// This is required at the time the client dispatches a script, but can be set on construction or on script dispatch.
 | ||||||
|  |     ///
 | ||||||
|  |     /// # Arguments
 | ||||||
|  |     ///
 | ||||||
|  |     /// * `worker_id` - A unique identifier for this client instance
 | ||||||
|  |     pub fn worker_id(mut self, worker_id: &str) -> Self { | ||||||
|  |         self.worker_id = worker_id.to_string(); | ||||||
|  |         self | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /// Sets the Redis connection URL.
 |     /// Sets the Redis connection URL.
 | ||||||
|     ///
 |     ///
 | ||||||
| @@ -205,7 +238,7 @@ impl RhaiClientBuilder { | |||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Builds the final `RhaiClient` instance.
 |     /// Builds the final `RhaiDispatcher` instance.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// This method validates the configuration and creates the Redis client.
 |     /// This method validates the configuration and creates the Redis client.
 | ||||||
|     /// It will return an error if the caller ID is empty or if the Redis
 |     /// It will return an error if the caller ID is empty or if the Redis
 | ||||||
| @@ -213,22 +246,18 @@ impl RhaiClientBuilder { | |||||||
|     ///
 |     ///
 | ||||||
|     /// # Returns
 |     /// # Returns
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// * `Ok(RhaiClient)` - Successfully configured client
 |     /// * `Ok(RhaiDispatcher)` - Successfully configured client
 | ||||||
|     /// * `Err(RhaiClientError)` - Configuration or connection error
 |     /// * `Err(RhaiDispatcherError)` - Configuration or connection error
 | ||||||
|     pub fn build(self) -> Result<RhaiClient, RhaiClientError> { |     pub fn build(self) -> Result<RhaiDispatcher, RhaiDispatcherError> { | ||||||
|         let url = self |         let url = self | ||||||
|             .redis_url |             .redis_url | ||||||
|             .unwrap_or_else(|| "redis://127.0.0.1/".to_string()); |             .unwrap_or_else(|| "redis://127.0.0.1/".to_string()); | ||||||
|         let client = redis::Client::open(url)?; |         let client = redis::Client::open(url)?; | ||||||
|         if self.caller_id.is_empty() { |         Ok(RhaiDispatcher { | ||||||
|             return Err(RhaiClientError::RedisError(redis::RedisError::from(( |  | ||||||
|                 redis::ErrorKind::InvalidClientConfig, |  | ||||||
|                 "Caller ID is empty", |  | ||||||
|             )))); |  | ||||||
|         } |  | ||||||
|         Ok(RhaiClient { |  | ||||||
|             redis_client: client, |             redis_client: client, | ||||||
|             caller_id: self.caller_id, |             caller_id: self.caller_id, | ||||||
|  |             worker_id: self.worker_id, | ||||||
|  |             context_id: self.context_id, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -265,21 +294,23 @@ pub struct PlayRequest { | |||||||
| ///     .await?;
 | ///     .await?;
 | ||||||
| /// ```
 | /// ```
 | ||||||
| pub struct PlayRequestBuilder<'a> { | pub struct PlayRequestBuilder<'a> { | ||||||
|     client: &'a RhaiClient, |     client: &'a RhaiDispatcher, | ||||||
|     request_id: String, |     request_id: String, | ||||||
|     worker_id: String, |     worker_id: String, | ||||||
|     context_id: String, |     context_id: String, | ||||||
|  |     caller_id: String, | ||||||
|     script: String, |     script: String, | ||||||
|     timeout: Duration, |     timeout: Duration, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> PlayRequestBuilder<'a> { | impl<'a> PlayRequestBuilder<'a> { | ||||||
|     pub fn new(client: &'a RhaiClient) -> Self { |     pub fn new(client: &'a RhaiDispatcher) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             client, |             client, | ||||||
|             request_id: "".to_string(), |             request_id: "".to_string(), | ||||||
|             worker_id: "".to_string(), |             worker_id: client.worker_id.clone(), | ||||||
|             context_id: "".to_string(), |             context_id: client.context_id.clone(), | ||||||
|  |             caller_id: client.caller_id.clone(), | ||||||
|             script: "".to_string(), |             script: "".to_string(), | ||||||
|             timeout: Duration::from_secs(10), |             timeout: Duration::from_secs(10), | ||||||
|         } |         } | ||||||
| @@ -315,7 +346,7 @@ impl<'a> PlayRequestBuilder<'a> { | |||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn build(self) -> Result<PlayRequest, RhaiClientError> { |     pub fn build(self) -> Result<PlayRequest, RhaiDispatcherError> { | ||||||
|         let request_id = if self.request_id.is_empty() { |         let request_id = if self.request_id.is_empty() { | ||||||
|             // Generate a UUID for the request_id
 |             // Generate a UUID for the request_id
 | ||||||
|             Uuid::new_v4().to_string() |             Uuid::new_v4().to_string() | ||||||
| @@ -324,7 +355,11 @@ impl<'a> PlayRequestBuilder<'a> { | |||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         if self.context_id.is_empty() { |         if self.context_id.is_empty() { | ||||||
|             return Err(RhaiClientError::ContextIdMissing); |             return Err(RhaiDispatcherError::ContextIdMissing); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if self.caller_id.is_empty() { | ||||||
|  |             return Err(RhaiDispatcherError::ContextIdMissing); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let play_request = PlayRequest { |         let play_request = PlayRequest { | ||||||
| @@ -337,7 +372,7 @@ impl<'a> PlayRequestBuilder<'a> { | |||||||
|         Ok(play_request) |         Ok(play_request) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn submit(self) -> Result<(), RhaiClientError> { |     pub async fn submit(self) -> Result<(), RhaiDispatcherError> { | ||||||
|         // Build the request and submit using self.client
 |         // Build the request and submit using self.client
 | ||||||
|         println!( |         println!( | ||||||
|             "Submitting request {} with timeout {:?}", |             "Submitting request {} with timeout {:?}", | ||||||
| @@ -347,7 +382,7 @@ impl<'a> PlayRequestBuilder<'a> { | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn await_response(self) -> Result<RhaiTaskDetails, RhaiClientError> { |     pub async fn await_response(self) -> Result<RhaiTaskDetails, RhaiDispatcherError> { | ||||||
|         // Build the request and submit using self.client
 |         // Build the request and submit using self.client
 | ||||||
|         println!( |         println!( | ||||||
|             "Awaiting response for request {} with timeout {:?}", |             "Awaiting response for request {} with timeout {:?}", | ||||||
| @@ -361,7 +396,7 @@ impl<'a> PlayRequestBuilder<'a> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl RhaiClient { | impl RhaiDispatcher { | ||||||
|     pub fn new_play_request(&self) -> PlayRequestBuilder { |     pub fn new_play_request(&self) -> PlayRequestBuilder { | ||||||
|         PlayRequestBuilder::new(self) |         PlayRequestBuilder::new(self) | ||||||
|     } |     } | ||||||
| @@ -371,7 +406,7 @@ impl RhaiClient { | |||||||
|         &self, |         &self, | ||||||
|         conn: &mut redis::aio::MultiplexedConnection, |         conn: &mut redis::aio::MultiplexedConnection, | ||||||
|         play_request: &PlayRequest, |         play_request: &PlayRequest, | ||||||
|     ) -> Result<(), RhaiClientError> { |     ) -> Result<(), RhaiDispatcherError> { | ||||||
|         let now = Utc::now(); |         let now = Utc::now(); | ||||||
| 
 | 
 | ||||||
|         let task_key = format!("{}{}", NAMESPACE_PREFIX, play_request.id); |         let task_key = format!("{}{}", NAMESPACE_PREFIX, play_request.id); | ||||||
| @@ -422,7 +457,7 @@ impl RhaiClient { | |||||||
|         task_key: &String, |         task_key: &String, | ||||||
|         reply_queue_key: &String, |         reply_queue_key: &String, | ||||||
|         timeout: Duration, |         timeout: Duration, | ||||||
|     ) -> Result<RhaiTaskDetails, RhaiClientError> { |     ) -> Result<RhaiTaskDetails, RhaiDispatcherError> { | ||||||
|         // BLPOP on the reply queue
 |         // BLPOP on the reply queue
 | ||||||
|         // The timeout for BLPOP is in seconds (integer)
 |         // The timeout for BLPOP is in seconds (integer)
 | ||||||
|         let blpop_timeout_secs = timeout.as_secs().max(1); // Ensure at least 1 second for BLPOP timeout
 |         let blpop_timeout_secs = timeout.as_secs().max(1); // Ensure at least 1 second for BLPOP timeout
 | ||||||
| @@ -458,7 +493,7 @@ impl RhaiClient { | |||||||
|                         ); |                         ); | ||||||
|                         // Optionally, delete the reply queue
 |                         // Optionally, delete the reply queue
 | ||||||
|                         let _: redis::RedisResult<i32> = conn.del(&reply_queue_key).await; |                         let _: redis::RedisResult<i32> = conn.del(&reply_queue_key).await; | ||||||
|                         Err(RhaiClientError::SerializationError(e)) |                         Err(RhaiDispatcherError::SerializationError(e)) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -470,7 +505,7 @@ impl RhaiClient { | |||||||
|                 ); |                 ); | ||||||
|                 // Optionally, delete the reply queue
 |                 // Optionally, delete the reply queue
 | ||||||
|                 let _: redis::RedisResult<i32> = conn.del(&reply_queue_key).await; |                 let _: redis::RedisResult<i32> = conn.del(&reply_queue_key).await; | ||||||
|                 Err(RhaiClientError::Timeout(task_key.clone())) |                 Err(RhaiDispatcherError::Timeout(task_key.clone())) | ||||||
|             } |             } | ||||||
|             Err(e) => { |             Err(e) => { | ||||||
|                 // Redis error
 |                 // Redis error
 | ||||||
| @@ -480,7 +515,7 @@ impl RhaiClient { | |||||||
|                 ); |                 ); | ||||||
|                 // Optionally, delete the reply queue
 |                 // Optionally, delete the reply queue
 | ||||||
|                 let _: redis::RedisResult<i32> = conn.del(&reply_queue_key).await; |                 let _: redis::RedisResult<i32> = conn.del(&reply_queue_key).await; | ||||||
|                 Err(RhaiClientError::RedisError(e)) |                 Err(RhaiDispatcherError::RedisError(e)) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -489,7 +524,7 @@ impl RhaiClient { | |||||||
|     pub async fn submit_play_request( |     pub async fn submit_play_request( | ||||||
|         &self, |         &self, | ||||||
|         play_request: &PlayRequest, |         play_request: &PlayRequest, | ||||||
|     ) -> Result<(), RhaiClientError> { |     ) -> Result<(), RhaiDispatcherError> { | ||||||
|         let mut conn = self.redis_client.get_multiplexed_async_connection().await?; |         let mut conn = self.redis_client.get_multiplexed_async_connection().await?; | ||||||
| 
 | 
 | ||||||
|         self.submit_play_request_using_connection( |         self.submit_play_request_using_connection( | ||||||
| @@ -504,7 +539,7 @@ impl RhaiClient { | |||||||
|     pub async fn submit_play_request_and_await_result( |     pub async fn submit_play_request_and_await_result( | ||||||
|         &self, |         &self, | ||||||
|         play_request: &PlayRequest, |         play_request: &PlayRequest, | ||||||
|     ) -> Result<RhaiTaskDetails, RhaiClientError> { |     ) -> Result<RhaiTaskDetails, RhaiDispatcherError> { | ||||||
|         let mut conn = self.redis_client.get_multiplexed_async_connection().await?; |         let mut conn = self.redis_client.get_multiplexed_async_connection().await?; | ||||||
| 
 | 
 | ||||||
|         let reply_queue_key = format!("{}:reply:{}", NAMESPACE_PREFIX, play_request.id); // Derived from the passed task_id
 |         let reply_queue_key = format!("{}:reply:{}", NAMESPACE_PREFIX, play_request.id); // Derived from the passed task_id
 | ||||||
| @@ -535,7 +570,7 @@ impl RhaiClient { | |||||||
|     pub async fn get_task_status( |     pub async fn get_task_status( | ||||||
|         &self, |         &self, | ||||||
|         task_id: &str, |         task_id: &str, | ||||||
|     ) -> Result<Option<RhaiTaskDetails>, RhaiClientError> { |     ) -> Result<Option<RhaiTaskDetails>, RhaiDispatcherError> { | ||||||
|         let mut conn = self.redis_client.get_multiplexed_async_connection().await?; |         let mut conn = self.redis_client.get_multiplexed_async_connection().await?; | ||||||
|         let task_key = format!("{}{}", NAMESPACE_PREFIX, task_id); |         let task_key = format!("{}{}", NAMESPACE_PREFIX, task_id); | ||||||
| 
 | 
 | ||||||
| @@ -573,6 +608,7 @@ impl RhaiClient { | |||||||
|                                         Utc::now() |                                         Utc::now() | ||||||
|                                     }), |                                     }), | ||||||
|                     caller_id: map.get("callerId").cloned().expect("callerId field missing from Redis hash"), |                     caller_id: map.get("callerId").cloned().expect("callerId field missing from Redis hash"), | ||||||
|  |                     worker_id: map.get("workerId").cloned().expect("workerId field missing from Redis hash"), | ||||||
|                     context_id: map.get("contextId").cloned().expect("contextId field missing from Redis hash"), |                     context_id: map.get("contextId").cloned().expect("contextId field missing from Redis hash"), | ||||||
|                 }; |                 }; | ||||||
|                 // It's important to also check if the 'taskId' field exists in the map and matches the input task_id
 |                 // It's important to also check if the 'taskId' field exists in the map and matches the input task_id
 | ||||||
							
								
								
									
										
											BIN
										
									
								
								src/repl/.DS_Store
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/repl/.DS_Store
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user