diff --git a/src/services/resource_provider.rs b/src/services/resource_provider.rs index ad24765..ee94fc4 100644 --- a/src/services/resource_provider.rs +++ b/src/services/resource_provider.rs @@ -1301,25 +1301,83 @@ impl ResourceProviderService { // Fetch node data from grid let grid_data = self.grid_service.fetch_node_data(grid_node_id).await?; - // Create FarmNode from grid data - let node = FarmNodeBuilder::new() - .id(format!("grid_node_{}", grid_node_id)) - .name(format!("Grid Node {}", grid_node_id)) - .location(format!("{}, {}", - if grid_data.city.is_empty() { "Unknown City" } else { &grid_data.city }, - if grid_data.country.is_empty() { "Unknown Country" } else { &grid_data.country } - )) - .status(NodeStatus::Online) - .capacity(grid_data.total_resources.clone()) - .used_capacity(grid_data.used_resources.clone()) - .uptime_percentage(99.0) // Default uptime - .earnings_today_usd(Decimal::ZERO) - .health_score(100.0) - .region(if grid_data.country.is_empty() { "Unknown".to_string() } else { grid_data.country.clone() }) - .node_type("MyceliumNode".to_string()) - .grid_node_id(grid_node_id) - .grid_data(grid_data) - .build()?; + // FIX: Calculate slice data using the slice calculator + let total_base_slices = self.slice_calculator.calculate_max_base_slices(&grid_data.total_resources); + + // Generate unique node ID for SLA + let node_id = format!("grid_node_{}", grid_node_id); + let node_id_for_sla = node_id.clone(); + + // Create FarmNode from grid data with proper slice calculations + let mut node = FarmNode { + id: node_id, + name: if grid_data.farm_name.is_empty() { format!("Grid Node {}", grid_node_id) } else { grid_data.farm_name.clone() }, + location: { + let city = if grid_data.city.is_empty() { "Unknown" } else { &grid_data.city }; + let country = if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country }; + if city == "Unknown" { + country.to_string() + } else { + format!("{}, {}", city, country) + } + }, + status: NodeStatus::Online, // Assume online if we can fetch from grid + capacity: grid_data.total_resources.clone(), + used_capacity: grid_data.used_resources.clone(), + uptime_percentage: 99.8, // Clean uptime value for grid nodes + farming_start_date: Utc::now() - chrono::Duration::days(30), // Default farming start + last_updated: grid_data.last_updated, + last_seen: Some(Utc::now()), + health_score: 98.5, + utilization_7_day_avg: 65.0, // Default utilization + slice_formats_supported: vec!["1x1".to_string(), "2x2".to_string(), "4x4".to_string()], + rental_options: None, + earnings_today_usd: Decimal::ZERO, + region: if grid_data.country.is_empty() { "Unknown".to_string() } else { grid_data.country.clone() }, + node_type: "MyceliumNode".to_string(), + slice_formats: None, // Not used in new slice system + staking_options: None, + availability_status: crate::models::user::NodeAvailabilityStatus::Available, + grid_node_id: Some(grid_node_id.to_string()), + grid_data: Some(serde_json::to_value(&grid_data).unwrap_or_default()), + node_group_id: None, + group_assignment_date: None, + group_slice_format: None, + group_slice_price: None, + + // FIX: Marketplace SLA field with clean uptime value + marketplace_sla: Some(MarketplaceSLA { + id: format!("sla-{}", node_id_for_sla), + name: "Standard Marketplace SLA".to_string(), + uptime_guarantee: 99.8, + response_time_hours: 24, + resolution_time_hours: 48, + penalty_rate: 0.01, + uptime_guarantee_percentage: 99.8, + bandwidth_guarantee_mbps: grid_data.total_resources.bandwidth_mbps as f32, + base_slice_price: SlicePricing::default().base_price_per_hour, + last_updated: Utc::now(), + }), + + // FIX: Automatic slice management fields + total_base_slices: total_base_slices as i32, + allocated_base_slices: 0, + slice_allocations: Vec::new(), + available_combinations: Vec::new(), // Will be calculated below + slice_pricing: Some(serde_json::to_value(&SlicePricing::default()).unwrap_or_default()), + slice_last_calculated: Some(Utc::now()), + }; + + // FIX: Generate initial slice combinations + let combinations = self.slice_calculator.generate_slice_combinations( + node.total_base_slices as u32, + node.allocated_base_slices as u32, + &node, + user_email + ); + node.available_combinations = combinations.iter() + .map(|c| serde_json::to_value(c).unwrap_or_default()) + .collect(); // Save to persistent storage let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email); @@ -1356,26 +1414,82 @@ impl ResourceProviderService { } let grid_data = self.grid_service.fetch_node_data(grid_node_id).await.map_err(|e| e.to_string())?; - // Build node - let node = FarmNodeBuilder::new() - .id(node_id) - .name(format!("Grid Node {}", grid_node_id)) - .location(format!("{}, {}", - if grid_data.city.is_empty() { "Unknown City" } else { &grid_data.city }, - if grid_data.country.is_empty() { "Unknown Country" } else { &grid_data.country } - )) - .status(NodeStatus::Online) - .capacity(grid_data.total_resources.clone()) - .used_capacity(grid_data.used_resources.clone()) - .uptime_percentage(99.0) - .earnings_today_usd(Decimal::ZERO) - .health_score(100.0) - .region(if grid_data.country.is_empty() { "Unknown".to_string() } else { grid_data.country.clone() }) - .node_type("MyceliumNode".to_string()) - .grid_node_id(grid_node_id) - .grid_data(grid_data) - .build() - .map_err(|e| e.to_string())?; + // FIX: Calculate slice data using the slice calculator (same as add_node_from_grid) + let total_base_slices = self.slice_calculator.calculate_max_base_slices(&grid_data.total_resources); + + // Generate unique node ID for SLA + let node_id_for_sla = node_id.clone(); + + // Build node with proper slice calculations + let mut node = FarmNode { + id: node_id, + name: if grid_data.farm_name.is_empty() { format!("Grid Node {}", grid_node_id) } else { grid_data.farm_name.clone() }, + location: { + let city = if grid_data.city.is_empty() { "Unknown" } else { &grid_data.city }; + let country = if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country }; + if city == "Unknown" { + country.to_string() + } else { + format!("{}, {}", city, country) + } + }, + status: NodeStatus::Online, // Assume online if we can fetch from grid + capacity: grid_data.total_resources.clone(), + used_capacity: grid_data.used_resources.clone(), + uptime_percentage: 99.8, // Clean uptime value for grid nodes + farming_start_date: Utc::now() - chrono::Duration::days(30), // Default farming start + last_updated: grid_data.last_updated, + last_seen: Some(Utc::now()), + health_score: 98.5, + utilization_7_day_avg: 65.0, // Default utilization + slice_formats_supported: vec!["1x1".to_string(), "2x2".to_string(), "4x4".to_string()], + rental_options: None, + earnings_today_usd: Decimal::ZERO, + region: if grid_data.country.is_empty() { "Unknown".to_string() } else { grid_data.country.clone() }, + node_type: "MyceliumNode".to_string(), + slice_formats: None, // Not used in new slice system + staking_options: None, + availability_status: crate::models::user::NodeAvailabilityStatus::Available, + grid_node_id: Some(grid_node_id.to_string()), + grid_data: Some(serde_json::to_value(&grid_data).unwrap_or_default()), + node_group_id: None, + group_assignment_date: None, + group_slice_format: None, + group_slice_price: None, + + // FIX: Marketplace SLA field with clean uptime value + marketplace_sla: Some(MarketplaceSLA { + id: format!("sla-{}", node_id_for_sla), + name: "Standard Marketplace SLA".to_string(), + uptime_guarantee: 99.8, + response_time_hours: 24, + resolution_time_hours: 48, + penalty_rate: 0.01, + uptime_guarantee_percentage: 99.8, + bandwidth_guarantee_mbps: grid_data.total_resources.bandwidth_mbps as f32, + base_slice_price: SlicePricing::default().base_price_per_hour, + last_updated: Utc::now(), + }), + + // FIX: Automatic slice management fields + total_base_slices: total_base_slices as i32, + allocated_base_slices: 0, + slice_allocations: Vec::new(), + available_combinations: Vec::new(), // Will be calculated below + slice_pricing: Some(serde_json::to_value(&SlicePricing::default()).unwrap_or_default()), + slice_last_calculated: Some(Utc::now()), + }; + + // FIX: Generate initial slice combinations + let combinations = self.slice_calculator.generate_slice_combinations( + node.total_base_slices as u32, + node.allocated_base_slices as u32, + &node, + user_email + ); + node.available_combinations = combinations.iter() + .map(|c| serde_json::to_value(c).unwrap_or_default()) + .collect(); persistent_data.nodes.push(node.clone()); added_nodes.push(node); @@ -1472,6 +1586,50 @@ impl ResourceProviderService { // Apply slice formats if provided if !slice_formats.is_empty() { node.slice_formats = Some(slice_formats.clone()); } + // FIX: Calculate and set slice data + let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node.capacity); + node.total_base_slices = total_base_slices as i32; + node.allocated_base_slices = 0; + node.slice_allocations = Vec::new(); + + // Generate slice combinations + let combinations = self.slice_calculator.generate_slice_combinations( + total_base_slices, + 0, // No allocated slices yet + &node, + user_email + ); + node.available_combinations = combinations.iter() + .map(|c| serde_json::to_value(c).unwrap_or_default()) + .collect(); + node.slice_last_calculated = Some(Utc::now()); + + // Set marketplace SLA if not already set + if node.marketplace_sla.is_none() { + node.marketplace_sla = Some(MarketplaceSLA { + id: format!("sla-{}", node.id), + name: "Standard Marketplace SLA".to_string(), + uptime_guarantee: 99.8, + response_time_hours: 24, + resolution_time_hours: 48, + penalty_rate: 0.01, + uptime_guarantee_percentage: 99.8, + bandwidth_guarantee_mbps: node.capacity.bandwidth_mbps as f32, + base_slice_price: SlicePricing::default().base_price_per_hour, + last_updated: Utc::now(), + }); + } + + // Set default slice pricing if not already set + if node.slice_pricing.is_none() { + let default_pricing = SlicePricing { + base_price_per_hour: rust_decimal::Decimal::try_from(0.50).unwrap_or_default(), + currency: "USD".to_string(), + pricing_multiplier: rust_decimal::Decimal::from(1), + }; + node.slice_pricing = Some(serde_json::to_value(&default_pricing).unwrap_or_default()); + } + persistent_data.nodes.push(node.clone()); added_nodes.push(node); } @@ -1554,6 +1712,34 @@ impl ResourceProviderService { node.slice_formats = Some(slice_formats.clone()); } + // SLICE CALCULATION FIX: Calculate and set slice data + let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node.capacity); + node.total_base_slices = total_base_slices as i32; + node.allocated_base_slices = 0; + node.slice_allocations = Vec::new(); + + // Generate slice combinations + let combinations = self.slice_calculator.generate_slice_combinations( + total_base_slices, + 0, // No allocated slices yet + &node, + user_email + ); + node.available_combinations = combinations.iter() + .map(|c| serde_json::to_value(c).unwrap_or_default()) + .collect(); + node.slice_last_calculated = Some(Utc::now()); + + // Set default slice pricing if not already set + if node.slice_pricing.is_none() { + let default_pricing = crate::services::slice_calculator::SlicePricing { + base_price_per_hour: rust_decimal::Decimal::try_from(0.50).unwrap_or_default(), + currency: "USD".to_string(), + pricing_multiplier: rust_decimal::Decimal::from(1), + }; + node.slice_pricing = Some(serde_json::to_value(&default_pricing).unwrap_or_default()); + } + // Push to in-memory and batch list persistent_data.nodes.push(node.clone()); added_nodes.push(node); @@ -1654,6 +1840,34 @@ impl ResourceProviderService { node.slice_formats = Some(slice_formats.clone()); } + // SLICE CALCULATION FIX: Calculate and set slice data for individual pricing method + let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node.capacity); + node.total_base_slices = total_base_slices as i32; + node.allocated_base_slices = 0; + node.slice_allocations = Vec::new(); + + // Generate slice combinations + let combinations = self.slice_calculator.generate_slice_combinations( + total_base_slices, + 0, // No allocated slices yet + &node, + user_email + ); + node.available_combinations = combinations.iter() + .map(|c| serde_json::to_value(c).unwrap_or_default()) + .collect(); + node.slice_last_calculated = Some(Utc::now()); + + // Set default slice pricing if not already set + if node.slice_pricing.is_none() { + let default_pricing = crate::services::slice_calculator::SlicePricing { + base_price_per_hour: rust_decimal::Decimal::try_from(0.50).unwrap_or_default(), + currency: "USD".to_string(), + pricing_multiplier: rust_decimal::Decimal::from(1), + }; + node.slice_pricing = Some(serde_json::to_value(&default_pricing).unwrap_or_default()); + } + persistent_data.nodes.push(node.clone()); added_nodes.push(node); } @@ -1721,6 +1935,50 @@ impl ResourceProviderService { node.slice_formats = Some(slice_formats); } + // FIX: Calculate and set slice data + let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node.capacity); + node.total_base_slices = total_base_slices as i32; + node.allocated_base_slices = 0; + node.slice_allocations = Vec::new(); + + // Generate slice combinations + let combinations = self.slice_calculator.generate_slice_combinations( + total_base_slices, + 0, // No allocated slices yet + &node, + user_email + ); + node.available_combinations = combinations.iter() + .map(|c| serde_json::to_value(c).unwrap_or_default()) + .collect(); + node.slice_last_calculated = Some(Utc::now()); + + // Set marketplace SLA if not already set + if node.marketplace_sla.is_none() { + node.marketplace_sla = Some(MarketplaceSLA { + id: format!("sla-{}", node.id), + name: "Standard Marketplace SLA".to_string(), + uptime_guarantee: 99.8, + response_time_hours: 24, + resolution_time_hours: 48, + penalty_rate: 0.01, + uptime_guarantee_percentage: 99.8, + bandwidth_guarantee_mbps: node.capacity.bandwidth_mbps as f32, + base_slice_price: SlicePricing::default().base_price_per_hour, + last_updated: Utc::now(), + }); + } + + // Set default slice pricing if not already set + if node.slice_pricing.is_none() { + let default_pricing = SlicePricing { + base_price_per_hour: rust_decimal::Decimal::try_from(0.50).unwrap_or_default(), + currency: "USD".to_string(), + pricing_multiplier: rust_decimal::Decimal::from(1), + }; + node.slice_pricing = Some(serde_json::to_value(&default_pricing).unwrap_or_default()); + } + // Add node to user's data let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email); @@ -1767,41 +2025,53 @@ impl ResourceProviderService { None }; - // Create the node - let node = FarmNode { - id: format!("grid_node_{}", grid_node_id), - name: format!("Grid Node {}", grid_node_id), - location: format!("{}, {}", - if grid_data.city.is_empty() { "Unknown" } else { &grid_data.city }, - if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country } - ), + // FIX: Calculate slice data using the slice calculator + let node_capacity = crate::models::user::NodeCapacity { + cpu_cores: grid_data.total_resources.cpu_cores, + memory_gb: grid_data.total_resources.memory_gb, + storage_gb: grid_data.total_resources.storage_gb, + bandwidth_mbps: grid_data.total_resources.bandwidth_mbps, + ssd_storage_gb: grid_data.total_resources.ssd_storage_gb, + hdd_storage_gb: grid_data.total_resources.hdd_storage_gb, + ram_gb: grid_data.total_resources.ram_gb, + }; + + let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node_capacity); + let node_id = format!("grid_node_{}", grid_node_id); + let bandwidth_mbps = node_capacity.bandwidth_mbps; // Store before move + + // Create the node with proper slice calculations + let mut node = FarmNode { + id: node_id.clone(), + name: if grid_data.farm_name.is_empty() { format!("Grid Node {}", grid_node_id) } else { grid_data.farm_name.clone() }, + location: { + let city = if grid_data.city.is_empty() { "Unknown" } else { &grid_data.city }; + let country = if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country }; + if city == "Unknown" { + country.to_string() + } else { + format!("{}, {}", city, country) + } + }, status: crate::models::user::NodeStatus::Online, - capacity: crate::models::user::NodeCapacity { - cpu_cores: grid_data.total_resources.cpu_cores, - memory_gb: grid_data.total_resources.memory_gb, - storage_gb: grid_data.total_resources.storage_gb, - bandwidth_mbps: grid_data.total_resources.bandwidth_mbps, - ssd_storage_gb: grid_data.total_resources.ssd_storage_gb, - hdd_storage_gb: grid_data.total_resources.hdd_storage_gb, - ram_gb: grid_data.total_resources.ram_gb, - }, + capacity: node_capacity, used_capacity: crate::models::user::NodeCapacity { - cpu_cores: 0, - memory_gb: 0, - storage_gb: 0, - bandwidth_mbps: 0, - ssd_storage_gb: 0, - hdd_storage_gb: 0, - ram_gb: 0, + cpu_cores: grid_data.used_resources.cpu_cores, + memory_gb: grid_data.used_resources.memory_gb, + storage_gb: grid_data.used_resources.storage_gb, + bandwidth_mbps: grid_data.used_resources.bandwidth_mbps, + ssd_storage_gb: grid_data.used_resources.ssd_storage_gb, + hdd_storage_gb: grid_data.used_resources.hdd_storage_gb, + ram_gb: grid_data.used_resources.ram_gb, }, - uptime_percentage: 99.0, + uptime_percentage: 99.8, // Clean uptime value for grid nodes farming_start_date: grid_data.last_updated, last_updated: grid_data.last_updated, - utilization_7_day_avg: 0.0, - slice_formats_supported: if slice_formats.is_empty() { Vec::new() } else { slice_formats.clone() }, + utilization_7_day_avg: 65.0, // Default utilization + slice_formats_supported: if slice_formats.is_empty() { vec!["1x1".to_string(), "2x2".to_string(), "4x4".to_string()] } else { slice_formats.clone() }, earnings_today_usd: Decimal::ZERO, last_seen: Some(Utc::now()), - health_score: 100.0, + health_score: 98.5, region: if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country }.to_string(), node_type: "MyceliumNode".to_string(), slice_formats: if slice_formats.is_empty() { None } else { Some(slice_formats.clone()) }, @@ -1815,17 +2085,40 @@ impl ResourceProviderService { group_slice_format: None, group_slice_price: None, - // NEW: Marketplace SLA field (None for basic grid nodes) - marketplace_sla: None, + // FIX: Marketplace SLA field with proper data + marketplace_sla: Some(MarketplaceSLA { + id: format!("sla-{}", node_id), + name: "Standard Marketplace SLA".to_string(), + uptime_guarantee: 99.8, + response_time_hours: 24, + resolution_time_hours: 48, + penalty_rate: 0.01, + uptime_guarantee_percentage: 99.8, + bandwidth_guarantee_mbps: bandwidth_mbps as f32, + base_slice_price: SlicePricing::default().base_price_per_hour, + last_updated: Utc::now(), + }), - total_base_slices: 0, + // FIX: Automatic slice management fields with proper calculations + total_base_slices: total_base_slices as i32, allocated_base_slices: 0, slice_allocations: Vec::new(), - available_combinations: Vec::new(), - slice_pricing: Some(serde_json::to_value(&crate::services::slice_calculator::SlicePricing::default()).unwrap_or_default()), - slice_last_calculated: None, + available_combinations: Vec::new(), // Will be calculated below + slice_pricing: Some(serde_json::to_value(&SlicePricing::default()).unwrap_or_default()), + slice_last_calculated: Some(Utc::now()), }; + // FIX: Generate initial slice combinations + let combinations = self.slice_calculator.generate_slice_combinations( + node.total_base_slices as u32, + node.allocated_base_slices as u32, + &node, + user_email + ); + node.available_combinations = combinations.iter() + .map(|c| serde_json::to_value(c).unwrap_or_default()) + .collect(); + // Save to persistent storage let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email); diff --git a/src/static/js/dashboard-layout-init.js b/src/static/js/dashboard-layout-init.js new file mode 100644 index 0000000..c3a02cb --- /dev/null +++ b/src/static/js/dashboard-layout-init.js @@ -0,0 +1,50 @@ +/** + * Dashboard Layout Initialization - CSP-compliant external script + * Handles messaging system initialization and other dashboard-wide functionality + */ + +(function() { + 'use strict'; + + /** + * Initialize messaging system with proper error handling + */ + function initializeMessagingSystem() { + try { + // Check if MessagingSystem is available + if (typeof MessagingSystem !== 'undefined') { + // Create global messaging system instance if it doesn't exist + if (!window.messagingSystem) { + console.log('🔧 Creating MessagingSystem instance for dashboard'); + window.messagingSystem = new MessagingSystem(); + } else { + console.log('✅ MessagingSystem already initialized'); + } + } else { + console.warn('⚠️ MessagingSystem class not available - messaging features may not work'); + } + } catch (error) { + console.error('❌ Failed to initialize messaging system:', error); + } + } + + /** + * Initialize dashboard layout components + */ + function initializeDashboard() { + // Initialize messaging system + initializeMessagingSystem(); + + // Add any other dashboard-wide initialization here + console.log('✅ Dashboard layout initialized'); + } + + // Initialize when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initializeDashboard); + } else { + // DOM is already ready + initializeDashboard(); + } + +})(); \ No newline at end of file diff --git a/src/views/dashboard/layout.html b/src/views/dashboard/layout.html index f3cd05d..04b8e14 100644 --- a/src/views/dashboard/layout.html +++ b/src/views/dashboard/layout.html @@ -224,15 +224,5 @@ {% block scripts %} - + {% endblock %} \ No newline at end of file diff --git a/src/views/dashboard/resource_provider.html b/src/views/dashboard/resource_provider.html index 203efc5..84779e1 100644 --- a/src/views/dashboard/resource_provider.html +++ b/src/views/dashboard/resource_provider.html @@ -303,9 +303,12 @@
- +
diff --git a/user_data/user123_at_example_com.json b/user_data/user123_at_example_com.json index 782da21..1a0d1cc 100644 --- a/user_data/user123_at_example_com.json +++ b/user_data/user123_at_example_com.json @@ -150,6 +150,232 @@ "group_slice_price": null, "last_seen": "2025-09-09T03:03:44.241206636Z", "health_score": 100.0 + }, + { + "id": "grid_node_10", + "location": "Unknown, Belgium", + "status": "Online", + "capacity": { + "cpu_cores": 8, + "memory_gb": 15, + "storage_gb": 402559, + "bandwidth_mbps": 1000, + "ssd_storage_gb": 223, + "hdd_storage_gb": 402336, + "ram_gb": 15 + }, + "used_capacity": { + "cpu_cores": 4, + "memory_gb": 10, + "storage_gb": 137, + "bandwidth_mbps": 0, + "ssd_storage_gb": 137, + "hdd_storage_gb": 0, + "ram_gb": 10 + }, + "uptime_percentage": 99.0, + "farming_start_date": "2025-08-10T03:10:19.936729614Z", + "last_updated": "2025-09-09T03:10:19.936733378Z", + "utilization_7_day_avg": 65.0, + "slice_formats_supported": [ + "1x1", + "2x2", + "4x4" + ], + "rental_options": null, + "total_base_slices": 0, + "allocated_base_slices": 0, + "earnings_today_usd": 0.0, + "grid_node_id": "10", + "available_combinations": [], + "slice_allocations": [], + "slice_last_calculated": null, + "marketplace_sla": { + "id": "sla-repair-e3b05c2c-5eb6-4304-93c0-7a9c7348636a", + "name": "Repaired Node SLA", + "uptime_guarantee": 99.8, + "response_time_hours": 24, + "resolution_time_hours": 48, + "penalty_rate": 0.01, + "uptime_guarantee_percentage": 99.8, + "base_slice_price": 0.5, + "bandwidth_guarantee_mbps": 100.0, + "last_updated": "2025-09-09T03:13:53.570999450Z" + }, + "slice_pricing": { + "base_price_per_hour": 1.0, + "currency": "USD", + "pricing_multiplier": 1.0 + }, + "grid_data": { + "capacity": { + "bandwidth_mbps": 1000, + "cpu_cores": 8, + "hdd_storage_gb": 402336, + "memory_gb": 15, + "ram_gb": 15, + "ssd_storage_gb": 223, + "storage_gb": 402559 + }, + "certification_type": "Diy", + "city": "Unknown", + "country": "Belgium", + "farm_id": 1, + "farm_name": "Freefarm", + "farming_policy_id": 1, + "grid_node_id": 10, + "last_updated": "2025-09-09T03:10:19.936676347Z", + "location": "Unknown, Belgium", + "node_id": 10, + "public_ips": [ + "192.168.1.100" + ], + "status": "Online", + "total_resources": { + "bandwidth_mbps": 1000, + "cpu_cores": 8, + "hdd_storage_gb": 402336, + "memory_gb": 15, + "ram_gb": 15, + "ssd_storage_gb": 223, + "storage_gb": 402559 + }, + "uptime": 99.5, + "used_resources": { + "bandwidth_mbps": 0, + "cpu_cores": 4, + "hdd_storage_gb": 0, + "memory_gb": 10, + "ram_gb": 10, + "ssd_storage_gb": 137, + "storage_gb": 137 + } + }, + "slice_formats": null, + "name": "Grid Node 10", + "region": "Belgium", + "node_type": "MyceliumNode", + "staking_options": null, + "availability_status": "Available", + "node_group_id": null, + "group_assignment_date": null, + "group_slice_format": null, + "group_slice_price": null, + "last_seen": "2025-09-09T03:10:19.936736220Z", + "health_score": 100.0 + }, + { + "id": "grid_node_12", + "location": "Unknown, Belgium", + "status": "Online", + "capacity": { + "cpu_cores": 8, + "memory_gb": 15, + "storage_gb": 402559, + "bandwidth_mbps": 1000, + "ssd_storage_gb": 223, + "hdd_storage_gb": 402336, + "ram_gb": 15 + }, + "used_capacity": { + "cpu_cores": 5, + "memory_gb": 12, + "storage_gb": 165, + "bandwidth_mbps": 0, + "ssd_storage_gb": 165, + "hdd_storage_gb": 0, + "ram_gb": 12 + }, + "uptime_percentage": 99.0, + "farming_start_date": "2025-08-10T03:30:24.732131670Z", + "last_updated": "2025-09-09T03:30:24.732143334Z", + "utilization_7_day_avg": 65.0, + "slice_formats_supported": [ + "1x1", + "2x2", + "4x4" + ], + "rental_options": null, + "total_base_slices": 0, + "allocated_base_slices": 0, + "earnings_today_usd": 0.0, + "grid_node_id": "12", + "available_combinations": [], + "slice_allocations": [], + "slice_last_calculated": null, + "marketplace_sla": { + "id": "sla-repair-25c05a40-790f-4a80-8ef8-fa12a726c0ff", + "name": "Repaired Node SLA", + "uptime_guarantee": 99.8, + "response_time_hours": 24, + "resolution_time_hours": 48, + "penalty_rate": 0.01, + "uptime_guarantee_percentage": 99.8, + "base_slice_price": 0.5, + "bandwidth_guarantee_mbps": 100.0, + "last_updated": "2025-09-09T03:30:27.416132016Z" + }, + "slice_pricing": { + "base_price_per_hour": 1.0, + "currency": "USD", + "pricing_multiplier": 1.0 + }, + "grid_data": { + "capacity": { + "bandwidth_mbps": 1000, + "cpu_cores": 8, + "hdd_storage_gb": 402336, + "memory_gb": 15, + "ram_gb": 15, + "ssd_storage_gb": 223, + "storage_gb": 402559 + }, + "certification_type": "Diy", + "city": "Unknown", + "country": "Belgium", + "farm_id": 1, + "farm_name": "Freefarm", + "farming_policy_id": 1, + "grid_node_id": 12, + "last_updated": "2025-09-09T03:30:24.731928799Z", + "location": "Unknown, Belgium", + "node_id": 12, + "public_ips": [ + "192.168.1.100" + ], + "status": "Online", + "total_resources": { + "bandwidth_mbps": 1000, + "cpu_cores": 8, + "hdd_storage_gb": 402336, + "memory_gb": 15, + "ram_gb": 15, + "ssd_storage_gb": 223, + "storage_gb": 402559 + }, + "uptime": 99.5, + "used_resources": { + "bandwidth_mbps": 0, + "cpu_cores": 5, + "hdd_storage_gb": 0, + "memory_gb": 12, + "ram_gb": 12, + "ssd_storage_gb": 165, + "storage_gb": 165 + } + }, + "slice_formats": null, + "name": "Grid Node 12", + "region": "Belgium", + "node_type": "MyceliumNode", + "staking_options": null, + "availability_status": "Available", + "node_group_id": null, + "group_assignment_date": null, + "group_slice_format": null, + "group_slice_price": null, + "last_seen": "2025-09-09T03:30:24.732150580Z", + "health_score": 100.0 } ], "resource_provider_earnings": [], diff --git a/user_data/user123_at_example_com_cart.json b/user_data/user123_at_example_com_cart.json new file mode 100644 index 0000000..3b53144 --- /dev/null +++ b/user_data/user123_at_example_com_cart.json @@ -0,0 +1,15 @@ +{ + "user_id": "user123@example.com", + "items": [ + { + "product_id": "user_user0_example_com_fa373486", + "quantity": 1, + "selected_specifications": {}, + "added_at": "2025-09-09T03:32:30.573242755Z", + "updated_at": "2025-09-09T03:32:30.573242755Z" + } + ], + "session_id": null, + "created_at": "2025-09-09T03:32:30.573133861Z", + "updated_at": "2025-09-09T03:32:30.573271484Z" +} \ No newline at end of file diff --git a/user_data/user321_at_example_com.json b/user_data/user321_at_example_com.json index a753663..947b0b2 100644 --- a/user_data/user321_at_example_com.json +++ b/user_data/user321_at_example_com.json @@ -18,7 +18,121 @@ "deleted": null, "deleted_at": null, "deletion_reason": null, - "nodes": [], + "nodes": [ + { + "id": "grid_node_2007", + "location": "Unknown, Belgium", + "status": "Online", + "capacity": { + "cpu_cores": 24, + "memory_gb": 188, + "storage_gb": 8859, + "bandwidth_mbps": 1000, + "ssd_storage_gb": 476, + "hdd_storage_gb": 8383, + "ram_gb": 188 + }, + "used_capacity": { + "cpu_cores": 9, + "memory_gb": 55, + "storage_gb": 343, + "bandwidth_mbps": 0, + "ssd_storage_gb": 343, + "hdd_storage_gb": 0, + "ram_gb": 55 + }, + "uptime_percentage": 99.0, + "farming_start_date": "2025-08-10T03:27:08.942256607Z", + "last_updated": "2025-09-09T03:27:08.942268123Z", + "utilization_7_day_avg": 65.0, + "slice_formats_supported": [ + "1x1", + "2x2", + "4x4" + ], + "rental_options": null, + "total_base_slices": 0, + "allocated_base_slices": 0, + "earnings_today_usd": 0.0, + "grid_node_id": "2007", + "available_combinations": [], + "slice_allocations": [], + "slice_last_calculated": null, + "marketplace_sla": { + "id": "sla-repair-8fa25e61-493a-46cc-b942-ce8cef923ae6", + "name": "Repaired Node SLA", + "uptime_guarantee": 99.8, + "response_time_hours": 24, + "resolution_time_hours": 48, + "penalty_rate": 0.01, + "uptime_guarantee_percentage": 99.8, + "base_slice_price": 0.5, + "bandwidth_guarantee_mbps": 100.0, + "last_updated": "2025-09-09T03:27:12.489433171Z" + }, + "slice_pricing": { + "base_price_per_hour": 1.0, + "currency": "USD", + "pricing_multiplier": 1.0 + }, + "grid_data": { + "capacity": { + "bandwidth_mbps": 1000, + "cpu_cores": 24, + "hdd_storage_gb": 8383, + "memory_gb": 188, + "ram_gb": 188, + "ssd_storage_gb": 476, + "storage_gb": 8859 + }, + "certification_type": "Diy", + "city": "Unknown", + "country": "Belgium", + "farm_id": 1, + "farm_name": "Freefarm", + "farming_policy_id": 1, + "grid_node_id": 2007, + "last_updated": "2025-09-09T03:27:08.942100965Z", + "location": "Unknown, Belgium", + "node_id": 2007, + "public_ips": [ + "192.168.1.100" + ], + "status": "Online", + "total_resources": { + "bandwidth_mbps": 1000, + "cpu_cores": 24, + "hdd_storage_gb": 8383, + "memory_gb": 188, + "ram_gb": 188, + "ssd_storage_gb": 476, + "storage_gb": 8859 + }, + "uptime": 99.5, + "used_resources": { + "bandwidth_mbps": 0, + "cpu_cores": 9, + "hdd_storage_gb": 0, + "memory_gb": 55, + "ram_gb": 55, + "ssd_storage_gb": 343, + "storage_gb": 343 + } + }, + "slice_formats": null, + "name": "Grid Node 2007", + "region": "Belgium", + "node_type": "MyceliumNode", + "staking_options": null, + "availability_status": "Available", + "node_group_id": null, + "group_assignment_date": null, + "group_slice_format": null, + "group_slice_price": null, + "last_seen": "2025-09-09T03:27:08.942273898Z", + "health_score": 100.0 + } + ], "resource_provider_earnings": [], "resource_provider_settings": null, "slice_products": [], @@ -29,7 +143,91 @@ "active_product_rentals": [], "resource_provider_rental_earnings": [], "node_rentals": [], - "node_groups": [], + "node_groups": [ + { + "id": "compute", + "name": "Compute", + "description": "General compute workloads", + "node_ids": [], + "group_type": { + "Default": "compute" + }, + "updated_at": "2025-09-09T03:26:57.639840151Z", + "created_at": "2025-09-09T03:26:57.639836172Z", + "group_config": { + "group_name": "Compute Nodes", + "max_nodes": 100, + "allocation_strategy": "balanced", + "auto_scaling": true, + "preferred_slice_formats": [ + "1x1", + "2x2" + ], + "default_pricing": 50.0, + "resource_optimization": { + "cpu_optimization": 0.5, + "memory_optimization": 0.5, + "storage_optimization": 0.5, + "network_optimization": 0.5 + } + } + }, + { + "id": "storage", + "name": "Storage", + "description": "Storage and data workloads", + "node_ids": [], + "group_type": { + "Default": "storage" + }, + "updated_at": "2025-09-09T03:26:57.639846621Z", + "created_at": "2025-09-09T03:26:57.639846284Z", + "group_config": { + "group_name": "Storage Nodes", + "max_nodes": 50, + "allocation_strategy": "storage_optimized", + "auto_scaling": false, + "preferred_slice_formats": [ + "1x1" + ], + "default_pricing": 30.0, + "resource_optimization": { + "cpu_optimization": 0.3, + "memory_optimization": 0.3, + "storage_optimization": 0.8, + "network_optimization": 0.6 + } + } + }, + { + "id": "ai-gpu", + "name": "AI/GPU", + "description": "AI and GPU-intensive workloads", + "node_ids": [], + "group_type": { + "Default": "ai-gpu" + }, + "updated_at": "2025-09-09T03:26:57.639850994Z", + "created_at": "2025-09-09T03:26:57.639850646Z", + "group_config": { + "group_name": "AI/GPU Nodes", + "max_nodes": 20, + "allocation_strategy": "gpu_optimized", + "auto_scaling": true, + "preferred_slice_formats": [ + "4x4", + "8x8" + ], + "default_pricing": 200.0, + "resource_optimization": { + "cpu_optimization": 0.8, + "memory_optimization": 0.7, + "storage_optimization": 0.4, + "network_optimization": 0.5 + } + } + } + ], "slice_rentals": [], "slice_assignments": [], "display_currency": "MC",