portal, platform, and server fixes

This commit is contained in:
Timur Gordon
2025-06-30 17:01:40 +02:00
parent 1c96fa4087
commit a5b46bffb1
59 changed files with 9158 additions and 1057 deletions

2692
circle/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

11
circle/Cargo.toml Normal file
View File

@@ -0,0 +1,11 @@
[package]
name = "circle"
version = "0.1.0"
edition = "2024"
[dependencies]
launcher = { path = "../../circles/src/launcher" }
log = "0.4.14"
tokio = { version = "1.42", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

68
circle/src/README.md Normal file
View File

@@ -0,0 +1,68 @@
# OurWorld Example
This directory contains a complete example demonstrating a simulated "OurWorld" network, consisting of multiple interconnected "circles" (nodes). Each circle runs its own WebSocket server and a Rhai script worker, all managed by a central launcher.
This example is designed to showcase:
1. **Multi-Circle Configuration**: How to define and configure multiple circles in a single `circles.json` file.
2. **Programmatic Launching**: How to use the `launcher` library to start, manage, and monitor these circles from within a Rust application.
3. **Dynamic Key Generation**: The launcher generates unique cryptographic keypairs for each circle upon startup.
4. **Output Generation**: How to use the `--output` functionality to get a JSON file containing the connection details (public keys, WebSocket URLs, etc.) for each running circle.
5. **Graceful Shutdown**: How the launcher handles a `Ctrl+C` signal to shut down all running circles cleanly.
## Directory Contents
- `circles.json`: The main configuration file that defines the 7 circles in the OurWorld network, including their names, ports, and associated Rhai scripts.
- `scripts/`: This directory contains the individual Rhai scripts that define the behavior of each circle.
- `ourworld_output.json` (Generated): This file is created after running the example and contains the runtime details of each circle.
## How to Run the Example
There are two ways to run this example, each demonstrating a different way to use the launcher.
### 1. As a Root Example (Recommended)
This method runs the launcher programmatically from the root of the workspace and is the simplest way to see the system in action. It uses the `examples/ourworld.rs` file.
```sh
# From the root of the workspace
cargo run --example ourworld
```
### 2. As a Crate-Level Example
This method runs a similar launcher, but as an example *within* the `launcher` crate itself. It uses the `src/launcher/examples/ourworld/main.rs` file. This is useful for testing the launcher in a more isolated context.
```sh
# Navigate to the launcher's crate directory
cd src/launcher
# Run the 'ourworld' example using cargo
cargo run --example ourworld
```
### 3. Using the Launcher Binary
This method uses the main `launcher` binary to run the configuration, which is useful for testing the command-line interface.
```sh
# From the root of the workspace
cargo run -p launcher -- --config examples/ourworld/circles.json --output examples/ourworld/ourworld_output.json
```
## What to Expect
When you run the example, you will see log output indicating that the launcher is starting up, followed by a table summarizing the running circles:
```
+-----------------+------------------------------------------------------------------+------------------------------------------+-----------------------+
| Name | Public Key | Worker Queue | WS URL |
+=================+==================================================================+==========================================+=======================+
| OurWorld | 02... | rhai_tasks:02... | ws://127.0.0.1:9000/ws|
+-----------------+------------------------------------------------------------------+------------------------------------------+-----------------------+
| Dunia Cybercity | 03... | rhai_tasks:03... | ws://127.0.0.1:9001/ws|
+-----------------+------------------------------------------------------------------+------------------------------------------+-----------------------+
| ... (and so on for all 7 circles) |
+-----------------+------------------------------------------------------------------+------------------------------------------+-----------------------+
```
The launcher will then wait for you to press `Ctrl+C` to initiate a graceful shutdown of all services.

9
circle/src/circles.json Normal file
View File

@@ -0,0 +1,9 @@
[
{
"name": "Freezone",
"port": 9000,
"script_path": "scripts/freezone.rhai",
"public_key": "030b62236efa67855b3379a9d4add1facbe8a545bafa86e1d6fbac06caae5b5b12",
"secret_key": "04225fbb41d8c397581d7ec19ded8aaf02d8b9daf27fed9617525e4f8114a382"
}
]

90
circle/src/main.rs Normal file
View File

@@ -0,0 +1,90 @@
//! Example of launching multiple circles and outputting their details to a file.
//!
//! This example demonstrates how to use the launcher library to start circles
//! programmatically, similar to how the `launcher` binary works.
//!
//! # Usage
//!
//! ```sh
//! cargo run --example ourworld
//! ```
//!
//! This will:
//! 1. Read the `circles.json` file in the `examples/ourworld` directory.
//! 2. Launch all 7 circles defined in the config.
//! 3. Create a `ourworld_output.json` file in the same directory with the details.
//! 4. The launcher will run until you stop it with Ctrl+C.
use launcher::{run_launcher, Args, CircleConfig};
use log::{error, info};
use std::error::Error as StdError;
use std::fs;
use std::path::PathBuf;
#[tokio::main]
async fn main() -> Result<(), Box<dyn StdError>> {
println!("--- Launching OurWorld Example Programmatically ---");
// The example is now at the root of the `examples` directory,
// so we can reference its assets directly.
let example_dir = PathBuf::from("./src");
let config_path = example_dir.join("circles.json");
let output_path = example_dir.join("ourworld_output.json");
println!("Using config file: {:?}", config_path);
println!("Output will be written to: {:?}", output_path);
// Manually construct the arguments instead of parsing from command line.
// This is useful when embedding the launcher logic in another application.
let args = Args {
config_path: config_path.clone(),
output: Some(output_path),
debug: true, // Enable debug logging for the example
verbose: 2, // Set verbosity to max
};
if !config_path.exists() {
let msg = format!("Configuration file not found at {:?}", config_path);
error!("{}", msg);
return Err(msg.into());
}
let config_content = fs::read_to_string(&config_path)?;
let mut circle_configs: Vec<CircleConfig> = match serde_json::from_str(&config_content) {
Ok(configs) => configs,
Err(e) => {
error!(
"Failed to parse {}: {}. Ensure it's a valid JSON array of CircleConfig.",
config_path.display(),
e
);
return Err(Box::new(e) as Box<dyn StdError>);
}
};
// Make script paths relative to the project root by prepending the example directory path.
for config in &mut circle_configs {
if let Some(script_path) = &config.script_path {
let full_script_path = example_dir.join(script_path);
config.script_path = Some(full_script_path.to_string_lossy().into_owned());
}
}
if circle_configs.is_empty() {
info!(
"No circle configurations found in {}. Exiting.",
config_path.display()
);
return Ok(());
}
println!("Starting launcher... Press Ctrl+C to exit.");
// The run_launcher function will setup logging, spawn circles, print the table,
// and wait for a shutdown signal (Ctrl+C).
run_launcher(args, circle_configs).await?;
println!("--- OurWorld Example Finished ---");
Ok(())
}

View File

@@ -0,0 +1,8 @@
[
{
"name": "Freezone",
"public_key": "030b62236efa67855b3379a9d4add1facbe8a545bafa86e1d6fbac06caae5b5b12",
"worker_queue": "rhai_tasks:030b62236efa67855b3379a9d4add1facbe8a545bafa86e1d6fbac06caae5b5b12",
"ws_url": "ws://127.0.0.1:9000"
}
]

View File

@@ -0,0 +1,10 @@
configure()
.title("Zanzibar Digital Freezone")
.description("Creating a better world.")
.ws_url("wss://localhost:9000/ws")
.logo("🌍")
.save_circle();
let circle = get_configuration();
print("--- Creating OurWorld Library ---");