use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::time::SystemTime;
use uuid::Uuid;
use crate::utils::error::Result;
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct VectorClock {
pub clocks: BTreeMap<String, u64>,
}
impl VectorClock {
pub fn new() -> Self {
Self {
clocks: BTreeMap::new(),
}
}
pub fn tick(&mut self, node_id: &str) {
let entry = self.clocks.entry(node_id.to_string()).or_insert(0);
*entry += 1;
}
pub fn merge(&mut self, other: &VectorClock) {
for (node_id, &time) in &other.clocks {
let entry = self.clocks.entry(node_id.clone()).or_insert(0);
*entry = std::cmp::max(*entry, time);
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BoundaryCrossing {
pub id: String,
pub crossing_type: String,
pub caller_id: String,
pub callee_id: String,
pub interface_fn: String,
pub timestamp: DateTime<Utc>,
pub vector_clock: VectorClock,
pub input_hash: String,
pub output_hash: Option<String>,
pub status_code: i32,
pub duration_us: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InterchangeablePart {
pub id: String,
pub part_type: String,
pub version: String,
pub interfaces: Vec<String>,
pub payload_hash: String,
pub payload_size: usize,
}
pub struct GenesisCore {
pub parts: HashMap<String, InterchangeablePart>,
pub memory_states: HashMap<String, Vec<u8>>,
pub runtime_clock: VectorClock,
}
impl GenesisCore {
pub fn new() -> Self {
Self {
parts: HashMap::new(),
memory_states: HashMap::new(),
runtime_clock: VectorClock::new(),
}
}
pub fn register_part(&mut self, part: InterchangeablePart) -> Result<()> {
let part_id = part.id.clone();
self.runtime_clock.tick("genesis-core");
self.parts.insert(part_id, part);
Ok(())
}
pub fn set_state(&mut self, part_id: &str, state: Vec<u8>) -> Result<()> {
self.memory_states.insert(part_id.to_string(), state);
Ok(())
}
}
pub struct GgenMembrane {
pub core: GenesisCore,
pub event_log: Vec<BoundaryCrossing>,
pub adapters: HashMap<String, String>,
}
impl GgenMembrane {
pub fn new(core: GenesisCore) -> Self {
Self {
core,
event_log: Vec::new(),
adapters: HashMap::new(),
}
}
pub fn bind_adapter(&mut self, outer_port: &str, inner_interface: &str) {
self.adapters
.insert(outer_port.to_string(), inner_interface.to_string());
}
pub fn invoke(
&mut self, caller: &str, callee_part_id: &str, interface_fn: &str, input_data: &[u8],
) -> Result<(Vec<u8>, BoundaryCrossing)> {
let start_time = Instant::new();
let utc_now = Utc::now();
let input_hash = blake3::hash(input_data).to_hex().to_string();
self.core.runtime_clock.tick(callee_part_id);
self.core.runtime_clock.tick(caller);
let current_clock = self.core.runtime_clock.clone();
let (output_data, status_code) = if let Some(part) = self.core.parts.get(callee_part_id) {
let mut output = Vec::new();
output.extend_from_slice(b"Executed: ");
output.extend_from_slice(part.id.as_bytes());
output.extend_from_slice(b"::");
output.extend_from_slice(interface_fn.as_bytes());
output.extend_from_slice(b" on data: ");
output.extend_from_slice(input_data);
(output, 0)
} else {
(b"Part not found".to_vec(), 404)
};
let output_hash = blake3::hash(&output_data).to_hex().to_string();
let duration = start_time.elapsed().as_micros() as u64;
let crossing = BoundaryCrossing {
id: Uuid::new_v4().to_string(),
crossing_type: "CallAndReturn".to_string(),
caller_id: caller.to_string(),
callee_id: callee_part_id.to_string(),
interface_fn: interface_fn.to_string(),
timestamp: utc_now,
vector_clock: current_clock,
input_hash,
output_hash: Some(output_hash),
status_code,
duration_us: duration,
};
self.event_log
.clone_from(&[self.event_log.clone(), vec![crossing.clone()]].concat());
Ok((output_data, crossing))
}
}
struct Instant(SystemTime);
impl Instant {
fn new() -> Self {
Self(SystemTime::now())
}
fn elapsed(&self) -> std::time::Duration {
self.0
.elapsed()
.unwrap_or(std::time::Duration::from_secs(0))
}
}