mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Add Docs
This commit is contained in:
@@ -26,7 +26,7 @@ unshell/
|
||||
├── src/tree/ # Hierarchical message routing
|
||||
│ ├── component.rs # Component trait (implement for any module)
|
||||
│ ├── endpoint.rs # Endpoint manager
|
||||
│ ├── protocols/ # Pluggable protocol stack
|
||||
│ ├── protocols/ # Pluggable protocol stack
|
||||
│ └── tcp/ # Example transport implementations
|
||||
├── ush-obfuscate/ # Compile-time string obfuscation
|
||||
└── ush-payload/ # Test harness
|
||||
@@ -36,7 +36,24 @@ unshell/
|
||||
|
||||
Everything plugs into these abstractions:
|
||||
|
||||
### Component - Any Module
|
||||
### TreeElement - The Foundation
|
||||
|
||||
Every node in the tree implements this trait:
|
||||
|
||||
```rust
|
||||
use serde_json::Value;
|
||||
use unshell::tree::TreeElement;
|
||||
|
||||
pub trait TreeElement: Send + Sync {
|
||||
fn get_type(&self) -> Value;
|
||||
fn send_message(&mut self, target: Value, message: Value) -> Value;
|
||||
}
|
||||
```
|
||||
|
||||
- `get_type()` returns the element's type identifier
|
||||
- `send_message()` handles incoming messages and returns responses
|
||||
|
||||
### Component - Extensible Modules
|
||||
|
||||
```rust
|
||||
use unshell::tree::Component;
|
||||
@@ -50,10 +67,13 @@ pub trait Component: Send + Sync {
|
||||
}
|
||||
```
|
||||
|
||||
**Important**: The `init()` method should only configure the component, not establish connections.
|
||||
For TcpClient, use `auto_connect: true` in config if you need auto-connection after initialization.
|
||||
|
||||
### Protocol - Any Encoding Layer
|
||||
|
||||
```rust
|
||||
use unshell::tree::protocols::Protocol;
|
||||
use unshell::protocols::Protocol;
|
||||
|
||||
pub trait Protocol: Send + Sync {
|
||||
fn name(&self) -> &'static str;
|
||||
@@ -76,6 +96,82 @@ pub trait Protocol: Send + Sync {
|
||||
// They expose the same interface as native components
|
||||
```
|
||||
|
||||
## Tree Message Protocol
|
||||
|
||||
Messages follow a JSON-based format defined in `src/tree/message.rs`:
|
||||
|
||||
```rust
|
||||
// Create a request
|
||||
let msg = TreeMessage::new("rpc.call")
|
||||
.to_target(["components", "tcp-client"])
|
||||
.with_payload(json!({
|
||||
"method": "connect",
|
||||
"params": {"address": "127.0.0.1", "port": 443}
|
||||
}));
|
||||
|
||||
// Send via protocol stack
|
||||
let encoded = protocol_stack.encode_message(&msg)?;
|
||||
```
|
||||
|
||||
### Message Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `req` | Request - expecting a response |
|
||||
| `resp` | Response - reply to a request |
|
||||
| `event` | Unsolicited notification |
|
||||
| `stream` | Stream data message |
|
||||
|
||||
## ComponentRegistry Usage
|
||||
|
||||
```rust
|
||||
use unshell::tree::{ComponentRegistry, Component};
|
||||
|
||||
// Create registry
|
||||
let mut registry = ComponentRegistry::new();
|
||||
|
||||
// Register components
|
||||
let client = Box::new(TcpClient::new("my-client"));
|
||||
registry.register(client).unwrap();
|
||||
|
||||
// List components
|
||||
let names = registry.list();
|
||||
|
||||
// Send to specific component
|
||||
let result = registry.send_to_component("my-client", json!({"method": "status"}));
|
||||
|
||||
// Broadcast to all
|
||||
let results = registry.broadcast(json!({"method": "status"}));
|
||||
|
||||
// Shutdown all gracefully
|
||||
let shutdown_results = registry.shutdown_all();
|
||||
|
||||
// Remove component
|
||||
registry.remove("my-client");
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
The framework includes a feature-gated logging system. Use the logging macros:
|
||||
|
||||
```rust
|
||||
use unshell::{info, warn, error};
|
||||
|
||||
// Info messages
|
||||
info!("Component '{}' registered", name);
|
||||
|
||||
// Warnings
|
||||
warn!("Component '{}' not found", name);
|
||||
|
||||
// Errors
|
||||
error!("Connection failed: {}", err);
|
||||
```
|
||||
|
||||
Enable logging with the `log` feature:
|
||||
```toml
|
||||
unshell = { path = ".", features = ["log"] }
|
||||
```
|
||||
|
||||
## Module System
|
||||
|
||||
```rust
|
||||
@@ -106,10 +202,19 @@ Load compiled `.so`/`.dll` modules at runtime using `libloading` or in-memory vi
|
||||
Layer protocols arbitrarily:
|
||||
|
||||
```rust
|
||||
use ush_payload::protocols::{ProtocolStack, ProtocolConfig};
|
||||
|
||||
// Create stack: base64 -> http -> tcp
|
||||
let mut stack = ProtocolStack::new();
|
||||
stack.push(&ProtocolConfig::Base64(Default::default())).unwrap();
|
||||
stack.push(&ProtocolConfig::Http(Default::default())).unwrap();
|
||||
stack.push(&ProtocolConfig::Tcp(Default::default())).unwrap();
|
||||
|
||||
// Encode: app -> base64 -> http -> tcp -> network
|
||||
let encoded = stack.encode(data)?;
|
||||
|
||||
// Decode: network -> tcp -> http -> base64 -> app
|
||||
let decoded = stack.decode(&encoded)?;
|
||||
```
|
||||
|
||||
Order determines encoding: app → base64 → http → tcp → network
|
||||
@@ -151,6 +256,40 @@ impl Protocol for DnsTransport {
|
||||
stack.push(&ProtocolConfig::Custom { name: "dns", config: ... });
|
||||
```
|
||||
|
||||
### Create a Custom Component
|
||||
|
||||
```rust
|
||||
use unshell::tree::{Component, TreeElement, Branch};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
pub struct MyComponent {
|
||||
name: String,
|
||||
config: MyConfig,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
fn name(&self) -> &str { &self.name }
|
||||
|
||||
fn status(&self) -> Value {
|
||||
json!({"active": true, "name": self.name})
|
||||
}
|
||||
|
||||
fn init(&mut self, config: Value) -> Result<(), String> {
|
||||
// Configure only - don't connect here
|
||||
self.config = serde_json::from_value(config)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn shutdown(&mut self) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Register in component registry
|
||||
let mut registry = ComponentRegistry::new();
|
||||
registry.register(Box::new(MyComponent::new("my-component"))).unwrap();
|
||||
```
|
||||
|
||||
## Cross-Compilation
|
||||
|
||||
```bash
|
||||
@@ -183,8 +322,12 @@ cargo build --features obfuscate
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Run the test harness
|
||||
cd ush-payload
|
||||
cargo run
|
||||
|
||||
# Run library tests
|
||||
cargo test -p ush-payload --lib
|
||||
```
|
||||
|
||||
## Obfuscation
|
||||
@@ -235,7 +378,7 @@ To avoid redundant `sym!()` calls, define constants in `src/tree/symbols.rs`:
|
||||
```rust
|
||||
use crate::obfuscate::sym;
|
||||
|
||||
pub const MY_CONSTANT: &'static str = sym!("MyString");
|
||||
pub const MY_CONSTANT: &str = sym!("MyString");
|
||||
```
|
||||
|
||||
Then use the constant in your code:
|
||||
@@ -260,3 +403,10 @@ Protocol-specific and transport-specific code belongs in `ush-payload`, while th
|
||||
```
|
||||
|
||||
This produces a ~200KB binary (may vary with content).
|
||||
|
||||
### Component Design Guidelines
|
||||
|
||||
1. **init() should configure, not connect**: Only establish connections if explicitly requested via config
|
||||
2. **Use symbols for string constants**: All user-facing strings should use `sym!()` for obfuscation
|
||||
3. **Log important operations**: Use the logging macros for registration, connection, and errors
|
||||
4. **Return structured responses**: Use JSON with `success`, `result`, and `error` fields
|
||||
|
||||
Reference in New Issue
Block a user