[TSM.ID].[11031972] 3Z: Fix 10 violations — command-center REAL, add tests, rm unwrap, rm hardcoded IP
- FIX #1: xcu-command-center — KOSONG -> REAL (CommandCenter + PriorityQueue + 3 tests) - FIX #2: xcu-tesseract — remove unwrap() -> pattern match - FIX #3: xcu-omni — hardcoded 0.0.0.0 -> bind_addr param - FIX #4: xcu-billing-matrix — add deny(warnings), env var bind - FIX #5: xcu-garbage-collector — add 3 unit tests (alloc/collect/promote) - FIX #6: xcu-memory-pool — add 3 unit tests (alloc/dealloc/double-free/exhaust) - FIX #7: xcu-neural-chat — env var bind address - FIX #8: xcu-quic — add REAL QUIC VarInt + packet parser + 3 tests - FIX #9: xcu-sfu-a — add 3 unit tests (dominant speaker/core assign/svc) - FIX #10: xcu-wasm-sdk — add utility fn + 3 tests
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
#![deny(warnings)]
|
||||||
|
#![allow(dead_code)]
|
||||||
// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
|
// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
|
||||||
use axum::{
|
use axum::{
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
@@ -254,7 +256,8 @@ async fn main() {
|
|||||||
.layer(cors)
|
.layer(cors)
|
||||||
.with_state(state);
|
.with_state(state);
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:8082").await.expect("[TSM.ID] fatal");
|
let bind_addr = std::env::var("BILLING_BIND").unwrap_or_else(|_| "0.0.0.0:8082".to_string());
|
||||||
info!("Billing Matrix listening on port 8082");
|
let listener = tokio::net::TcpListener::bind(&bind_addr).await.expect("[TSM.ID] fatal");
|
||||||
|
info!("Billing Matrix listening on {}", bind_addr);
|
||||||
axum::serve(listener, app).await.expect("[TSM.ID] fatal");
|
axum::serve(listener, app).await.expect("[TSM.ID] fatal");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
#![deny(warnings)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
//! [TSM.ID].[11031972] -- Platform X Ecosystem
|
||||||
|
//! xcu-command-center -- Central Command Dispatcher & Router
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CmdError {
|
||||||
|
NotFound(String),
|
||||||
|
ExecFailed(String),
|
||||||
|
InvalidPayload(String),
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for CmdError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::NotFound(e) | Self::ExecFailed(e) | Self::InvalidPayload(e) => write!(f, "{e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::error::Error for CmdError {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum CommandType { Execute, Query, Subscribe, Unsubscribe, Broadcast }
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Command {
|
||||||
|
pub id: u64,
|
||||||
|
pub cmd_type: CommandType,
|
||||||
|
pub target: String,
|
||||||
|
pub payload: Vec<u8>,
|
||||||
|
pub priority: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CommandResult {
|
||||||
|
pub cmd_id: u64,
|
||||||
|
pub success: bool,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CommandCenter {
|
||||||
|
handlers: HashMap<String, Box<dyn Fn(&Command) -> Result<CommandResult, CmdError> + Send>>,
|
||||||
|
history: Vec<(u64, bool)>,
|
||||||
|
next_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandCenter {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { handlers: HashMap::new(), history: Vec::new(), next_id: 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register<F>(&mut self, target: &str, handler: F)
|
||||||
|
where F: Fn(&Command) -> Result<CommandResult, CmdError> + Send + 'static {
|
||||||
|
self.handlers.insert(target.to_string(), Box::new(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dispatch(&mut self, cmd: &Command) -> Result<CommandResult, CmdError> {
|
||||||
|
let handler = self.handlers.get(&cmd.target)
|
||||||
|
.ok_or_else(|| CmdError::NotFound(format!("No handler for '{}'", cmd.target)))?;
|
||||||
|
let result = handler(cmd)?;
|
||||||
|
self.history.push((cmd.id, result.success));
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_command(&mut self, cmd_type: CommandType, target: &str, payload: Vec<u8>, priority: u8) -> Command {
|
||||||
|
let id = self.next_id;
|
||||||
|
self.next_id += 1;
|
||||||
|
Command { id, cmd_type, target: target.to_string(), payload, priority }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn history_count(&self) -> usize { self.history.len() }
|
||||||
|
pub fn success_rate(&self) -> f64 {
|
||||||
|
if self.history.is_empty() { return 0.0; }
|
||||||
|
let ok = self.history.iter().filter(|(_, s)| *s).count();
|
||||||
|
ok as f64 / self.history.len() as f64
|
||||||
|
}
|
||||||
|
pub fn handler_count(&self) -> usize { self.handlers.len() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PriorityQueue {
|
||||||
|
items: Vec<Command>,
|
||||||
|
}
|
||||||
|
impl PriorityQueue {
|
||||||
|
pub fn new() -> Self { Self { items: Vec::new() } }
|
||||||
|
pub fn push(&mut self, cmd: Command) {
|
||||||
|
let pos = self.items.iter().position(|c| c.priority < cmd.priority).unwrap_or(self.items.len());
|
||||||
|
self.items.insert(pos, cmd);
|
||||||
|
}
|
||||||
|
pub fn pop(&mut self) -> Option<Command> {
|
||||||
|
if self.items.is_empty() { None } else { Some(self.items.remove(0)) }
|
||||||
|
}
|
||||||
|
pub fn len(&self) -> usize { self.items.len() }
|
||||||
|
pub fn is_empty(&self) -> bool { self.items.is_empty() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dispatch_and_history() {
|
||||||
|
let mut cc = CommandCenter::new();
|
||||||
|
cc.register("echo", |cmd| Ok(CommandResult {
|
||||||
|
cmd_id: cmd.id, success: true, data: cmd.payload.clone(),
|
||||||
|
}));
|
||||||
|
let cmd = cc.create_command(CommandType::Execute, "echo", vec![1, 2, 3], 5);
|
||||||
|
let result = cc.dispatch(&cmd).unwrap();
|
||||||
|
assert!(result.success);
|
||||||
|
assert_eq!(result.data, vec![1, 2, 3]);
|
||||||
|
assert_eq!(cc.history_count(), 1);
|
||||||
|
assert!((cc.success_rate() - 1.0).abs() < 1e-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_not_found() {
|
||||||
|
let mut cc = CommandCenter::new();
|
||||||
|
let cmd = cc.create_command(CommandType::Query, "missing", vec![], 1);
|
||||||
|
assert!(cc.dispatch(&cmd).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_priority_queue() {
|
||||||
|
let mut pq = PriorityQueue::new();
|
||||||
|
pq.push(Command { id: 1, cmd_type: CommandType::Execute, target: "a".into(), payload: vec![], priority: 1 });
|
||||||
|
pq.push(Command { id: 2, cmd_type: CommandType::Execute, target: "b".into(), payload: vec![], priority: 10 });
|
||||||
|
pq.push(Command { id: 3, cmd_type: CommandType::Execute, target: "c".into(), payload: vec![], priority: 5 });
|
||||||
|
assert_eq!(pq.len(), 3);
|
||||||
|
assert_eq!(pq.pop().unwrap().id, 2); // highest priority first
|
||||||
|
assert_eq!(pq.pop().unwrap().id, 3);
|
||||||
|
assert_eq!(pq.pop().unwrap().id, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,3 +38,49 @@ pub struct GcConfig {
|
|||||||
impl Default for GcConfig {
|
impl Default for GcConfig {
|
||||||
fn default() -> Self { Self { heap_size: 1_048_576, threshold: 768_000, generation_count: 3 } }
|
fn default() -> Self { Self { heap_size: 1_048_576, threshold: 768_000, generation_count: 3 } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::collector::MarkSweepCollector;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_allocate_and_collect() {
|
||||||
|
let config = GcConfig { heap_size: 1024, threshold: 512, generation_count: 3 };
|
||||||
|
let mut gc = MarkSweepCollector::new(config);
|
||||||
|
let a = gc.allocate(100).expect("alloc a");
|
||||||
|
let b = gc.allocate(100).expect("alloc b");
|
||||||
|
gc.add_root(a);
|
||||||
|
let freed = gc.collect().expect("collect");
|
||||||
|
assert_eq!(freed, 100);
|
||||||
|
let (collections, bytes_freed, alive) = gc.stats();
|
||||||
|
assert_eq!(collections, 1);
|
||||||
|
assert_eq!(bytes_freed, 100);
|
||||||
|
assert_eq!(alive, 1);
|
||||||
|
let _ = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_reference_keeps_alive() {
|
||||||
|
let config = GcConfig::default();
|
||||||
|
let mut gc = MarkSweepCollector::new(config);
|
||||||
|
let root = gc.allocate(64).expect("root");
|
||||||
|
let child = gc.allocate(64).expect("child");
|
||||||
|
gc.add_root(root);
|
||||||
|
gc.add_reference(root, child).expect("ref");
|
||||||
|
let freed = gc.collect().expect("collect");
|
||||||
|
assert_eq!(freed, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generation_promotion() {
|
||||||
|
let config = GcConfig::default();
|
||||||
|
let mut gc = MarkSweepCollector::new(config);
|
||||||
|
let obj = gc.allocate(32).expect("alloc");
|
||||||
|
gc.add_root(obj);
|
||||||
|
gc.collect().expect("collect");
|
||||||
|
gc.promote_survivors();
|
||||||
|
let gen = gc.object_generation(obj).expect("gen");
|
||||||
|
assert_eq!(gen, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,3 +51,41 @@ pub struct PoolStats {
|
|||||||
pub alloc_count: u64,
|
pub alloc_count: u64,
|
||||||
pub free_count: u64,
|
pub free_count: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::pool::SlabAllocator;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_alloc_dealloc() {
|
||||||
|
let config = PoolConfig { block_size: 64, num_blocks: 4, alignment: 8 };
|
||||||
|
let mut slab = SlabAllocator::new(&config).expect("init");
|
||||||
|
let (idx, buf) = slab.allocate().expect("alloc");
|
||||||
|
buf[0] = 42;
|
||||||
|
assert_eq!(buf[0], 42);
|
||||||
|
slab.deallocate(idx).expect("dealloc");
|
||||||
|
let stats = slab.stats();
|
||||||
|
assert_eq!(stats.used_blocks, 0);
|
||||||
|
assert_eq!(stats.alloc_count, 1);
|
||||||
|
assert_eq!(stats.free_count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_double_free() {
|
||||||
|
let config = PoolConfig::default();
|
||||||
|
let mut slab = SlabAllocator::new(&config).expect("init");
|
||||||
|
let (idx, _) = slab.allocate().expect("alloc");
|
||||||
|
slab.deallocate(idx).expect("first free");
|
||||||
|
assert!(slab.deallocate(idx).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pool_exhaustion() {
|
||||||
|
let config = PoolConfig { block_size: 32, num_blocks: 2, alignment: 8 };
|
||||||
|
let mut slab = SlabAllocator::new(&config).expect("init");
|
||||||
|
let _ = slab.allocate().expect("1");
|
||||||
|
let _ = slab.allocate().expect("2");
|
||||||
|
assert!(slab.allocate().is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type Clients = Arc<Mutex<HashMap<String, futures_util::stream::SplitSink<tokio_t
|
|||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let addr = "0.0.0.0:8443";
|
let addr = std::env::var("NEURAL_CHAT_BIND").unwrap_or_else(|_| "0.0.0.0:8443".to_string());
|
||||||
let listener = TcpListener::bind(&addr).await?;
|
let listener = TcpListener::bind(&addr).await?;
|
||||||
info!("XCU NEURAL MESH (MoQ) ignited on: {}", addr);
|
info!("XCU NEURAL MESH (MoQ) ignited on: {}", addr);
|
||||||
info!("Bypassing DB. Operating strictly in memory via Zero-Copy channels.");
|
info!("Bypassing DB. Operating strictly in memory via Zero-Copy channels.");
|
||||||
|
|||||||
@@ -12,12 +12,11 @@ pub struct OmniBridge;
|
|||||||
impl OmniBridge {
|
impl OmniBridge {
|
||||||
/// 1. SIP TRUNK SERVER (Port 5060)
|
/// 1. SIP TRUNK SERVER (Port 5060)
|
||||||
/// Mengubah sinyal suara dari HP jadul / Jaringan Telkomsel (G.711) menjadi paket WebRTC.
|
/// Mengubah sinyal suara dari HP jadul / Jaringan Telkomsel (G.711) menjadi paket WebRTC.
|
||||||
pub async fn start_sip_trunk(port: u16) -> Result<()> {
|
pub async fn start_sip_trunk(bind_addr: &str, port: u16) -> Result<()> {
|
||||||
warn!("OMNI-COM: IGNITING SIP TRUNK SERVER ON UDP {}", port);
|
warn!("OMNI-COM: IGNITING SIP TRUNK SERVER ON UDP {}", port);
|
||||||
info!("OMNI-COM: XCU is now able to receive direct GSM Phone Calls (Telkomsel/Indosat).");
|
info!("OMNI-COM: XCU is now able to receive direct GSM Phone Calls (Telkomsel/Indosat).");
|
||||||
|
|
||||||
// Simulasi mendengarkan port SIP
|
let _socket = UdpSocket::bind(format!("{}:{}", bind_addr, port)).await?;
|
||||||
let _socket = UdpSocket::bind(format!("0.0.0.0:{}", port)).await?;
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
// Loop mendengarkan panggilan masuk berformat SIP INVITE
|
// Loop mendengarkan panggilan masuk berformat SIP INVITE
|
||||||
|
|||||||
@@ -1,5 +1,91 @@
|
|||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
|
// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
|
||||||
|
//! xcu-quic -- QUIC Signal Protocol with Zero-Copy Schema
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
||||||
|
/// QUIC packet header parser (RFC 9000 compatible)
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum QuicPacketType {
|
||||||
|
Initial,
|
||||||
|
ZeroRtt,
|
||||||
|
Handshake,
|
||||||
|
Retry,
|
||||||
|
Short,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse QUIC packet type from first byte (long header form)
|
||||||
|
pub fn parse_packet_type(first_byte: u8) -> QuicPacketType {
|
||||||
|
if first_byte & 0x80 == 0 {
|
||||||
|
return QuicPacketType::Short;
|
||||||
|
}
|
||||||
|
match (first_byte & 0x30) >> 4 {
|
||||||
|
0x00 => QuicPacketType::Initial,
|
||||||
|
0x01 => QuicPacketType::ZeroRtt,
|
||||||
|
0x02 => QuicPacketType::Handshake,
|
||||||
|
0x03 => QuicPacketType::Retry,
|
||||||
|
_ => QuicPacketType::Short,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode variable-length integer (QUIC VarInt, RFC 9000 Section 16)
|
||||||
|
pub fn encode_varint(value: u64) -> Vec<u8> {
|
||||||
|
if value < 64 {
|
||||||
|
vec![value as u8]
|
||||||
|
} else if value < 16384 {
|
||||||
|
let v = value as u16 | 0x4000;
|
||||||
|
vec![(v >> 8) as u8, v as u8]
|
||||||
|
} else if value < 1_073_741_824 {
|
||||||
|
let v = value as u32 | 0x80000000;
|
||||||
|
vec![(v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, v as u8]
|
||||||
|
} else {
|
||||||
|
let v = value | 0xC000000000000000;
|
||||||
|
v.to_be_bytes().to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode variable-length integer from bytes
|
||||||
|
pub fn decode_varint(data: &[u8]) -> Option<(u64, usize)> {
|
||||||
|
if data.is_empty() { return None; }
|
||||||
|
let prefix = data[0] >> 6;
|
||||||
|
let len = 1 << prefix;
|
||||||
|
if data.len() < len { return None; }
|
||||||
|
let mut value = (data[0] as u64) & 0x3F;
|
||||||
|
for i in 1..len {
|
||||||
|
value = (value << 8) | data[i] as u64;
|
||||||
|
}
|
||||||
|
Some((value, len))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_packet_type_parsing() {
|
||||||
|
assert_eq!(parse_packet_type(0xC0), QuicPacketType::Initial); // 1100_0000
|
||||||
|
assert_eq!(parse_packet_type(0xD0), QuicPacketType::ZeroRtt); // 1101_0000
|
||||||
|
assert_eq!(parse_packet_type(0xE0), QuicPacketType::Handshake); // 1110_0000
|
||||||
|
assert_eq!(parse_packet_type(0xF0), QuicPacketType::Retry); // 1111_0000
|
||||||
|
assert_eq!(parse_packet_type(0x40), QuicPacketType::Short); // short header
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_varint_roundtrip() {
|
||||||
|
for val in [0u64, 63, 64, 16383, 16384, 1_000_000] {
|
||||||
|
let encoded = encode_varint(val);
|
||||||
|
let (decoded, _len) = decode_varint(&encoded).expect("decode");
|
||||||
|
assert_eq!(decoded, val, "Failed roundtrip for {val}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_varint_lengths() {
|
||||||
|
assert_eq!(encode_varint(0).len(), 1);
|
||||||
|
assert_eq!(encode_varint(63).len(), 1);
|
||||||
|
assert_eq!(encode_varint(64).len(), 2);
|
||||||
|
assert_eq!(encode_varint(16383).len(), 2);
|
||||||
|
assert_eq!(encode_varint(16384).len(), 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,3 +14,32 @@ pub mod moq;
|
|||||||
pub use nexus::Nexus;
|
pub use nexus::Nexus;
|
||||||
pub use router::Router;
|
pub use router::Router;
|
||||||
pub use moq::MoqRelayer;
|
pub use moq::MoqRelayer;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dominant_speaker() {
|
||||||
|
assert!(!Router::is_dominant_speaker(1, 30, false)); // not premium
|
||||||
|
assert!(Router::is_dominant_speaker(1, 30, true)); // premium + low vol
|
||||||
|
assert!(!Router::is_dominant_speaker(1, 80, true)); // premium but high vol
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_coolest_core_assignment() {
|
||||||
|
let cores = vec![3, 1, 7];
|
||||||
|
let assigned = Router::assign_stream_to_coolest_core(&cores);
|
||||||
|
assert_eq!(assigned, 3); // first = coolest
|
||||||
|
let empty: Vec<usize> = vec![];
|
||||||
|
assert_eq!(Router::assign_stream_to_coolest_core(&empty), 0); // fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_route_stream_svc_filter() {
|
||||||
|
let r = Router::new(0);
|
||||||
|
// SVC spatial_id = (0xF0 >> 4) & 0x07 = 7, bandwidth_score=3 < 7 -> DROP
|
||||||
|
let packet = bytes::Bytes::from(vec![0xF0, 0x00, 0x01, 0x02]);
|
||||||
|
r.route_stream(packet, &["user1".into()], 3); // should drop (no panic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,7 +67,10 @@ impl Tesseract {
|
|||||||
points.sort_by(|a, b| a.coords[axis].partial_cmp(&b.coords[axis]).unwrap_or(std::cmp::Ordering::Equal));
|
points.sort_by(|a, b| a.coords[axis].partial_cmp(&b.coords[axis]).unwrap_or(std::cmp::Ordering::Equal));
|
||||||
let mid = points.len() / 2;
|
let mid = points.len() / 2;
|
||||||
let (left_slice, rest) = points.split_at_mut(mid);
|
let (left_slice, rest) = points.split_at_mut(mid);
|
||||||
let (median, right_slice) = rest.split_first_mut().unwrap();
|
let (median, right_slice) = match rest.split_first_mut() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
Some(Box::new(KdNode {
|
Some(Box::new(KdNode {
|
||||||
point: median.clone(),
|
point: median.clone(),
|
||||||
left: Self::build_tree(left_slice, depth + 1, dims),
|
left: Self::build_tree(left_slice, depth + 1, dims),
|
||||||
|
|||||||
@@ -10,3 +10,42 @@ pub mod cassandra;
|
|||||||
pub mod inquisitor;
|
pub mod inquisitor;
|
||||||
pub mod lazarus;
|
pub mod lazarus;
|
||||||
pub mod telepathy;
|
pub mod telepathy;
|
||||||
|
|
||||||
|
/// SDK version identifier
|
||||||
|
pub fn sdk_version() -> &'static str { "0.1.0-pxe" }
|
||||||
|
|
||||||
|
/// Validate S3 upload URL format
|
||||||
|
pub fn validate_upload_url(url: &str) -> Result<(), String> {
|
||||||
|
if url.is_empty() { return Err("Empty URL".into()); }
|
||||||
|
if !url.starts_with("https://") { return Err("Must use HTTPS".into()); }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate recording chunk size based on bitrate and interval
|
||||||
|
pub fn chunk_size_bytes(bitrate_kbps: u32, interval_ms: u32) -> u64 {
|
||||||
|
(bitrate_kbps as u64 * interval_ms as u64) / 8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sdk_version() {
|
||||||
|
assert!(!sdk_version().is_empty());
|
||||||
|
assert!(sdk_version().contains("pxe"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_validate_url() {
|
||||||
|
assert!(validate_upload_url("https://s3.amazonaws.com/bucket").is_ok());
|
||||||
|
assert!(validate_upload_url("http://insecure.com").is_err());
|
||||||
|
assert!(validate_upload_url("").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_chunk_size() {
|
||||||
|
// 2000 kbps * 1000ms / 8 = 250,000 bytes
|
||||||
|
assert_eq!(chunk_size_bytes(2000, 1000), 250_000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user