wip
This commit is contained in:
4
interfaces/websocket/client/Cargo.lock
generated
4
interfaces/websocket/client/Cargo.lock
generated
@@ -595,7 +595,7 @@ dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"redis",
|
||||
"rhai_dispatcher",
|
||||
"rhai_supervisor",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
@@ -1765,7 +1765,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "rhai_dispatcher"
|
||||
name = "rhai_supervisor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
|
4
interfaces/websocket/server/Cargo.lock
generated
4
interfaces/websocket/server/Cargo.lock
generated
@@ -584,7 +584,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"rand 0.8.5",
|
||||
"redis",
|
||||
"rhai_dispatcher",
|
||||
"rhai_supervisor",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"secp256k1",
|
||||
@@ -1769,7 +1769,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "rhai_dispatcher"
|
||||
name = "rhai_supervisor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
|
@@ -44,7 +44,7 @@ redis = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
hero_dispatcher = { path = "../../../core/dispatcher" }
|
||||
hero_supervisor = { path = "../../../core/supervisor" }
|
||||
hero_job = { path = "../../../core/job" }
|
||||
thiserror = { workspace = true }
|
||||
heromodels = { path = "../../../../db/heromodels" }
|
||||
|
@@ -4,9 +4,14 @@ An OpenRPC WebSocket Server to interface with the [cores](../../core) of authori
|
||||
|
||||
- [OpenRPC Specification](openrpc.json) defines the API.
|
||||
- There are RPC Operations specified to authorize a websocket connection.
|
||||
- Authorized clients can execute Rhai scripts on the server.
|
||||
- Authorized clients can manage jobs.
|
||||
- The server uses the [supervisor] to dispatch [jobs] to the [workers].
|
||||
|
||||
## Circles
|
||||
|
||||
Circles are contexts which a hero can act in. Each circle has a unique public key and a set of members.
|
||||
The server offers a separate path for each circle.
|
||||
|
||||
## Authentication
|
||||
|
||||
The server provides a robust authentication mechanism to ensure that only authorized clients can execute scripts. The entire flow is handled over the WebSocket connection using two dedicated JSON-RPC methods:
|
||||
|
@@ -1,7 +1,5 @@
|
||||
use hero_websocket_server::{ServerBuilder, TlsConfigError};
|
||||
use hero_websocket_server::{ServerBuilder, ServerConfig};
|
||||
use clap::Parser;
|
||||
use dotenv::dotenv;
|
||||
use log::info;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
@@ -39,14 +37,62 @@ struct Args {
|
||||
#[clap(long, help = "Enable webhook handling")]
|
||||
webhooks: bool,
|
||||
|
||||
#[clap(long, value_parser, help = "Worker ID for the server")]
|
||||
worker_id: String,
|
||||
#[clap(short, long, value_parser, help = "Path to configuration file")]
|
||||
config: Option<String>,
|
||||
|
||||
#[clap(long, help = "Generate a sample configuration file")]
|
||||
generate_config: bool,
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
// Handle config file generation
|
||||
if args.generate_config {
|
||||
let sample_config = ServerConfig::create_sample();
|
||||
let config_path = "config.json";
|
||||
match sample_config.to_file(config_path) {
|
||||
Ok(_) => {
|
||||
println!("✅ Sample configuration file generated: {}", config_path);
|
||||
println!("📝 Edit the file to customize your server configuration.");
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("❌ Failed to generate config file: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load configuration from file if provided, otherwise use CLI args
|
||||
let config = if let Some(config_path) = &args.config {
|
||||
match ServerConfig::from_file(config_path) {
|
||||
Ok(config) => {
|
||||
println!("📄 Loaded configuration from: {}", config_path);
|
||||
config
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("❌ Failed to load config file {}: {}", config_path, e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create config from CLI arguments
|
||||
ServerConfig {
|
||||
host: args.host.clone(),
|
||||
port: args.port,
|
||||
redis_url: args.redis_url.clone(),
|
||||
auth: args.auth,
|
||||
tls: args.tls,
|
||||
cert: args.cert.clone(),
|
||||
key: args.key.clone(),
|
||||
tls_port: args.tls_port,
|
||||
webhooks: args.webhooks,
|
||||
circles: std::collections::HashMap::new(), // Empty circles when using CLI
|
||||
}
|
||||
};
|
||||
|
||||
// Configure logging based on verbosity level
|
||||
let log_config = match args.verbose {
|
||||
0 => {
|
||||
@@ -78,39 +124,14 @@ async fn main() -> std::io::Result<()> {
|
||||
env_logger::init();
|
||||
}
|
||||
|
||||
// Validate TLS configuration
|
||||
if args.tls && (args.cert.is_none() || args.key.is_none()) {
|
||||
eprintln!("Error: TLS is enabled but certificate or key path is missing");
|
||||
eprintln!("Use --cert and --key to specify certificate and key files");
|
||||
// Validate configuration
|
||||
if let Err(e) = config.validate() {
|
||||
eprintln!("❌ Configuration validation failed: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let mut builder = ServerBuilder::new()
|
||||
.host(args.host.clone())
|
||||
.port(args.port)
|
||||
.redis_url(args.redis_url.clone())
|
||||
.worker_id(args.worker_id.clone());
|
||||
|
||||
if args.auth {
|
||||
builder = builder.with_auth();
|
||||
}
|
||||
|
||||
if args.tls {
|
||||
if let (Some(cert), Some(key)) = (args.cert.clone(), args.key.clone()) {
|
||||
builder = builder.with_tls(cert, key);
|
||||
} else {
|
||||
eprintln!("Error: TLS is enabled but --cert or --key is missing.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(tls_port) = args.tls_port {
|
||||
builder = builder.with_tls_port(tls_port);
|
||||
}
|
||||
|
||||
if args.webhooks {
|
||||
builder = builder.with_webhooks();
|
||||
}
|
||||
// Build server from configuration
|
||||
let builder = ServerBuilder::new().from_config(config.clone());
|
||||
|
||||
let server = match builder.build() {
|
||||
Ok(server) => server,
|
||||
@@ -122,27 +143,36 @@ async fn main() -> std::io::Result<()> {
|
||||
|
||||
println!("🚀 Starting Circles WebSocket Server");
|
||||
println!("📋 Configuration:");
|
||||
println!(" Host: {}", args.host);
|
||||
println!(" Port: {}", args.port);
|
||||
if let Some(tls_port) = args.tls_port {
|
||||
println!(" Host: {}", config.host);
|
||||
println!(" Port: {}", config.port);
|
||||
println!(" Redis URL: {}", config.redis_url);
|
||||
if let Some(tls_port) = config.tls_port {
|
||||
println!(" TLS Port: {}", tls_port);
|
||||
}
|
||||
println!(" Authentication: {}", if args.auth { "ENABLED" } else { "DISABLED" });
|
||||
println!(" TLS/WSS: {}", if args.tls { "ENABLED" } else { "DISABLED" });
|
||||
println!(" Webhooks: {}", if args.webhooks { "ENABLED" } else { "DISABLED" });
|
||||
println!(" Authentication: {}", if config.auth { "ENABLED" } else { "DISABLED" });
|
||||
println!(" TLS/WSS: {}", if config.tls { "ENABLED" } else { "DISABLED" });
|
||||
println!(" Webhooks: {}", if config.webhooks { "ENABLED" } else { "DISABLED" });
|
||||
println!(" Circles configured: {}", config.circles.len());
|
||||
|
||||
if args.tls {
|
||||
if let (Some(cert), Some(key)) = (&args.cert, &args.key) {
|
||||
if config.tls {
|
||||
if let (Some(cert), Some(key)) = (&config.cert, &config.key) {
|
||||
println!(" Certificate: {}", cert);
|
||||
println!(" Private Key: {}", key);
|
||||
}
|
||||
}
|
||||
|
||||
if args.webhooks {
|
||||
if config.webhooks {
|
||||
println!(" Webhook secrets loaded from environment variables:");
|
||||
println!(" - STRIPE_WEBHOOK_SECRET");
|
||||
println!(" - IDENFY_WEBHOOK_SECRET");
|
||||
}
|
||||
|
||||
if config.auth && !config.circles.is_empty() {
|
||||
println!(" Configured circles:");
|
||||
for (circle_name, members) in &config.circles {
|
||||
println!(" - {}: {} members", circle_name, members.len());
|
||||
}
|
||||
}
|
||||
println!();
|
||||
|
||||
let (server_task, _server_handle) = server.spawn_circle_server()?;
|
||||
|
@@ -90,7 +90,7 @@ sequenceDiagram
|
||||
participant HS as HttpServer
|
||||
participant WH as Webhook Handler
|
||||
participant WV as Webhook Verifier
|
||||
participant RC as RhaiDispatcher
|
||||
participant RC as RhaiSupervisor
|
||||
participant Redis as Redis
|
||||
|
||||
WS->>+HS: POST /webhooks/{provider}/{circle_pk}
|
||||
@@ -102,7 +102,7 @@ sequenceDiagram
|
||||
|
||||
alt Signature Valid
|
||||
WH->>WH: Parse webhook payload (heromodels types)
|
||||
WH->>+RC: Create RhaiDispatcher with caller_id
|
||||
WH->>+RC: Create RhaiSupervisor with caller_id
|
||||
RC->>+Redis: Execute webhook script
|
||||
Redis-->>-RC: Script result
|
||||
RC-->>-WH: Execution result
|
||||
@@ -128,6 +128,6 @@ sequenceDiagram
|
||||
| **Connection Type** | Persistent, bidirectional | HTTP request/response |
|
||||
| **Authentication** | secp256k1 signature-based | HMAC signature verification |
|
||||
| **State Management** | Stateful sessions via CircleWs actor | Stateless HTTP requests |
|
||||
| **Script Execution** | Direct via authenticated session | Via RhaiDispatcher with provider caller_id |
|
||||
| **Script Execution** | Direct via authenticated session | Via RhaiSupervisor with provider caller_id |
|
||||
| **Use Case** | Interactive client applications | External service notifications |
|
||||
| **Data Types** | JSON-RPC messages | Provider-specific webhook payloads (heromodels) |
|
@@ -19,8 +19,8 @@ graph TB
|
||||
E[Webhook Handler]
|
||||
F[Stripe Verifier]
|
||||
G[iDenfy Verifier]
|
||||
H[Script Dispatcher]
|
||||
I[RhaiDispatcherBuilder]
|
||||
H[Script Supervisor]
|
||||
I[RhaiSupervisorBuilder]
|
||||
end
|
||||
|
||||
subgraph "Configuration"
|
||||
@@ -92,8 +92,8 @@ sequenceDiagram
|
||||
participant WS as Webhook Service
|
||||
participant CS as Circle Server
|
||||
participant WV as Webhook Verifier
|
||||
participant SD as Script Dispatcher
|
||||
participant RC as RhaiDispatcher
|
||||
participant SD as Script Supervisor
|
||||
participant RC as RhaiSupervisor
|
||||
participant RW as Rhai Worker
|
||||
|
||||
WS->>CS: POST /webhooks/stripe/{circle_pk}
|
||||
@@ -113,7 +113,7 @@ sequenceDiagram
|
||||
|
||||
alt Verification Success
|
||||
CS->>SD: Dispatch appropriate script
|
||||
SD->>RC: Create RhaiDispatcherBuilder
|
||||
SD->>RC: Create RhaiSupervisorBuilder
|
||||
RC->>RC: Set caller_id="stripe" or "idenfy"
|
||||
RC->>RC: Set recipient_id=circle_pk
|
||||
RC->>RC: Set script="stripe_webhook_received" or "idenfy_webhook_received"
|
||||
@@ -248,8 +248,8 @@ heromodels/src/models/
|
||||
### Key Architectural Changes
|
||||
- **Type Organization**: Webhook payload types moved to `heromodels` library for reusability
|
||||
- **Modular Handlers**: Separate handler files for each webhook provider
|
||||
- **Simplified Architecture**: Removed unnecessary dispatcher complexity
|
||||
- **Direct Script Execution**: Handlers directly use `RhaiDispatcher` for script execution
|
||||
- **Simplified Architecture**: Removed unnecessary supervisor complexity
|
||||
- **Direct Script Execution**: Handlers directly use `RhaiSupervisor` for script execution
|
||||
|
||||
### Modified Files
|
||||
- `src/lib.rs` - Add webhook routes and module imports
|
||||
|
@@ -1,5 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::{Server, TlsConfigError};
|
||||
use crate::{Server, TlsConfigError, ServerConfig};
|
||||
|
||||
/// ServerBuilder for constructing Server instances with a fluent API
|
||||
pub struct ServerBuilder {
|
||||
@@ -12,7 +12,7 @@ pub struct ServerBuilder {
|
||||
tls_port: Option<u16>,
|
||||
enable_auth: bool,
|
||||
enable_webhooks: bool,
|
||||
circle_worker_id: String,
|
||||
|
||||
circles: HashMap<String, Vec<String>>,
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ impl ServerBuilder {
|
||||
tls_port: None,
|
||||
enable_auth: false,
|
||||
enable_webhooks: false,
|
||||
circle_worker_id: "default".to_string(),
|
||||
|
||||
circles: HashMap::new(),
|
||||
}
|
||||
}
|
||||
@@ -48,10 +48,7 @@ impl ServerBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn worker_id(mut self, worker_id: impl Into<String>) -> Self {
|
||||
self.circle_worker_id = worker_id.into();
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
pub fn with_tls(mut self, cert_path: String, key_path: String) -> Self {
|
||||
self.enable_tls = true;
|
||||
@@ -79,6 +76,21 @@ impl ServerBuilder {
|
||||
self.circles = circles;
|
||||
self
|
||||
}
|
||||
|
||||
/// Load configuration from a ServerConfig instance
|
||||
pub fn from_config(mut self, config: ServerConfig) -> Self {
|
||||
self.host = config.host;
|
||||
self.port = config.port;
|
||||
self.redis_url = config.redis_url;
|
||||
self.enable_auth = config.auth;
|
||||
self.enable_tls = config.tls;
|
||||
self.cert_path = config.cert;
|
||||
self.key_path = config.key;
|
||||
self.tls_port = config.tls_port;
|
||||
self.enable_webhooks = config.webhooks;
|
||||
self.circles = config.circles;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<Server, TlsConfigError> {
|
||||
Ok(Server {
|
||||
@@ -91,13 +103,13 @@ impl ServerBuilder {
|
||||
tls_port: self.tls_port,
|
||||
enable_auth: self.enable_auth,
|
||||
enable_webhooks: self.enable_webhooks,
|
||||
circle_worker_id: self.circle_worker_id,
|
||||
|
||||
circle_name: "default".to_string(),
|
||||
circle_public_key: "default".to_string(),
|
||||
circles: self.circles,
|
||||
nonce_store: HashMap::new(),
|
||||
authenticated_pubkey: None,
|
||||
dispatcher: None,
|
||||
supervisor: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use crate::Server;
|
||||
use actix::prelude::*;
|
||||
use actix_web_actors::ws;
|
||||
use hero_dispatcher::{Dispatcher, ScriptType};
|
||||
use hero_supervisor::{Supervisor, ScriptType};
|
||||
use serde_json::{json, Value};
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -82,7 +82,7 @@ impl Server {
|
||||
}
|
||||
};
|
||||
|
||||
let dispatcher = match self.dispatcher.clone() {
|
||||
let supervisor = match self.supervisor.clone() {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err_resp = JsonRpcResponse {
|
||||
@@ -90,7 +90,7 @@ impl Server {
|
||||
result: None,
|
||||
error: Some(JsonRpcError {
|
||||
code: -32603,
|
||||
message: "Internal error: dispatcher not available".to_string(),
|
||||
message: "Internal error: supervisor not available".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
id: client_rpc_id,
|
||||
@@ -102,7 +102,7 @@ impl Server {
|
||||
|
||||
let client_rpc_id_clone = client_rpc_id.clone();
|
||||
let fut = async move {
|
||||
dispatcher.start_job(&job_id).await
|
||||
supervisor.start_job(&job_id).await
|
||||
};
|
||||
|
||||
ctx.spawn(
|
||||
@@ -190,7 +190,7 @@ impl Server {
|
||||
}
|
||||
};
|
||||
|
||||
let dispatcher = match self.dispatcher.clone() {
|
||||
let supervisor = match self.supervisor.clone() {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err_resp = JsonRpcResponse {
|
||||
@@ -198,7 +198,7 @@ impl Server {
|
||||
result: None,
|
||||
error: Some(JsonRpcError {
|
||||
code: -32603,
|
||||
message: "Internal error: dispatcher not available".to_string(),
|
||||
message: "Internal error: supervisor not available".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
id: client_rpc_id,
|
||||
@@ -210,7 +210,7 @@ impl Server {
|
||||
|
||||
let client_rpc_id_clone = client_rpc_id.clone();
|
||||
let fut = async move {
|
||||
dispatcher.get_job_status(&job_id).await
|
||||
supervisor.get_job_status(&job_id).await
|
||||
};
|
||||
|
||||
ctx.spawn(
|
||||
@@ -279,7 +279,7 @@ impl Server {
|
||||
return;
|
||||
}
|
||||
|
||||
let dispatcher = match self.dispatcher.clone() {
|
||||
let supervisor = match self.supervisor.clone() {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err_resp = JsonRpcResponse {
|
||||
@@ -287,7 +287,7 @@ impl Server {
|
||||
result: None,
|
||||
error: Some(JsonRpcError {
|
||||
code: -32603,
|
||||
message: "Internal error: dispatcher not available".to_string(),
|
||||
message: "Internal error: supervisor not available".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
id: client_rpc_id,
|
||||
@@ -299,7 +299,7 @@ impl Server {
|
||||
|
||||
let client_rpc_id_clone = client_rpc_id.clone();
|
||||
let fut = async move {
|
||||
dispatcher.list_jobs().await
|
||||
supervisor.list_jobs().await
|
||||
};
|
||||
|
||||
ctx.spawn(
|
||||
@@ -403,7 +403,7 @@ impl Server {
|
||||
}
|
||||
};
|
||||
|
||||
let dispatcher = match self.dispatcher.clone() {
|
||||
let supervisor = match self.supervisor.clone() {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err_resp = JsonRpcResponse {
|
||||
@@ -411,7 +411,7 @@ impl Server {
|
||||
result: None,
|
||||
error: Some(JsonRpcError {
|
||||
code: -32603,
|
||||
message: "Internal error: dispatcher not available".to_string(),
|
||||
message: "Internal error: supervisor not available".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
id: client_rpc_id,
|
||||
@@ -423,7 +423,7 @@ impl Server {
|
||||
|
||||
let client_rpc_id_clone = client_rpc_id.clone();
|
||||
let fut = async move {
|
||||
dispatcher
|
||||
supervisor
|
||||
.new_job()
|
||||
.context_id(&circle_pk)
|
||||
.script_type(ScriptType::RhaiSAL)
|
||||
@@ -518,7 +518,7 @@ impl Server {
|
||||
}
|
||||
};
|
||||
|
||||
let dispatcher = match self.dispatcher.clone() {
|
||||
let supervisor = match self.supervisor.clone() {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err_resp = JsonRpcResponse {
|
||||
@@ -526,7 +526,7 @@ impl Server {
|
||||
result: None,
|
||||
error: Some(JsonRpcError {
|
||||
code: -32603,
|
||||
message: "Internal error: dispatcher not available".to_string(),
|
||||
message: "Internal error: supervisor not available".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
id: client_rpc_id,
|
||||
@@ -538,7 +538,7 @@ impl Server {
|
||||
|
||||
let client_rpc_id_clone = client_rpc_id.clone();
|
||||
let fut = async move {
|
||||
dispatcher.get_job_output(&job_id).await
|
||||
supervisor.get_job_output(&job_id).await
|
||||
};
|
||||
|
||||
ctx.spawn(
|
||||
@@ -625,7 +625,7 @@ impl Server {
|
||||
}
|
||||
};
|
||||
|
||||
let dispatcher = match self.dispatcher.clone() {
|
||||
let supervisor = match self.supervisor.clone() {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err_resp = JsonRpcResponse {
|
||||
@@ -633,7 +633,7 @@ impl Server {
|
||||
result: None,
|
||||
error: Some(JsonRpcError {
|
||||
code: -32603,
|
||||
message: "Internal error: dispatcher not available".to_string(),
|
||||
message: "Internal error: supervisor not available".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
id: client_rpc_id,
|
||||
@@ -645,7 +645,7 @@ impl Server {
|
||||
|
||||
let client_rpc_id_clone = client_rpc_id.clone();
|
||||
let fut = async move {
|
||||
dispatcher.get_job_logs(&job_id).await
|
||||
supervisor.get_job_logs(&job_id).await
|
||||
};
|
||||
|
||||
ctx.spawn(
|
||||
@@ -733,7 +733,7 @@ impl Server {
|
||||
}
|
||||
};
|
||||
|
||||
let dispatcher = match self.dispatcher.clone() {
|
||||
let supervisor = match self.supervisor.clone() {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err_resp = JsonRpcResponse {
|
||||
@@ -741,7 +741,7 @@ impl Server {
|
||||
result: None,
|
||||
error: Some(JsonRpcError {
|
||||
code: -32603,
|
||||
message: "Internal error: dispatcher not available".to_string(),
|
||||
message: "Internal error: supervisor not available".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
id: client_rpc_id,
|
||||
@@ -753,7 +753,7 @@ impl Server {
|
||||
|
||||
let client_rpc_id_clone = client_rpc_id.clone();
|
||||
let fut = async move {
|
||||
dispatcher.stop_job(&job_id).await
|
||||
supervisor.stop_job(&job_id).await
|
||||
};
|
||||
|
||||
ctx.spawn(
|
||||
@@ -840,7 +840,7 @@ impl Server {
|
||||
}
|
||||
};
|
||||
|
||||
let dispatcher = match self.dispatcher.clone() {
|
||||
let supervisor = match self.supervisor.clone() {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err_resp = JsonRpcResponse {
|
||||
@@ -848,7 +848,7 @@ impl Server {
|
||||
result: None,
|
||||
error: Some(JsonRpcError {
|
||||
code: -32603,
|
||||
message: "Internal error: dispatcher not available".to_string(),
|
||||
message: "Internal error: supervisor not available".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
id: client_rpc_id,
|
||||
@@ -860,7 +860,7 @@ impl Server {
|
||||
|
||||
let client_rpc_id_clone = client_rpc_id.clone();
|
||||
let fut = async move {
|
||||
dispatcher.delete_job(&job_id).await
|
||||
supervisor.delete_job(&job_id).await
|
||||
};
|
||||
|
||||
ctx.spawn(
|
||||
@@ -929,7 +929,7 @@ impl Server {
|
||||
return;
|
||||
}
|
||||
|
||||
let dispatcher = match self.dispatcher.clone() {
|
||||
let supervisor = match self.supervisor.clone() {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
let err_resp = JsonRpcResponse {
|
||||
@@ -937,7 +937,7 @@ impl Server {
|
||||
result: None,
|
||||
error: Some(JsonRpcError {
|
||||
code: -32603,
|
||||
message: "Internal error: dispatcher not available".to_string(),
|
||||
message: "Internal error: supervisor not available".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
id: client_rpc_id,
|
||||
@@ -949,7 +949,7 @@ impl Server {
|
||||
|
||||
let client_rpc_id_clone = client_rpc_id.clone();
|
||||
let fut = async move {
|
||||
dispatcher.clear_all_jobs().await
|
||||
supervisor.clear_all_jobs().await
|
||||
};
|
||||
|
||||
ctx.spawn(
|
||||
|
@@ -3,7 +3,7 @@ use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer};
|
||||
use actix_web_actors::ws;
|
||||
use log::{info, error}; // Added error for better logging
|
||||
use once_cell::sync::Lazy;
|
||||
use hero_dispatcher::{Dispatcher, DispatcherBuilder, DispatcherError};
|
||||
use hero_supervisor::{Supervisor, SupervisorBuilder, SupervisorError};
|
||||
use hero_job::{Job, JobStatus};
|
||||
use rustls::pki_types::PrivateKeyDer;
|
||||
use rustls::ServerConfig as RustlsServerConfig;
|
||||
@@ -211,7 +211,7 @@ pub struct Server {
|
||||
pub circles: HashMap<String, Vec<String>>,
|
||||
nonce_store: HashMap<String, NonceResponse>,
|
||||
authenticated_pubkey: Option<String>,
|
||||
pub dispatcher: Option<Dispatcher>,
|
||||
pub supervisor: Option<Supervisor>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
@@ -552,15 +552,15 @@ impl Server {
|
||||
|
||||
let fut = async move {
|
||||
let caller_id = public_key.unwrap_or_else(|| "anonymous".to_string());
|
||||
match DispatcherBuilder::new()
|
||||
match SupervisorBuilder::new()
|
||||
.redis_url(&redis_url_clone)
|
||||
.caller_id(&caller_id)
|
||||
.build() {
|
||||
Ok(hero_dispatcher) => {
|
||||
hero_dispatcher
|
||||
Ok(hero_supervisor) => {
|
||||
hero_supervisor
|
||||
.new_job()
|
||||
.context_id(&circle_pk_clone)
|
||||
.script_type(hero_dispatcher::ScriptType::RhaiSAL)
|
||||
.script_type(hero_supervisor::ScriptType::RhaiSAL)
|
||||
.script(&script_content)
|
||||
.timeout(TASK_TIMEOUT_DURATION)
|
||||
.await_response()
|
||||
@@ -574,7 +574,7 @@ impl Server {
|
||||
fut.into_actor(self)
|
||||
.map(move |res, _act, ctx_inner| match res {
|
||||
Ok(output) => {
|
||||
// The dispatcher returns the actual string output from job execution
|
||||
// The supervisor returns the actual string output from job execution
|
||||
let result_value = PlayResult { output };
|
||||
let resp = JsonRpcResponse {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
@@ -586,7 +586,7 @@ impl Server {
|
||||
}
|
||||
Err(e) => {
|
||||
let (code, message) = match e {
|
||||
DispatcherError::Timeout(task_id) => (
|
||||
SupervisorError::Timeout(task_id) => (
|
||||
-32002,
|
||||
format!(
|
||||
"Timeout waiting for Rhai script (task: {})",
|
||||
|
Reference in New Issue
Block a user