Compare commits

..

No commits in common. "dbb52ccbb22b0ebf5ba346c05fa61b676a03d241" and "500b26703e93edb4eeee3128b17815183445da50" have entirely different histories.

12 changed files with 25 additions and 263 deletions

View file

@ -1 +1 @@
146 136

View file

@ -1,41 +1,24 @@
use tracing::{debug, info}; use tracing::info;
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use std::thread::JoinHandle;
use crate::lifecycle::{LifeState, LifecycleCommand, LifecycleCommandResponse, LifecycleReceipt}; use crate::lifecycle::{LifeState, LifecycleCommand, LifecycleCommandResponse, LifecycleReceipt};
use crate::lifecycle::LifeState::{Dying, Buried, Genisys}; use crate::lifecycle::LifeState::{Buried, Genisys};
use crate::organs::organ_factory::OrganFactory;
use crate::organs::organ_socket::OrganSocket;
use crate::protocols::{BrainMessage, OrganCommand, OrganCommandEnvelope};
pub struct Brain { pub struct Brain {
state:LifeState, state:LifeState,
divine_rx : Receiver<LifecycleCommand>, divine_rx : Receiver<LifecycleCommand>,
divine_tx: Sender<LifecycleReceipt>, divine_tx: Sender<LifecycleReceipt>
organ_rx: Receiver<BrainMessage>,
organ_tx: Sender<BrainMessage>,
organ_sockets: Vec<OrganSocket>,
} }
impl Brain { impl Brain {
pub fn new(divine_rx: Receiver<LifecycleCommand>, divine_tx: Sender<LifecycleReceipt>) -> Self { pub fn new(divine_rx: Receiver<LifecycleCommand>, divine_tx: Sender<LifecycleReceipt>) -> Self {
let (organ_tx, organ_rx) = std::sync::mpsc::channel::<BrainMessage>();
Self { Self {
state: LifeState::Dead, state: LifeState::Dead,
divine_rx, divine_rx,
divine_tx, divine_tx,
organ_rx,
organ_tx,
organ_sockets: Vec::new()
} }
} }
pub fn run(&mut self) { pub fn run(&mut self) {
self.execute_brain_loop();
self.build_organs();
}
fn execute_brain_loop(&mut self) {
loop { loop {
while let Ok(command) = self.divine_rx.try_recv() { while let Ok(command) = self.divine_rx.try_recv() {
self.handle_divine_command(command) self.handle_divine_command(command)
@ -53,22 +36,14 @@ impl Brain {
} }
fn rest() { fn rest() {
debug!("Brain is resting."); std::thread::sleep(std::time::Duration::from_millis(1))
std::thread::sleep(std::time::Duration::from_millis(200))
} }
fn handle_divine_command(&mut self, command: LifecycleCommand) { fn handle_divine_command(&mut self, command: LifecycleCommand) {
info!("God has commanded {:?}", command); info!("God has commanded {:?}", command);
if self.can_transition_lifecycle(&command) { if self.can_transition_lifecycle(&command) {
if command.required_state == Dying self.set_lifecycle_state(&command);
{
self.set_lifecycle_state(&command, Buried);
} else {
self.set_lifecycle_state(&command, command.required_state);
}
return; return;
} }
@ -85,7 +60,7 @@ impl Brain {
fn can_transition_lifecycle(&self, command: &LifecycleCommand) -> bool fn can_transition_lifecycle(&self, command: &LifecycleCommand) -> bool
{ {
if command.required_state == Buried || command.required_state == Dying { if (command.required_state == Buried) {
return true return true
} }
@ -95,26 +70,17 @@ impl Brain {
false false
} }
fn set_lifecycle_state(&mut self, command: &LifecycleCommand, new_state: LifeState) { fn set_lifecycle_state(&mut self, command: &LifecycleCommand) {
self.state = new_state; self.state = command.required_state;
self.report_to_god(LifecycleReceipt{ self.report_to_god(LifecycleReceipt{
command: command.clone(), command: command.clone(),
response: LifecycleCommandResponse::Ok, response: LifecycleCommandResponse::Ok,
new_state: self.state new_state: self.state
}); });
} }
fn report_to_god(&self, receipt: LifecycleReceipt) { fn report_to_god(&self, receipt: LifecycleReceipt) {
info!("Reporting to God: Status = {:?}, NewState={:?}", receipt.response, receipt.new_state); info!("Reporting to God: Status = {:?}, NewState={:?}", receipt.response, receipt.new_state);
let _ = self.divine_tx.send(receipt); let _ = self.divine_tx.send(receipt);
} }
fn build_organs(& mut self) {
info!("Building organs...");
let factory = OrganFactory::new(self.organ_tx.clone());
info!("{} organs have been built and wired in.", self.organ_sockets.len());
}
} }

View file

@ -0,0 +1,7 @@
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum State {
Starting,
Running,
Stopping,
Stopped,
}

View file

@ -1,6 +0,0 @@
#[derive(Debug, Clone, Copy)]
pub struct Point3D {
pub x: f32,
pub y: f32,
pub z: f32
}

View file

@ -12,7 +12,7 @@ pub enum LifeState {
Flight, Flight,
Panic, Panic,
Dying, Dying,
Buried, Buried
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -34,4 +34,3 @@ pub struct LifecycleReceipt {
pub response: LifecycleCommandResponse, pub response: LifecycleCommandResponse,
pub new_state: LifeState pub new_state: LifeState
} }

View file

@ -1,43 +1,27 @@
pub mod lifecycle; pub mod lifecycle;
pub mod brain; pub mod brain;
pub mod organs;
pub mod coordinates;
pub mod protocols;
use std::fmt::Alignment::Left; use tracing::info;
use tracing::{info, debug};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::sync::mpsc; use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tracing_subscriber::registry;
use crate::brain::Brain; use crate::brain::Brain;
use crate::lifecycle::{LifeState, LifecycleCommand, LifecycleReceipt}; use crate::lifecycle::{LifeState, LifecycleCommand, LifecycleReceipt};
fn main() { fn main() {
let shutdown_requested = Arc::new(AtomicBool::new(false));
setup_logging(); setup_logging();
info!("RustyLee: {}", env!("FULL_VERSION")); info!("RustyLee: {}", env!("FULL_VERSION"));
setup_os_signal_handler(shutdown_requested.clone());
let (tx, rx) = spawn_brain(); let (tx, rx) = spawn_brain();
setup_os_signal_handler(tx.clone());
let_there_be_life(&tx, &rx); let_there_be_life(&tx, &rx);
wait_for_death(tx, rx);
info!("God is watching.");
loop{
if let Ok(receipt) = rx.recv() {
debug!("Brain status: {:?}", receipt.new_state);
if receipt.new_state == LifeState::Dead || receipt.new_state == LifeState::Buried {
break;
} else {
thread::sleep(Duration::from_millis(100));
}
}
}
// wait_for_death(tx, rx);
info!("God: Brain has been buried. Shutting down."); info!("God: Brain has been buried. Shutting down.");
} }
@ -85,14 +69,11 @@ fn spawn_brain() -> (Sender<LifecycleCommand>, Receiver<LifecycleReceipt>) {
(to_brain_tx, from_brain_rx) (to_brain_tx, from_brain_rx)
} }
fn setup_os_signal_handler(tx: Sender<LifecycleCommand>) { fn setup_os_signal_handler(s: Arc<AtomicBool>) {
info!("Setting up SIGTERM/SIGINT handling."); info!("Setting up SIGTERM/SIGINT handling.");
ctrlc::set_handler(move || { ctrlc::set_handler(move || {
info!("[Signal] Shutdown signal caught!"); info!("[Signal] Shutdown signal caught!");
let _ = tx.send(LifecycleCommand { s.store(true, Ordering::SeqCst);
required_state: LifeState::Dying,
command_time: Instant::now(),
});
}).expect("Error setting signal handler."); }).expect("Error setting signal handler.");
} }

View file

@ -1,4 +0,0 @@
pub mod heart;
pub mod organ;
pub mod organ_socket;
pub mod organ_factory;

View file

@ -1,48 +0,0 @@
use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender};
use std::time::{SystemTime, UNIX_EPOCH};
use tracing::{info, instrument};
use crate::protocols::{BrainMessage, OrganCommandEnvelope, OrganResponse};
pub struct Heart {
id: u32,
brain_command_rx: mpsc::Receiver<OrganCommandEnvelope>,
feedback_to_brain_tx: mpsc::Sender<BrainMessage>,
}
impl Heart {
pub(crate) fn new(id: u32, rx: Receiver<OrganCommandEnvelope>, tx: Sender<BrainMessage>) -> Self {
Self {
id,
brain_command_rx: rx,
feedback_to_brain_tx: tx,
}
}
#[instrument(skip(self), fields(heart_id = self.id))]
pub fn start(&mut self) {
info!("Heart listener active");
while let Ok(envelope) = self.brain_command_rx.recv() {
// 1. Process the command (Logic goes here later)
let response = OrganResponse::Ok;
// 2. Capture the "now" timestamp
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64;
// 3. Package the reply
let reply = BrainMessage {
organ_command: envelope, // Move the original envelope back
responded_at: now,
response,
};
// 4. Trace the reply and send
info!(?reply, "Sending response to Brain");
let _ = self.feedback_to_brain_tx.send(reply);
}
}
}

View file

@ -1,9 +0,0 @@
use crate::coordinates::Point3D;
use crate::lifecycle::LifeState;
pub trait Organ: Send {
/// Returns the immutable U32 ID assigned by the factory.
fn id(&self) -> u32;
}

View file

@ -1,56 +0,0 @@
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
use crate::organs::organ_socket::OrganSocket;
use crate::organs::heart::Heart; // Assuming Heart is our first organ
use crate::protocols::{OrganCommandEnvelope, BrainMessage};
pub struct OrganFactory {
brain_tx: Sender<BrainMessage>,
}
impl OrganFactory {
pub(crate) fn new(brain_sender: Sender<BrainMessage>) -> Self {
Self {
brain_tx: brain_sender,
}
}
}
impl OrganFactory {
pub fn build_organs(
// The Brain's "Inbox" mouth - we'll clone this for each organ
brain_tx: Sender<BrainMessage>
) -> Vec<OrganSocket> {
let mut sockets = Vec::new();
// Let's spawn a Heart as an example (ID: 1)
// In a real factory, you might loop through a config list here
let heart_socket = Self::spawn_heart(1, brain_tx.clone());
sockets.push(heart_socket);
// Add more organs here...
// let lung_socket = Self::spawn_lung(2, brain_tx.clone());
tracing::info!(count = sockets.len(), "Organ collection built and threads spawned");
sockets
}
fn spawn_heart(id: u32, feedback_to_brain_tx: Sender<BrainMessage>) -> OrganSocket {
let (brain_command_to_organ_tx, brain_command_to_organ_rx) =
Self::get_organ_channels();
let socket = OrganSocket::new(id, brain_command_to_organ_tx);
thread::spawn(move || {
let mut heart = Heart::new(id, brain_command_to_organ_rx, feedback_to_brain_tx);
heart.start();
});
socket
}
fn get_organ_channels() -> (Sender<OrganCommandEnvelope>, Receiver<OrganCommandEnvelope>) {
mpsc::channel::<OrganCommandEnvelope>()
}
}

View file

@ -1,32 +0,0 @@
use std::time::{SystemTime, UNIX_EPOCH};
use std::sync::mpsc::Sender;
use crate::protocols::{OrganCommand, OrganCommandEnvelope};
pub struct OrganSocket {
pub id: u32,
tx: Sender<OrganCommandEnvelope>,
}
impl OrganSocket {
pub fn new(id: u32, tx: Sender<OrganCommandEnvelope>) -> Self {
Self { id, tx }
}
pub fn send(&self, command: OrganCommand) {
// Here's the "Stamping" logic.
// The Brain just says "Beat", the Socket adds the "Metadata".
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64;
let envelope = OrganCommandEnvelope {
command,
issued_at: now,
};
if let Err(e) = self.tx.send(envelope) {
tracing::error!(organ_id = self.id, error = %e, "Socket delivery failed");
}
}
}

View file

@ -1,36 +0,0 @@
use crate::coordinates::Point3D;
#[derive(Debug)]
pub enum OrganCommand {
Sleep,
Waken,
Pause,
Resume,
Beat (u32),
ChangeSpeed (u32),
GoFaster(u32),
GoSlower(u32),
MoveTo {
relative_to_center: Point3D,
speed: u32
}
}
#[derive(Debug)]
pub enum OrganResponse {
Ok,
Rejected
}
#[derive(Debug)]
pub struct OrganCommandEnvelope {
pub command: OrganCommand,
pub issued_at: u64
}
#[derive(Debug)]
pub struct BrainMessage {
pub organ_command: OrganCommandEnvelope,
pub responded_at: u64,
pub response: OrganResponse,
}