synor/crates/synor-compute/src/device/mod.rs
Gulshan Yadav 7e3bbe569c fix: implement incomplete features and apply linter fixes
- Fixed TransferDirection import error in ethereum.rs tests
- Implemented math.tanh function for Flutter tensor operations
- Added DocumentStore CRUD methods (find_by_id, update_by_id, delete_by_id)
- Implemented database gateway handlers (get/update/delete document)
- Applied cargo fix across all crates to resolve unused imports/variables
- Reduced warnings from 320+ to 68 (remaining are architectural)

Affected crates: synor-database, synor-bridge, synor-compute,
synor-privacy, synor-verifier, synor-hosting, synor-economics
2026-01-26 21:43:51 +05:30

377 lines
10 KiB
Rust

//! Device registry and management.
//!
//! Supports all device types:
//! - Data center servers
//! - Desktop workstations
//! - Laptops
//! - Mobile devices (iOS, Android)
//! - Browsers (WebGPU, WASM)
//! - IoT devices
use crate::error::ComputeError;
use crate::processor::{GenericProcessor, Processor, ProcessorId, ProcessorType};
use crate::{NodeId, ProcessorInfo};
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
/// Unique device identifier.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DeviceId(pub [u8; 32]);
impl DeviceId {
/// Creates a new random device ID.
pub fn new() -> Self {
use rand::Rng;
let mut bytes = [0u8; 32];
rand::thread_rng().fill(&mut bytes);
DeviceId(bytes)
}
/// Creates from bytes.
pub fn from_bytes(bytes: [u8; 32]) -> Self {
DeviceId(bytes)
}
}
impl Default for DeviceId {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Display for DeviceId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "dev_{}", hex::encode(&self.0[..8]))
}
}
/// Device type classification.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum DeviceType {
/// Data center server.
DataCenter,
/// Desktop workstation.
Desktop,
/// Laptop.
Laptop,
/// Mobile phone.
Mobile,
/// Tablet.
Tablet,
/// IoT device.
IoT,
/// Browser (WebGPU/WASM).
Browser,
/// Edge server.
Edge,
}
impl DeviceType {
/// Returns typical reliability score (0-100).
pub fn reliability(&self) -> u32 {
match self {
DeviceType::DataCenter => 99,
DeviceType::Edge => 95,
DeviceType::Desktop => 80,
DeviceType::Laptop => 60,
DeviceType::Mobile => 40,
DeviceType::Tablet => 50,
DeviceType::IoT => 70,
DeviceType::Browser => 30,
}
}
/// Returns typical availability hours per day.
pub fn availability_hours(&self) -> f32 {
match self {
DeviceType::DataCenter => 24.0,
DeviceType::Edge => 24.0,
DeviceType::Desktop => 8.0,
DeviceType::Laptop => 6.0,
DeviceType::Mobile => 4.0,
DeviceType::Tablet => 4.0,
DeviceType::IoT => 24.0,
DeviceType::Browser => 2.0,
}
}
}
/// Device capabilities.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DeviceCapabilities {
/// Device type.
pub device_type: DeviceType,
/// Available processors.
pub processors: Vec<ProcessorType>,
/// Total memory (GB).
pub memory_gb: f32,
/// Network bandwidth (Mbps).
pub bandwidth_mbps: f32,
/// Storage available (GB).
pub storage_gb: f32,
/// Battery powered.
pub battery_powered: bool,
/// Supports background execution.
pub background_execution: bool,
}
/// Device information.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DeviceInfo {
/// Device ID.
pub id: DeviceId,
/// Device type.
pub device_type: DeviceType,
/// Owner address.
pub owner: [u8; 32],
/// Capabilities.
pub capabilities: DeviceCapabilities,
/// Current status.
pub status: DeviceStatus,
/// Reputation score (0-100).
pub reputation: u32,
/// Total earnings (atomic SYNOR).
pub earnings: u64,
/// Geographic region.
pub region: String,
}
/// Device status.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum DeviceStatus {
/// Online and available.
Online,
/// Online but busy.
Busy,
/// Idle but available.
Idle,
/// On battery (reduced capacity).
OnBattery,
/// Offline.
Offline,
/// Maintenance.
Maintenance,
}
/// Device registry managing all devices and processors.
pub struct DeviceRegistry {
/// Registered devices.
devices: RwLock<HashMap<DeviceId, DeviceInfo>>,
/// Node to device mapping.
node_devices: RwLock<HashMap<NodeId, Vec<DeviceId>>>,
/// All processors (across all nodes).
processors: RwLock<HashMap<ProcessorId, Arc<dyn Processor>>>,
/// Processor to node mapping.
processor_nodes: RwLock<HashMap<ProcessorId, NodeId>>,
/// Next processor ID.
next_processor_id: std::sync::atomic::AtomicU64,
}
impl DeviceRegistry {
/// Creates a new device registry.
pub fn new() -> Self {
Self {
devices: RwLock::new(HashMap::new()),
node_devices: RwLock::new(HashMap::new()),
processors: RwLock::new(HashMap::new()),
processor_nodes: RwLock::new(HashMap::new()),
next_processor_id: std::sync::atomic::AtomicU64::new(0),
}
}
/// Registers a device.
pub fn register_device(&self, device: DeviceInfo) -> Result<DeviceId, ComputeError> {
let id = device.id;
self.devices.write().insert(id, device);
Ok(id)
}
/// Unregisters a device.
pub fn unregister_device(&self, device_id: DeviceId) -> Result<(), ComputeError> {
self.devices.write().remove(&device_id);
Ok(())
}
/// Gets a device by ID.
pub fn get_device(&self, device_id: DeviceId) -> Option<DeviceInfo> {
self.devices.read().get(&device_id).cloned()
}
/// Registers a processor for a node.
pub fn register_processor(
&self,
node_id: NodeId,
info: ProcessorInfo,
) -> Result<(), ComputeError> {
let processor_id = info.id;
// Create a generic processor from the info
let processor: Arc<dyn Processor> = Arc::new(GenericProcessor::new(
processor_id,
info.processor_type,
info.capabilities,
));
self.processors.write().insert(processor_id, processor);
self.processor_nodes.write().insert(processor_id, node_id);
Ok(())
}
/// Unregisters all processors for a node.
pub fn unregister_node(&self, node_id: NodeId) -> Result<(), ComputeError> {
let mut processors = self.processors.write();
let mut processor_nodes = self.processor_nodes.write();
// Find and remove all processors for this node
let to_remove: Vec<_> = processor_nodes
.iter()
.filter(|(_, n)| **n == node_id)
.map(|(p, _)| *p)
.collect();
for proc_id in to_remove {
processors.remove(&proc_id);
processor_nodes.remove(&proc_id);
}
Ok(())
}
/// Gets a processor by ID.
pub fn get_processor(&self, processor_id: ProcessorId) -> Result<Arc<dyn Processor>, ComputeError> {
self.processors
.read()
.get(&processor_id)
.cloned()
.ok_or(ComputeError::ProcessorNotFound(processor_id))
}
/// Gets all processors.
pub fn all_processors(&self) -> Vec<Arc<dyn Processor>> {
self.processors.read().values().cloned().collect()
}
/// Gets processors of a specific type.
pub fn processors_by_type(&self, proc_type: ProcessorType) -> Vec<Arc<dyn Processor>> {
self.processors
.read()
.values()
.filter(|p| p.processor_type() == proc_type)
.cloned()
.collect()
}
/// Gets the next processor ID.
pub fn next_processor_id(&self) -> ProcessorId {
ProcessorId(self.next_processor_id.fetch_add(1, std::sync::atomic::Ordering::SeqCst))
}
/// Gets total number of devices.
pub fn device_count(&self) -> usize {
self.devices.read().len()
}
/// Gets total number of processors.
pub fn processor_count(&self) -> usize {
self.processors.read().len()
}
/// Gets devices by type.
pub fn devices_by_type(&self, device_type: DeviceType) -> Vec<DeviceInfo> {
self.devices
.read()
.values()
.filter(|d| d.device_type == device_type)
.cloned()
.collect()
}
/// Gets online devices.
pub fn online_devices(&self) -> Vec<DeviceInfo> {
self.devices
.read()
.values()
.filter(|d| d.status == DeviceStatus::Online || d.status == DeviceStatus::Idle)
.cloned()
.collect()
}
/// Updates device status.
pub fn update_device_status(
&self,
device_id: DeviceId,
status: DeviceStatus,
) -> Result<(), ComputeError> {
if let Some(device) = self.devices.write().get_mut(&device_id) {
device.status = status;
Ok(())
} else {
Err(ComputeError::Internal(format!("Device not found: {}", device_id)))
}
}
}
impl Default for DeviceRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::processor::{CpuVariant, AvxSupport};
#[test]
fn test_device_id() {
let id1 = DeviceId::new();
let id2 = DeviceId::new();
assert_ne!(id1.0, id2.0);
}
#[test]
fn test_device_registry() {
let registry = DeviceRegistry::new();
let device = DeviceInfo {
id: DeviceId::new(),
device_type: DeviceType::Desktop,
owner: [1u8; 32],
capabilities: DeviceCapabilities {
device_type: DeviceType::Desktop,
processors: vec![ProcessorType::Cpu(CpuVariant::X86_64 {
avx: AvxSupport::Avx512,
})],
memory_gb: 64.0,
bandwidth_mbps: 1000.0,
storage_gb: 1000.0,
battery_powered: false,
background_execution: true,
},
status: DeviceStatus::Online,
reputation: 100,
earnings: 0,
region: "us-east".to_string(),
};
let device_id = device.id;
registry.register_device(device).unwrap();
assert_eq!(registry.device_count(), 1);
assert!(registry.get_device(device_id).is_some());
registry.unregister_device(device_id).unwrap();
assert_eq!(registry.device_count(), 0);
}
#[test]
fn test_device_type_properties() {
assert_eq!(DeviceType::DataCenter.reliability(), 99);
assert_eq!(DeviceType::Mobile.reliability(), 40);
assert_eq!(DeviceType::DataCenter.availability_hours(), 24.0);
assert_eq!(DeviceType::Browser.availability_hours(), 2.0);
}
}