pub trait HarborLayer {
fn resolve_peer(&self, address: &[u8]) -> Option<Vec<u8>>;
fn register_peer(&mut self, address: &[u8], meta: &[u8]) -> bool;
fn list_peers(&self) -> Vec<Vec<u8>>;
}
pub trait TidePoolLayer {
fn enqueue(&mut self, msg: &[u8]) -> bool;
fn dequeue(&mut self) -> Option<Vec<u8>>;
fn buffer_len(&self) -> usize;
}
pub trait CurrentLayer {
fn export(&self, msg: &[u8]) -> Vec<u8>;
fn import(&self, data: &[u8]) -> Option<Vec<u8>>;
fn transport_id(&self) -> String;
}
pub trait ChannelLayer {
fn bridge_send(&mut self, channel: u8, msg: &[u8]) -> bool;
fn bridge_recv(&mut self, channel: u8) -> Option<Vec<u8>>;
fn is_live(&self) -> bool;
}
pub trait BeaconLayer {
fn emit_event(&mut self, event: &[u8]) -> bool;
fn observe(&self) -> Option<Vec<u8>>;
fn trust_score(&self) -> f32;
}
pub trait ReefLayer {
fn persist(&mut self, key: &[u8], state: &[u8]) -> bool;
fn restore(&self, key: &[u8]) -> Option<Vec<u8>>;
fn handoff(&mut self, state: &[u8]) -> bool;
}
pub struct ShipStack {
pub harbor: Box<dyn HarborLayer>,
pub tide_pool: Box<dyn TidePoolLayer>,
pub current: Box<dyn CurrentLayer>,
pub channel: Box<dyn ChannelLayer>,
pub beacon: Box<dyn BeaconLayer>,
pub reef: Box<dyn ReefLayer>,
}
impl ShipStack {
pub fn send(&mut self, msg: &[u8]) -> Vec<u8> {
self.harbor.register_peer(msg, b"outbound");
self.tide_pool.enqueue(msg);
let buffered = self.tide_pool.dequeue().unwrap_or_else(|| msg.to_vec());
let framed = self.current.export(&buffered);
self.channel.bridge_send(0, &framed);
self.beacon.emit_event(b"send");
self.reef.persist(b"last-send", &framed);
framed
}
pub fn receive(&mut self, data: &[u8]) -> Vec<u8> {
self.reef.persist(b"last-recv", data);
self.beacon.emit_event(b"recv");
let from_channel = self.channel.bridge_recv(0).unwrap_or_else(|| data.to_vec());
let unframed = self.current.import(&from_channel).unwrap_or_else(|| from_channel.clone());
self.tide_pool.enqueue(&unframed);
let routed = self.tide_pool.dequeue().unwrap_or_else(|| unframed.clone());
self.harbor.register_peer(&routed, b"inbound");
routed
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::{HashMap, VecDeque};
struct MockHarbor {
peers: Vec<Vec<u8>>,
}
impl HarborLayer for MockHarbor {
fn resolve_peer(&self, address: &[u8]) -> Option<Vec<u8>> {
self.peers.iter().find(|p| p.as_slice() == address).cloned()
}
fn register_peer(&mut self, address: &[u8], _meta: &[u8]) -> bool {
self.peers.push(address.to_vec());
true
}
fn list_peers(&self) -> Vec<Vec<u8>> {
self.peers.clone()
}
}
struct MockTidePool {
buf: VecDeque<Vec<u8>>,
}
impl TidePoolLayer for MockTidePool {
fn enqueue(&mut self, msg: &[u8]) -> bool {
self.buf.push_back(msg.to_vec());
true
}
fn dequeue(&mut self) -> Option<Vec<u8>> {
self.buf.pop_front()
}
fn buffer_len(&self) -> usize {
self.buf.len()
}
}
struct MockCurrent;
impl CurrentLayer for MockCurrent {
fn export(&self, msg: &[u8]) -> Vec<u8> {
let mut out = b"git:".to_vec();
out.extend_from_slice(msg);
out
}
fn import(&self, data: &[u8]) -> Option<Vec<u8>> {
data.strip_prefix(b"git:").map(|b| b.to_vec())
}
fn transport_id(&self) -> String {
"git-i2i-mock".to_string()
}
}
struct MockChannel {
live: bool,
inbox: Option<Vec<u8>>,
}
impl ChannelLayer for MockChannel {
fn bridge_send(&mut self, _channel: u8, msg: &[u8]) -> bool {
self.inbox = Some(msg.to_vec());
true
}
fn bridge_recv(&mut self, _channel: u8) -> Option<Vec<u8>> {
self.inbox.take()
}
fn is_live(&self) -> bool {
self.live
}
}
struct MockBeacon {
score: f32,
last: Option<Vec<u8>>,
}
impl BeaconLayer for MockBeacon {
fn emit_event(&mut self, event: &[u8]) -> bool {
self.last = Some(event.to_vec());
true
}
fn observe(&self) -> Option<Vec<u8>> {
self.last.clone()
}
fn trust_score(&self) -> f32 {
self.score
}
}
struct MockReef {
store: HashMap<Vec<u8>, Vec<u8>>,
}
impl ReefLayer for MockReef {
fn persist(&mut self, key: &[u8], state: &[u8]) -> bool {
self.store.insert(key.to_vec(), state.to_vec());
true
}
fn restore(&self, key: &[u8]) -> Option<Vec<u8>> {
self.store.get(key).cloned()
}
fn handoff(&mut self, _state: &[u8]) -> bool {
true
}
}
fn make_stack() -> ShipStack {
ShipStack {
harbor: Box::new(MockHarbor { peers: vec![] }),
tide_pool: Box::new(MockTidePool { buf: VecDeque::new() }),
current: Box::new(MockCurrent),
channel: Box::new(MockChannel { live: true, inbox: None }),
beacon: Box::new(MockBeacon { score: 1.0, last: None }),
reef: Box::new(MockReef { store: HashMap::new() }),
}
}
#[test]
fn test_ship_stack_construction() {
let stack = make_stack();
assert!(stack.channel.is_live());
assert_eq!(stack.current.transport_id(), "git-i2i-mock");
assert_eq!(stack.beacon.trust_score(), 1.0);
}
#[test]
fn test_message_roundtrip() {
let mut stack = make_stack();
let original = b"hello plato";
let sent = stack.send(original);
assert_eq!(sent, b"git:hello plato");
let received = stack.receive(&sent);
assert_eq!(received, original.as_ref());
}
}