use heromodels::db::{Collection, Db}; use heromodels::models::grid4::{Contract, ContractStatus}; use heromodels::models::grid4::contract::contract_index::customer_id; use heromodels_core::Model; // Helper function to print contract details fn print_contract_details(contract: &Contract) { println!("\n--- Contract Details ---"); println!("ID: {}", contract.get_id()); println!("Customer ID: {}", contract.customer_id); println!("Compute Slices: {}", contract.compute_slices.len()); println!("Storage Slices: {}", contract.storage_slices.len()); println!("Compute Slice Price: ${:.2}", contract.compute_slice_price); println!("Storage Slice Price: ${:.2}", contract.storage_slice_price); println!("Network Slice Price: ${:.2}", contract.network_slice_price); println!("Status: {:?}", contract.status); println!("Start Date: {}", contract.start_date); println!("End Date: {}", contract.end_date); println!("Billing Period: {:?}", contract.billing_period); println!("Signature User: {}", contract.signature_user); println!("Signature Hoster: {}", contract.signature_hoster); println!("Created At: {}", contract.base_data.created_at); println!("Modified At: {}", contract.base_data.modified_at); // Print compute slices details if !contract.compute_slices.is_empty() { println!(" Compute Slices:"); for (i, slice) in contract.compute_slices.iter().enumerate() { println!(" {}. Node: {}, ID: {}, Memory: {:.1}GB, Storage: {:.1}GB, Passmark: {}, vCores: {}", i + 1, slice.node_id, slice.id, slice.mem_gb, slice.storage_gb, slice.passmark, slice.vcores); } } // Print storage slices details if !contract.storage_slices.is_empty() { println!(" Storage Slices:"); for (i, slice) in contract.storage_slices.iter().enumerate() { println!(" {}. Node: {}, ID: {}, Size: {}GB", i + 1, slice.node_id, slice.id, slice.storage_size_gb); } } } fn main() { // Create a new DB instance in /tmp/grid4_contracts_db, and reset before every run let db = heromodels::db::hero::OurDB::new("/tmp/grid4_contracts_db", true).expect("Can create DB"); println!("Grid4 Contract Models - Basic Usage Example"); println!("=========================================="); // Create compute slices for contracts let compute_slice1 = ComputeSliceProvisioned::new() .node_id(1001) .id(1) .mem_gb(2.0) .storage_gb(20.0) .passmark(2500) .vcores(2) .cpu_oversubscription(150) .tags("web-server,production".to_string()); let compute_slice2 = ComputeSliceProvisioned::new() .node_id(1002) .id(2) .mem_gb(4.0) .storage_gb(40.0) .passmark(5000) .vcores(4) .cpu_oversubscription(120) .tags("database,high-performance".to_string()); let compute_slice3 = ComputeSliceProvisioned::new() .node_id(1003) .id(1) .mem_gb(8.0) .storage_gb(80.0) .passmark(10000) .vcores(8) .cpu_oversubscription(100) .tags("ml-training,gpu-enabled".to_string()); // Create storage slices for contracts let storage_slice1 = StorageSliceProvisioned::new() .node_id(2001) .id(1) .storage_size_gb(100) .tags("backup,cold-storage".to_string()); let storage_slice2 = StorageSliceProvisioned::new() .node_id(2002) .id(2) .storage_size_gb(500) .tags("data-lake,analytics".to_string()); let storage_slice3 = StorageSliceProvisioned::new() .node_id(2003) .id(1) .storage_size_gb(1000) .tags("archive,long-term".to_string()); // Create contracts with different configurations // Contract 1 - Small web hosting contract let contract1 = Contract::new() .customer_id(201) .add_compute_slice(compute_slice1.clone()) .add_storage_slice(storage_slice1.clone()) .compute_slice_price(0.05) .storage_slice_price(0.02) .network_slice_price(0.01) .status(ContractStatus::Active) .start_date(1640995200) // 2022-01-01 .end_date(1672531200) // 2023-01-01 .billing_period(BillingPeriod::Monthly) .signature_user("contract_user_201_abc123".to_string()) .signature_hoster("hoster_node1001_xyz789".to_string()); // Contract 2 - Database hosting contract let contract2 = Contract::new() .customer_id(202) .add_compute_slice(compute_slice2.clone()) .add_storage_slice(storage_slice2.clone()) .compute_slice_price(0.04) .storage_slice_price(0.015) .network_slice_price(0.008) .status(ContractStatus::Active) .start_date(1640995200) .end_date(1704067200) // 2024-01-01 .billing_period(BillingPeriod::Yearly) .signature_user("contract_user_202_def456".to_string()) .signature_hoster("hoster_node1002_uvw123".to_string()); // Contract 3 - ML training contract (paused) let contract3 = Contract::new() .customer_id(203) .add_compute_slice(compute_slice3.clone()) .add_storage_slice(storage_slice3.clone()) .compute_slice_price(0.08) .storage_slice_price(0.01) .network_slice_price(0.015) .status(ContractStatus::Paused) .start_date(1640995200) .end_date(1672531200) .billing_period(BillingPeriod::Hourly) .signature_user("contract_user_203_ghi789".to_string()) .signature_hoster("hoster_node1003_rst456".to_string()); // Contract 4 - Multi-slice enterprise contract let contract4 = Contract::new() .customer_id(204) .add_compute_slice(compute_slice1.clone()) .add_compute_slice(compute_slice2.clone()) .add_storage_slice(storage_slice1.clone()) .add_storage_slice(storage_slice2.clone()) .compute_slice_price(0.045) .storage_slice_price(0.018) .network_slice_price(0.012) .status(ContractStatus::Active) .start_date(1640995200) .end_date(1735689600) // 2025-01-01 .billing_period(BillingPeriod::Monthly) .signature_user("contract_user_204_jkl012".to_string()) .signature_hoster("hoster_enterprise_mno345".to_string()); // Save all contracts to database and get their assigned IDs and updated models let (contract1_id, db_contract1) = db .collection() .expect("can open contract collection") .set(&contract1) .expect("can set contract"); let (contract2_id, db_contract2) = db .collection() .expect("can open contract collection") .set(&contract2) .expect("can set contract"); let (contract3_id, db_contract3) = db .collection() .expect("can open contract collection") .set(&contract3) .expect("can set contract"); let (contract4_id, db_contract4) = db .collection() .expect("can open contract collection") .set(&contract4) .expect("can set contract"); println!("Contract 1 assigned ID: {}", contract1_id); println!("Contract 2 assigned ID: {}", contract2_id); println!("Contract 3 assigned ID: {}", contract3_id); println!("Contract 4 assigned ID: {}", contract4_id); // Print all contracts retrieved from database println!("\n--- Contracts Retrieved from Database ---"); println!("\n1. Web hosting contract:"); print_contract_details(&db_contract1); println!("\n2. Database hosting contract:"); print_contract_details(&db_contract2); println!("\n3. ML training contract (paused):"); print_contract_details(&db_contract3); println!("\n4. Enterprise multi-slice contract:"); print_contract_details(&db_contract4); // Demonstrate different ways to retrieve contracts from the database // 1. Retrieve by customer ID index println!("\n--- Retrieving Contracts by Different Methods ---"); println!("\n1. By Customer ID Index (Customer 202):"); let customer_contracts = db .collection::() .expect("can open contract collection") .get::(&202u32) .expect("can load contracts by customer"); assert_eq!(customer_contracts.len(), 1); print_contract_details(&customer_contracts[0]); // 2. Update contract status println!("\n2. Resuming Paused Contract:"); let mut updated_contract = db_contract3.clone(); updated_contract.status = ContractStatus::Active; let (_, resumed_contract) = db .collection::() .expect("can open contract collection") .set(&updated_contract) .expect("can update contract"); println!("Updated contract status to Active:"); print_contract_details(&resumed_contract); // 3. Cancel a contract println!("\n3. Cancelling a Contract:"); let mut cancelled_contract = db_contract1.clone(); cancelled_contract.status = ContractStatus::Cancelled; let (_, final_contract) = db .collection::() .expect("can open contract collection") .set(&cancelled_contract) .expect("can update contract"); println!("Cancelled contract:"); print_contract_details(&final_contract); // Show remaining active contracts let all_contracts = db .collection::() .expect("can open contract collection") .get_all() .expect("can load all contracts"); println!("\n--- Contract Analytics ---"); let active_contracts: Vec<_> = all_contracts.iter() .filter(|c| matches!(c.status, ContractStatus::Active)) .collect(); let paused_contracts: Vec<_> = all_contracts.iter() .filter(|c| matches!(c.status, ContractStatus::Paused)) .collect(); let cancelled_contracts: Vec<_> = all_contracts.iter() .filter(|c| matches!(c.status, ContractStatus::Cancelled)) .collect(); println!("Total Contracts: {}", all_contracts.len()); println!("Active Contracts: {}", active_contracts.len()); println!("Paused Contracts: {}", paused_contracts.len()); println!("Cancelled Contracts: {}", cancelled_contracts.len()); // Calculate total provisioned resources let total_compute_slices: usize = all_contracts.iter().map(|c| c.compute_slices.len()).sum(); let total_storage_slices: usize = all_contracts.iter().map(|c| c.storage_slices.len()).sum(); let total_memory_gb: f64 = all_contracts.iter() .flat_map(|c| &c.compute_slices) .map(|s| s.mem_gb) .sum(); let total_storage_gb: i32 = all_contracts.iter() .flat_map(|c| &c.storage_slices) .map(|s| s.storage_size_gb) .sum(); println!("\nProvisioned Resources:"); println!(" Total Compute Slices: {}", total_compute_slices); println!(" Total Storage Slices: {}", total_storage_slices); println!(" Total Memory: {:.1} GB", total_memory_gb); println!(" Total Storage: {} GB", total_storage_gb); // Calculate average pricing let avg_compute_price: f64 = all_contracts.iter().map(|c| c.compute_slice_price).sum::() / all_contracts.len() as f64; let avg_storage_price: f64 = all_contracts.iter().map(|c| c.storage_slice_price).sum::() / all_contracts.len() as f64; let avg_network_price: f64 = all_contracts.iter().map(|c| c.network_slice_price).sum::() / all_contracts.len() as f64; println!("\nAverage Pricing:"); println!(" Compute: ${:.3} per slice", avg_compute_price); println!(" Storage: ${:.3} per slice", avg_storage_price); println!(" Network: ${:.3} per slice", avg_network_price); println!("\n--- Model Information ---"); println!("Contract DB Prefix: {}", Contract::db_prefix()); }