use super::engine::{ConstrainedEngine, EngineConfig, EngineEvent};
use super::state::ConnectionState;
use super::types::{ConnectionId, ConstrainedAddr, ConstrainedError};
use crate::transport::TransportAddr;
use std::net::SocketAddr;
#[derive(Debug, Clone)]
pub struct EngineOutput {
pub destination: TransportAddr,
pub data: Vec<u8>,
}
impl EngineOutput {
pub fn new(destination: TransportAddr, data: Vec<u8>) -> Self {
Self { destination, data }
}
}
#[derive(Debug)]
pub struct ConstrainedEngineAdapter {
engine: ConstrainedEngine,
addr_map: std::collections::HashMap<TransportAddr, SocketAddr>,
reverse_map: std::collections::HashMap<SocketAddr, TransportAddr>,
next_synthetic: u32,
}
impl ConstrainedEngineAdapter {
pub fn new(config: EngineConfig) -> Self {
Self {
engine: ConstrainedEngine::new(config),
addr_map: std::collections::HashMap::new(),
reverse_map: std::collections::HashMap::new(),
next_synthetic: 1,
}
}
pub fn for_ble() -> Self {
Self::new(EngineConfig::for_ble())
}
pub fn for_lora() -> Self {
Self::new(EngineConfig::for_lora())
}
fn get_or_create_socket_addr(&mut self, addr: &TransportAddr) -> SocketAddr {
if let TransportAddr::Udp(socket_addr) = addr {
return *socket_addr;
}
if let Some(socket_addr) = self.addr_map.get(addr) {
return *socket_addr;
}
let ip = std::net::Ipv4Addr::new(
127,
((self.next_synthetic >> 16) & 0xFF) as u8,
((self.next_synthetic >> 8) & 0xFF) as u8,
(self.next_synthetic & 0xFF) as u8,
);
let socket_addr = SocketAddr::new(
std::net::IpAddr::V4(ip),
(self.next_synthetic % 65535) as u16,
);
self.next_synthetic += 1;
self.addr_map.insert(addr.clone(), socket_addr);
self.reverse_map.insert(socket_addr, addr.clone());
socket_addr
}
fn socket_to_transport(&self, socket_addr: &SocketAddr) -> TransportAddr {
self.reverse_map
.get(socket_addr)
.cloned()
.unwrap_or(TransportAddr::Udp(*socket_addr))
}
pub fn connect(
&mut self,
remote: &TransportAddr,
) -> Result<(ConnectionId, Vec<EngineOutput>), ConstrainedError> {
let socket_addr = self.get_or_create_socket_addr(remote);
let (conn_id, packet) = self.engine.connect(socket_addr)?;
let output = EngineOutput::new(remote.clone(), packet);
Ok((conn_id, vec![output]))
}
pub fn process_incoming(
&mut self,
source: &TransportAddr,
data: &[u8],
) -> Result<Vec<EngineOutput>, ConstrainedError> {
let socket_addr = self.get_or_create_socket_addr(source);
let responses = self.engine.process_incoming(socket_addr, data)?;
Ok(responses
.into_iter()
.map(|(addr, packet)| {
let dest = self.socket_to_transport(&addr);
EngineOutput::new(dest, packet)
})
.collect())
}
pub fn send(
&mut self,
connection_id: ConnectionId,
data: &[u8],
) -> Result<Vec<EngineOutput>, ConstrainedError> {
let responses = self.engine.send(connection_id, data)?;
Ok(responses
.into_iter()
.map(|(addr, packet)| {
let dest = self.socket_to_transport(&addr);
EngineOutput::new(dest, packet)
})
.collect())
}
pub fn recv(&mut self, connection_id: ConnectionId) -> Option<Vec<u8>> {
self.engine.recv(connection_id)
}
pub fn close(
&mut self,
connection_id: ConnectionId,
) -> Result<Vec<EngineOutput>, ConstrainedError> {
let responses = self.engine.close(connection_id)?;
Ok(responses
.into_iter()
.map(|(addr, packet)| {
let dest = self.socket_to_transport(&addr);
EngineOutput::new(dest, packet)
})
.collect())
}
pub fn poll(&mut self) -> Vec<EngineOutput> {
let responses = self.engine.poll();
responses
.into_iter()
.map(|(addr, packet)| {
let dest = self.socket_to_transport(&addr);
EngineOutput::new(dest, packet)
})
.collect()
}
pub fn next_event(&mut self) -> Option<AdapterEvent> {
self.engine.next_event().map(|event| match event {
EngineEvent::ConnectionAccepted {
connection_id,
remote_addr,
} => {
let addr = self.socket_to_transport(&remote_addr);
AdapterEvent::ConnectionAccepted {
connection_id,
remote_addr: ConstrainedAddr::new(addr),
}
}
EngineEvent::ConnectionEstablished { connection_id } => {
AdapterEvent::ConnectionEstablished { connection_id }
}
EngineEvent::DataReceived {
connection_id,
data,
} => AdapterEvent::DataReceived {
connection_id,
data,
},
EngineEvent::ConnectionClosed { connection_id } => {
AdapterEvent::ConnectionClosed { connection_id }
}
EngineEvent::ConnectionError {
connection_id,
error,
} => AdapterEvent::ConnectionError {
connection_id,
error,
},
EngineEvent::Transmit {
remote_addr,
packet,
} => {
let addr = self.socket_to_transport(&remote_addr);
AdapterEvent::Transmit {
destination: addr,
packet,
}
}
})
}
pub fn connection_count(&self) -> usize {
self.engine.connection_count()
}
pub fn engine(&self) -> &ConstrainedEngine {
&self.engine
}
pub fn engine_mut(&mut self) -> &mut ConstrainedEngine {
&mut self.engine
}
pub fn connection_state(&self, connection_id: ConnectionId) -> Option<ConnectionState> {
self.engine.connection_state(connection_id)
}
pub fn active_connections(&self) -> Vec<ConnectionId> {
self.engine.active_connections()
}
}
#[derive(Debug, Clone)]
pub enum AdapterEvent {
ConnectionAccepted {
connection_id: ConnectionId,
remote_addr: ConstrainedAddr,
},
ConnectionEstablished {
connection_id: ConnectionId,
},
DataReceived {
connection_id: ConnectionId,
data: Vec<u8>,
},
ConnectionClosed {
connection_id: ConnectionId,
},
ConnectionError {
connection_id: ConnectionId,
error: String,
},
Transmit {
destination: TransportAddr,
packet: Vec<u8>,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_adapter_creation() {
let adapter = ConstrainedEngineAdapter::for_ble();
assert_eq!(adapter.connection_count(), 0);
}
#[test]
fn test_adapter_connect_udp() {
let mut adapter = ConstrainedEngineAdapter::for_ble();
let addr = TransportAddr::Udp("192.168.1.100:8080".parse().unwrap());
let result = adapter.connect(&addr);
assert!(result.is_ok());
let (_conn_id, outputs) = result.unwrap();
assert_eq!(outputs.len(), 1);
assert_eq!(outputs[0].destination, addr);
assert!(!outputs[0].data.is_empty());
assert_eq!(adapter.connection_count(), 1);
}
#[test]
fn test_adapter_connect_ble() {
let mut adapter = ConstrainedEngineAdapter::for_ble();
let addr = TransportAddr::Ble {
device_id: [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF],
service_uuid: None,
};
let result = adapter.connect(&addr);
assert!(result.is_ok());
let (_conn_id, outputs) = result.unwrap();
assert_eq!(outputs.len(), 1);
assert_eq!(outputs[0].destination, addr);
assert!(!outputs[0].data.is_empty());
}
#[test]
fn test_adapter_synthetic_address_reuse() {
let mut adapter = ConstrainedEngineAdapter::for_ble();
let addr = TransportAddr::Ble {
device_id: [0x11, 0x22, 0x33, 0x44, 0x55, 0x66],
service_uuid: None,
};
let socket1 = adapter.get_or_create_socket_addr(&addr);
let socket2 = adapter.get_or_create_socket_addr(&addr);
assert_eq!(socket1, socket2);
}
#[test]
fn test_adapter_different_addresses() {
let mut adapter = ConstrainedEngineAdapter::for_ble();
let addr1 = TransportAddr::Ble {
device_id: [0x11, 0x22, 0x33, 0x44, 0x55, 0x66],
service_uuid: None,
};
let addr2 = TransportAddr::Ble {
device_id: [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF],
service_uuid: None,
};
let socket1 = adapter.get_or_create_socket_addr(&addr1);
let socket2 = adapter.get_or_create_socket_addr(&addr2);
assert_ne!(socket1, socket2);
}
#[test]
fn test_adapter_poll() {
let mut adapter = ConstrainedEngineAdapter::for_ble();
let outputs = adapter.poll();
assert!(outputs.is_empty());
}
}