feat: rename farmer to resource provider across codebase and update terminology

This commit is contained in:
mik-tf
2025-09-06 23:27:14 -04:00
parent bf273102cb
commit c8e28cf8ed
34 changed files with 511 additions and 511 deletions

View File

@@ -392,11 +392,11 @@ impl DashboardController {
render_template(&tmpl, "dashboard/user.html", &ctx)
}
/// Renders the farmer section of the dashboard
pub async fn farmer_section(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
/// Renders the resource provider section of the dashboard
pub async fn resource_provider_section(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
let mut ctx = crate::models::builders::ContextBuilder::new()
.active_page("dashboard")
.active_section("farmer")
.active_section("resource_provider")
.gitea_enabled(get_app_config().is_gitea_enabled())
.build();
@@ -406,17 +406,17 @@ impl DashboardController {
return render_template(&tmpl, "dashboard/welcome.html", &ctx);
}
// FARMER FIX: Use persistent data only, no mock data for farmer dashboard
// RESOURCE PROVIDER FIX: Use persistent data only, no mock data for resource provider dashboard
if let Ok(Some(user_email)) = session.get::<String>("user_email") {
ctx.insert("user_email", &user_email);
// Initialize farmer service with slice calculator
if let Ok(farmer_service) = crate::services::farmer::FarmerService::builder().build() {
// Repair node-group data consistency when farmer dashboard loads
if let Err(_e) = farmer_service.repair_node_group_consistency(&user_email) {
// Initialize resource provider service with slice calculator
if let Ok(resource_provider_service) = crate::services::resource_provider::ResourceProviderService::builder().build() {
// Repair node-group data consistency when resource provider dashboard loads
if let Err(_e) = resource_provider_service.repair_node_group_consistency(&user_email) {
}
// Repair missing marketplace SLA data for existing nodes
if let Err(_e) = farmer_service.repair_missing_marketplace_sla(
if let Err(_e) = resource_provider_service.repair_missing_marketplace_sla(
&user_email,
99.8, // default uptime
100, // default bandwidth
@@ -424,18 +424,18 @@ impl DashboardController {
) {
}
// Get farmer nodes with updated slice calculations
let farmer_nodes = farmer_service.get_farmer_nodes(&user_email);
// Get resource provider nodes with updated slice calculations
let resource_provider_nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
// Calculate farmer statistics from nodes
let total_nodes = farmer_nodes.len() as u32;
// Calculate resource_provider statistics from nodes
let total_nodes = resource_provider_nodes.len() as u32;
let mut online_nodes = 0u32;
let mut total_base_slices = 0u32;
let mut allocated_base_slices = 0u32;
let mut total_monthly_earnings = rust_decimal::Decimal::ZERO;
let mut average_uptime = 0.0f32;
for node in &farmer_nodes {
for node in &resource_provider_nodes {
if matches!(node.status, crate::models::user::NodeStatus::Online) {
online_nodes += 1;
}
@@ -449,8 +449,8 @@ impl DashboardController {
average_uptime /= total_nodes as f32;
}
// Create farmer statistics for the dashboard
let farmer_stats = serde_json::json!({
// Create resource_provider statistics for the dashboard
let resource_provider_stats = serde_json::json!({
"total_nodes": total_nodes,
"online_nodes": online_nodes,
"total_base_slices": total_base_slices,
@@ -465,8 +465,8 @@ impl DashboardController {
}
});
ctx.insert("farmer_stats", &farmer_stats);
ctx.insert("farmer_nodes", &farmer_nodes);
ctx.insert("resource_provider_stats", &resource_provider_stats);
ctx.insert("resource_provider_nodes", &resource_provider_nodes);
}
// Load user data from session (without mock data override)
@@ -490,7 +490,7 @@ impl DashboardController {
}
ctx.insert("wallet_balance", &persistent_data.wallet_balance_usd);
ctx.insert("farmer_earnings", &persistent_data.farmer_earnings);
ctx.insert("resource_provider_earnings", &persistent_data.resource_provider_earnings);
}
ctx.insert("user_json", &user_json);
@@ -498,10 +498,10 @@ impl DashboardController {
}
}
// Load slice rental service to get farmer slice rental statistics
// Load slice rental service to get resource_provider slice rental statistics
if let Ok(slice_rental_service) = crate::services::slice_rental::SliceRentalService::builder().build() {
let farmer_slice_stats = slice_rental_service.get_farmer_slice_statistics(&user_email);
ctx.insert("slice_rental_statistics", &farmer_slice_stats);
let resource_provider_slice_stats = slice_rental_service.get_resource_provider_slice_statistics(&user_email);
ctx.insert("slice_rental_statistics", &resource_provider_slice_stats);
// Release any expired rentals
if let Err(_e) = slice_rental_service.release_expired_rentals(&user_email) {
@@ -509,7 +509,7 @@ impl DashboardController {
}
}
render_template(&tmpl, "dashboard/farmer.html", &ctx)
render_template(&tmpl, "dashboard/resource_provider.html", &ctx)
}
/// Renders the app provider section of the dashboard
@@ -837,13 +837,13 @@ impl DashboardController {
render_template(&tmpl, "dashboard/pools.html", &ctx)
}
/// API endpoint to return farmer dashboard data as JSON
pub async fn farmer_data_api(session: Session) -> Result<impl Responder> {
/// API endpoint to return resource_provider dashboard data as JSON
pub async fn resource_provider_data_api(session: Session) -> Result<impl Responder> {
let user_email = session.get::<String>("user_email").unwrap_or_default().unwrap_or_default();
// FARMER FIX: Use farmer service to ensure data consistency
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
// RESOURCE_PROVIDER FIX: Use resource_provider service to ensure data consistency
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(_e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -853,16 +853,16 @@ impl DashboardController {
};
// Repair data consistency before loading
if let Err(_e) = farmer_service.repair_node_group_consistency(&user_email) {
if let Err(_e) = resource_provider_service.repair_node_group_consistency(&user_email) {
}
// Load real farmer data from persistence using farmer service
let nodes = farmer_service.get_farmer_nodes(&user_email);
let earnings = farmer_service.get_farmer_earnings(&user_email);
let stats = farmer_service.get_farmer_statistics(&user_email);
// Load real resource_provider data from persistence using resource_provider service
let nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
let earnings = resource_provider_service.get_resource_provider_earnings(&user_email);
let stats = resource_provider_service.get_resource_provider_statistics(&user_email);
// Always use persistent data - no fallback to mock data for farmer dashboard
// If no data exists, return empty but valid farmer data structure
// Always use persistent data - no fallback to mock data for resource_provider dashboard
// If no data exists, return empty but valid resource_provider data structure
if nodes.is_empty() {
return Ok(ResponseBuilder::ok()
.json(serde_json::json!({
@@ -885,12 +885,12 @@ impl DashboardController {
.build());
}
// Load slice products for this farmer
// Load slice products for this resource_provider
let slice_products = crate::services::user_persistence::UserPersistence::get_slice_products(&user_email);
let active_slices = slice_products.len() as i32;
// Build comprehensive farmer data using statistics from farmer service
let farmer_data = serde_json::json!({
// Build comprehensive resource_provider data using statistics from resource_provider service
let resource_provider_data = serde_json::json!({
"total_nodes": stats.total_nodes,
"online_nodes": stats.online_nodes,
"total_capacity": stats.total_capacity,
@@ -904,13 +904,13 @@ impl DashboardController {
"slice_products": slice_products
});
Ok(ResponseBuilder::ok()
.json(farmer_data)
.json(resource_provider_data)
.build())
}
/// Enhanced farmer dashboard with node management
pub async fn farmer_dashboard_enhanced(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
let farmer_service = crate::services::farmer::FarmerService::builder()
/// Enhanced resource_provider dashboard with node management
pub async fn resource_provider_dashboard_enhanced(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
let resource_provider_service = crate::services::resource_provider::ResourceProviderService::builder()
.auto_sync_enabled(true)
.metrics_collection(true)
.build()
@@ -922,14 +922,14 @@ impl DashboardController {
.unwrap_or_default()
.unwrap_or_default();
// Load farmer data using the service
let nodes = farmer_service.get_farmer_nodes(&user_email);
let earnings = farmer_service.get_farmer_earnings(&user_email);
let stats = farmer_service.get_farmer_statistics(&user_email);
// Load resource_provider data using the service
let nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
let earnings = resource_provider_service.get_resource_provider_earnings(&user_email);
let stats = resource_provider_service.get_resource_provider_statistics(&user_email);
let mut ctx = crate::models::builders::ContextBuilder::new()
.active_page("dashboard")
.active_section("farmer")
.active_section("resource_provider")
.build();
ctx.insert("nodes", &nodes);
@@ -944,10 +944,10 @@ impl DashboardController {
ctx.insert("user", &user);
}
render_template(&tmpl, "dashboard/farmer.html", &ctx)
render_template(&tmpl, "dashboard/resource_provider.html", &ctx)
}
/// API endpoint to add a new farm node using FarmerService
/// API endpoint to add a new farm node using ResourceProviderService
pub async fn add_farm_node_enhanced(session: Session, form: web::Json<serde_json::Value>) -> Result<impl Responder> {
let user_email = session.get::<String>("user_email")
@@ -960,8 +960,8 @@ impl DashboardController {
})).build());
}
// Initialize farmer service
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
// Initialize resource_provider service
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(_e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1064,7 +1064,7 @@ impl DashboardController {
.bandwidth_mbps(node_data_json.get("bandwidth_mbps")
.and_then(|v| v.as_i64())
.unwrap_or(100) as i32)
.node_type("MyceliumNode"); // Always MyceliumNode - farmers register MyceliumNodes to Mycelium Grid
.node_type("MyceliumNode"); // Always MyceliumNode - resource providers register MyceliumNodes to Mycelium Grid
// Add optional fields
if let Some(region) = node_data_json.get("region").and_then(|v| v.as_str()) {
@@ -1087,8 +1087,8 @@ impl DashboardController {
actix_web::error::ErrorBadRequest(format!("Invalid node data: {}", e))
})?;
// Add node using farmer service
match farmer_service.add_node(&user_email, node_data) {
// Add node using resource_provider service
match resource_provider_service.add_node(&user_email, node_data) {
Ok(node) => {
// Add activity record
@@ -1143,7 +1143,7 @@ impl DashboardController {
_ => crate::models::user::NodeStatus::Offline,
};
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1152,7 +1152,7 @@ impl DashboardController {
}
};
match farmer_service.update_node_status(&user_email, &node_id, status) {
match resource_provider_service.update_node_status(&user_email, &node_id, status) {
Ok(()) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": true,
@@ -1182,7 +1182,7 @@ impl DashboardController {
let node_id = path.into_inner();
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1191,7 +1191,7 @@ impl DashboardController {
}
};
match farmer_service.get_node_by_id(&user_email, &node_id) {
match resource_provider_service.get_node_by_id(&user_email, &node_id) {
Some(mut node) => {
// MARKETPLACE SLA FIX: Override grid data with marketplace SLA values when available
@@ -1235,7 +1235,7 @@ impl DashboardController {
})).build());
}
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1244,7 +1244,7 @@ impl DashboardController {
}
};
let stats = farmer_service.get_farmer_statistics(&user_email);
let stats = resource_provider_service.get_resource_provider_statistics(&user_email);
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": true,
@@ -1262,7 +1262,7 @@ impl DashboardController {
}
/// API endpoint to update node configuration
pub async fn update_node_comprehensive(session: Session, path: web::Path<String>, form: web::Json<crate::services::farmer::NodeUpdateData>) -> Result<impl Responder> {
pub async fn update_node_comprehensive(session: Session, path: web::Path<String>, form: web::Json<crate::services::resource_provider::NodeUpdateData>) -> Result<impl Responder> {
let user_email = session.get::<String>("user_email")
.unwrap_or_default()
.unwrap_or_default();
@@ -1275,7 +1275,7 @@ impl DashboardController {
let node_id = path.into_inner();
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1284,7 +1284,7 @@ impl DashboardController {
}
};
match farmer_service.update_node(&user_email, &node_id, form.into_inner()) {
match resource_provider_service.update_node(&user_email, &node_id, form.into_inner()) {
Ok(()) => {
// Add activity record
@@ -1324,7 +1324,7 @@ impl DashboardController {
})).build());
}
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1338,7 +1338,7 @@ impl DashboardController {
let mut customized_formats = Vec::new();
for format_id in default_format_ids {
if let Some(format) = farmer_service.get_default_slice_format_with_customizations(&user_email, format_id) {
if let Some(format) = resource_provider_service.get_default_slice_format_with_customizations(&user_email, format_id) {
customized_formats.push(format);
}
}
@@ -1358,7 +1358,7 @@ impl DashboardController {
})).build());
}
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1367,7 +1367,7 @@ impl DashboardController {
}
};
let groups = farmer_service.get_node_groups(&user_email);
let groups = resource_provider_service.get_node_groups(&user_email);
Ok(ResponseBuilder::ok().json(groups).build())
}
@@ -1383,7 +1383,7 @@ impl DashboardController {
})).build());
}
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1402,7 +1402,7 @@ impl DashboardController {
.and_then(|v| v.as_str())
.map(|s| s.to_string());
match farmer_service.create_custom_node_group(&user_email, name, description, None) {
match resource_provider_service.create_custom_node_group(&user_email, name, description, None) {
Ok(group) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": true,
@@ -1431,7 +1431,7 @@ impl DashboardController {
})).build());
}
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1449,10 +1449,10 @@ impl DashboardController {
.and_then(|v| v.as_str())
.map(|s| s.to_string());
match farmer_service.update_node_group_assignment(&user_email, node_id, group_id) {
match resource_provider_service.update_node_group_assignment(&user_email, node_id, group_id) {
Ok(group_name) => {
// FARMER FIX: Repair consistency after group assignment change
if let Err(e) = farmer_service.repair_node_group_consistency(&user_email) {
// RESOURCE_PROVIDER FIX: Repair consistency after group assignment change
if let Err(e) = resource_provider_service.repair_node_group_consistency(&user_email) {
}
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": true,
@@ -1482,7 +1482,7 @@ impl DashboardController {
})).build());
}
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1493,7 +1493,7 @@ impl DashboardController {
let group_id = path.into_inner();
match farmer_service.delete_custom_node_group(&user_email, &group_id) {
match resource_provider_service.delete_custom_node_group(&user_email, &group_id) {
Ok(()) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": true,
@@ -1523,7 +1523,7 @@ impl DashboardController {
let format_id = path.into_inner();
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1532,7 +1532,7 @@ impl DashboardController {
}
};
match farmer_service.get_default_slice_format_with_customizations(&user_email, &format_id) {
match resource_provider_service.get_default_slice_format_with_customizations(&user_email, &format_id) {
Some(format) => {
Ok(ResponseBuilder::ok().json(format).build())
}
@@ -1558,7 +1558,7 @@ impl DashboardController {
let format_id = path.into_inner();
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -1576,7 +1576,7 @@ impl DashboardController {
let bandwidth_mbps = form.get("bandwidth_mbps").and_then(|v| v.as_i64()).unwrap_or(100) as i32;
let price_per_hour = form.get("price_per_hour").and_then(|v| v.as_f64()).map(rust_decimal::Decimal::from_f64_retain).flatten().unwrap_or(rust_decimal::Decimal::from(10));
let customization = crate::services::farmer::DefaultSliceFormat {
let customization = crate::services::resource_provider::DefaultSliceFormat {
id: format_id.clone(),
name,
cpu_cores,
@@ -1587,7 +1587,7 @@ impl DashboardController {
price_per_hour,
};
match farmer_service.save_default_slice_customization(&user_email, &format_id, customization) {
match resource_provider_service.save_default_slice_customization(&user_email, &format_id, customization) {
Ok(_) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": true,
@@ -1630,9 +1630,9 @@ impl DashboardController {
.map(|p| rust_decimal::Decimal::from_f64_retain(p).unwrap_or(rust_decimal::Decimal::new(50, 2)))
.unwrap_or(rust_decimal::Decimal::new(50, 2)); // Fallback to 0.50 TFC/hour only if no price provided
// Load user data to get farmer name
// Load user data to get resource_provider name
let user = Self::load_user_with_persistent_data(&session);
let farmer_name = user.as_ref().map(|u| u.name.clone()).unwrap_or_else(|| "Unknown Farmer".to_string());
let resource_provider_name = user.as_ref().map(|u| u.name.clone()).unwrap_or_else(|| "Unknown ResourceProvider".to_string());
// Create slice configuration with pricing
let slice_pricing = crate::models::product::SlicePricing::from_hourly(
@@ -1657,7 +1657,7 @@ impl DashboardController {
// Create slice product
let slice_product = crate::models::product::Product::create_slice_product(
user_email.clone(),
farmer_name,
resource_provider_name,
name,
slice_config,
price_per_hour,
@@ -2225,18 +2225,18 @@ impl DashboardController {
}
};
// Initialize farmer service to check for existing nodes
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
// Initialize resource_provider service to check for existing nodes
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
"error": "Failed to initialize farmer service"
"error": "Failed to initialize resource_provider service"
})).build());
}
};
// Get existing nodes to check for duplicates
let existing_nodes = farmer_service.get_farmer_nodes(&user_email);
let existing_nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
// Validate each node and fetch data
let mut validated_nodes = Vec::new();
@@ -2502,12 +2502,12 @@ impl DashboardController {
let slice_format = form.get("slice_format").and_then(|v| v.as_str()).map(|s| s.to_string());
let slice_price = form.get("slice_price").and_then(|v| v.as_f64()).map(|p| Decimal::from_f64_retain(p).unwrap_or_default());
// Initialize farmer service
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
// Initialize resource_provider service
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
"error": "Failed to initialize farmer service"
"error": "Failed to initialize resource_provider service"
})).build());
}
};
@@ -2515,7 +2515,7 @@ impl DashboardController {
// Add nodes with comprehensive configuration
log::info!(
target: "api.dashboard",
"add_grid_nodes:invoke_farmer_service req_id={} email={} node_count={} slice_enabled={} full_node_enabled={} pricing_mode={}",
"add_grid_nodes:invoke_resource_provider_service req_id={} email={} node_count={} slice_enabled={} full_node_enabled={} pricing_mode={}",
req_id,
user_email,
node_ids.len(),
@@ -2556,19 +2556,19 @@ impl DashboardController {
// For multi-node scenarios, apply pricing configuration based on user choice
if node_ids.len() > 1 && pricing_mode == "same_for_all" && rental_options.is_some() {
} else if node_ids.len() > 1 && pricing_mode == "individual" && individual_node_pricing.is_some() {
// Individual pricing will be handled in the farmer service
// Individual pricing will be handled in the resource_provider service
}
// Choose the appropriate method based on pricing mode
if pricing_mode == "individual" && individual_node_pricing.is_some() {
farmer_service.add_multiple_grid_nodes_with_individual_pricing(
resource_provider_service.add_multiple_grid_nodes_with_individual_pricing(
&user_email,
node_ids.clone(),
slice_formats,
individual_node_pricing.unwrap()
).await
} else {
farmer_service.add_multiple_grid_nodes_with_comprehensive_config(
resource_provider_service.add_multiple_grid_nodes_with_comprehensive_config(
&user_email,
node_ids.clone(),
slice_formats,
@@ -2576,7 +2576,7 @@ impl DashboardController {
).await
}
} else {
farmer_service.add_multiple_grid_nodes(&user_email, node_ids.clone()).await
resource_provider_service.add_multiple_grid_nodes(&user_email, node_ids.clone()).await
};
match add_result {
@@ -2594,7 +2594,7 @@ impl DashboardController {
// If node_group_id is provided, assign nodes to existing group
if let Some(group_id) = node_group_id {
for node in &added_nodes {
if let Err(e) = farmer_service.assign_node_to_group(&user_email, &node.id, Some(group_id.clone())) {
if let Err(e) = resource_provider_service.assign_node_to_group(&user_email, &node.id, Some(group_id.clone())) {
} else {
}
}
@@ -2606,7 +2606,7 @@ impl DashboardController {
group_data.get("description").and_then(|v| v.as_str())
) {
// Create node group
match farmer_service.create_custom_node_group(
match resource_provider_service.create_custom_node_group(
&user_email,
group_name.to_string(),
Some(group_description.to_string()),
@@ -2626,7 +2626,7 @@ impl DashboardController {
// Add nodes to group
for node in &added_nodes {
if let Err(e) = farmer_service.assign_node_to_group(&user_email, &node.id, Some(group.id.clone())) {
if let Err(e) = resource_provider_service.assign_node_to_group(&user_email, &node.id, Some(group.id.clone())) {
}
}
}
@@ -2663,7 +2663,7 @@ impl DashboardController {
}
};
if let Err(e) = farmer_service.stake_on_node(&user_email, &node.id, staking_options) {
if let Err(e) = resource_provider_service.stake_on_node(&user_email, &node.id, staking_options) {
} else {
}
}
@@ -2691,7 +2691,7 @@ impl DashboardController {
};
for node in &added_nodes {
if let Err(e) = farmer_service.stake_on_node(&user_email, &node.id, staking_options.clone()) {
if let Err(e) = resource_provider_service.stake_on_node(&user_email, &node.id, staking_options.clone()) {
} else {
}
}
@@ -2752,11 +2752,11 @@ impl DashboardController {
let slice_format = form.get("slice_format").and_then(|v| v.as_str()).map(|s| s.to_string());
let slice_price = form.get("slice_price").and_then(|v| v.as_f64()).map(|p| Decimal::from_f64_retain(p).unwrap_or_default());
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(_e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
"error": "Failed to initialize farmer service"
"error": "Failed to initialize resource_provider service"
})).build());
}
};
@@ -2774,7 +2774,7 @@ impl DashboardController {
resource_optimization: crate::models::user::ResourceOptimization::default(),
};
match farmer_service.create_custom_node_group(
match resource_provider_service.create_custom_node_group(
&user_email,
name.to_string(),
description,
@@ -2810,7 +2810,7 @@ impl DashboardController {
})).build()),
};
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
"success": false,
@@ -2818,15 +2818,15 @@ impl DashboardController {
})).build()),
};
// FARMER FIX: Repair node-group data consistency before getting statistics
if let Err(e) = farmer_service.repair_node_group_consistency(&user_email) {
// RESOURCE_PROVIDER FIX: Repair node-group data consistency before getting statistics
if let Err(e) = resource_provider_service.repair_node_group_consistency(&user_email) {
}
let groups = farmer_service.get_node_groups(&user_email);
let groups = resource_provider_service.get_node_groups(&user_email);
let mut groups_with_stats = Vec::new();
for group in groups {
match farmer_service.get_group_statistics(&user_email, &group.id) {
match resource_provider_service.get_group_statistics(&user_email, &group.id) {
Ok(stats) => {
groups_with_stats.push(serde_json::json!({
"group": group,
@@ -5387,7 +5387,7 @@ impl DashboardController {
};
// Check if node exists and get its details first
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -5398,7 +5398,7 @@ impl DashboardController {
};
// Verify node exists and belongs to user
let _node = match farmer_service.get_node_by_id(&user_email, &node_id) {
let _node = match resource_provider_service.get_node_by_id(&user_email, &node_id) {
Some(node) => node,
None => {
return Ok(ResponseBuilder::not_found().json(serde_json::json!({
@@ -5457,7 +5457,7 @@ impl DashboardController {
}
};
let _farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let _resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -5927,7 +5927,7 @@ impl DashboardController {
}
};
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -5970,7 +5970,7 @@ impl DashboardController {
};
// Stake on node
match farmer_service.stake_on_node(&user_email, &node_id, staking_options) {
match resource_provider_service.stake_on_node(&user_email, &node_id, staking_options) {
Ok(()) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": true,
@@ -6010,7 +6010,7 @@ impl DashboardController {
}
};
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -6030,7 +6030,7 @@ impl DashboardController {
match action {
"unstake" => {
// Unstake from node
match farmer_service.unstake_from_node(&user_email, &node_id) {
match resource_provider_service.unstake_from_node(&user_email, &node_id) {
Ok(returned_amount) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": true,
@@ -6078,7 +6078,7 @@ impl DashboardController {
};
// Update node staking
match farmer_service.update_node_staking(&user_email, &node_id, staking_options) {
match resource_provider_service.update_node_staking(&user_email, &node_id, staking_options) {
Ok(()) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": true,
@@ -6120,7 +6120,7 @@ impl DashboardController {
}
};
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -6130,7 +6130,7 @@ impl DashboardController {
}
};
let statistics = farmer_service.get_staking_statistics(&user_email);
let statistics = resource_provider_service.get_staking_statistics(&user_email);
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": false,
@@ -6293,7 +6293,7 @@ impl DashboardController {
.build())
}
/// Refresh slice calculations for farmer
/// Refresh slice calculations for resource_provider
pub async fn refresh_slice_calculations(session: Session) -> Result<impl Responder> {
let user_email = match session.get::<String>("user_email") {
Ok(Some(email)) => email,
@@ -6303,7 +6303,7 @@ impl DashboardController {
})).build())
};
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -6313,7 +6313,7 @@ impl DashboardController {
}
};
match farmer_service.refresh_all_slice_calculations(&user_email) {
match resource_provider_service.refresh_all_slice_calculations(&user_email) {
Ok(_) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": false,
@@ -6329,7 +6329,7 @@ impl DashboardController {
}
}
/// Sync farmer nodes with ThreeFold Grid
/// Sync resource_provider nodes with ThreeFold Grid
pub async fn sync_with_grid(session: Session) -> Result<impl Responder> {
// Check authentication
if let Err(response) = Self::check_authentication(&session) {
@@ -6463,7 +6463,7 @@ impl DashboardController {
let node_id = path.into_inner();
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -6473,7 +6473,7 @@ impl DashboardController {
}
};
match farmer_service.get_node_slices(&user_email, node_id) {
match resource_provider_service.get_node_slices(&user_email, node_id) {
Ok(slices) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": false,
@@ -6525,7 +6525,7 @@ impl DashboardController {
}
// Initialize services
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -6550,7 +6550,7 @@ impl DashboardController {
let mut errors = Vec::new();
for node_id in &node_ids {
match farmer_service.fetch_and_validate_grid_node(*node_id).await {
match resource_provider_service.fetch_and_validate_grid_node(*node_id).await {
Ok(node_data) => {
// Calculate automatic slices
let total_base_slices = slice_calculator.calculate_max_base_slices(&node_data.capacity);
@@ -6709,8 +6709,8 @@ impl DashboardController {
})).build());
}
// Initialize farmer service
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
// Initialize resource_provider service
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -6722,7 +6722,7 @@ impl DashboardController {
// Add nodes with automatic slice management
match farmer_service.add_multiple_grid_nodes_with_automatic_slices(
match resource_provider_service.add_multiple_grid_nodes_with_automatic_slices(
&user_email,
node_ids.clone(),
base_slice_price,
@@ -6759,7 +6759,7 @@ impl DashboardController {
}
}
/// API endpoint to refresh slice calculations for all farmer nodes
/// API endpoint to refresh slice calculations for all resource_provider nodes
pub async fn refresh_slice_calculations_api(session: Session) -> Result<impl Responder> {
let user_email = session.get::<String>("user_email")
@@ -6773,8 +6773,8 @@ impl DashboardController {
})).build());
}
// Initialize farmer service
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
// Initialize resource_provider service
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -6785,7 +6785,7 @@ impl DashboardController {
};
// Refresh slice calculations for all nodes
match farmer_service.refresh_all_slice_calculations_async(&user_email).await {
match resource_provider_service.refresh_all_slice_calculations_async(&user_email).await {
Ok(updated_nodes) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
@@ -6817,8 +6817,8 @@ impl DashboardController {
})).build());
}
// Initialize farmer service
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
// Initialize resource_provider service
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -6829,7 +6829,7 @@ impl DashboardController {
};
// Sync all nodes with grid
match farmer_service.sync_all_nodes_with_grid_async(&user_email).await {
match resource_provider_service.sync_all_nodes_with_grid_async(&user_email).await {
Ok(synced_nodes) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
@@ -6863,8 +6863,8 @@ impl DashboardController {
let node_id = path.into_inner();
// Initialize farmer service
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
// Initialize resource_provider service
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
Ok(service) => service,
Err(e) => {
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
@@ -6875,7 +6875,7 @@ impl DashboardController {
};
// Get node slice details
match farmer_service.get_node_slice_details(&user_email, &node_id) {
match resource_provider_service.get_node_slice_details(&user_email, &node_id) {
Ok(slice_details) => {
Ok(ResponseBuilder::ok().json(serde_json::json!({
"success": false,

View File

@@ -13,7 +13,7 @@ use chrono::Utc;
/// Form data for slice rental requests
#[derive(Debug, Deserialize)]
pub struct SliceRentalForm {
pub farmer_email: String,
pub resource_provider_email: String,
pub node_id: String,
pub combination_id: String,
pub quantity: u32,
@@ -377,7 +377,7 @@ impl MarketplaceController {
render_template(&tmpl, "marketplace/compute_resources.html", &ctx)
}
/// Renders the Mycelium Nodes marketplace page with REAL farmer nodes from database
/// Renders the Mycelium Nodes marketplace page with REAL resource_provider nodes from database
pub async fn mycelium_nodes(tmpl: web::Data<Tera>, session: Session, query: web::Query<std::collections::HashMap<String, String>>) -> Result<impl Responder> {
// Build services using established builder pattern
let currency_service = CurrencyService::builder()
@@ -411,7 +411,7 @@ impl MarketplaceController {
.unwrap_or(0);
let page_size = 12;
// Get all real farmer nodes as marketplace products
// Get all real resource_provider nodes as marketplace products
let all_node_products = node_marketplace_service.get_all_marketplace_nodes();
// Clone query for reuse
@@ -933,7 +933,7 @@ impl MarketplaceController {
pub async fn show_slice_rental_form(
tmpl: web::Data<Tera>,
session: Session,
path: web::Path<(String, String, String)> // farmer_email, node_id, combination_id
path: web::Path<(String, String, String)> // resource_provider_email, node_id, combination_id
) -> Result<impl Responder> {
let mut ctx = crate::models::builders::ContextBuilder::new()
.active_page("marketplace")
@@ -951,7 +951,7 @@ impl MarketplaceController {
}
}
let (farmer_email, node_id, combination_id) = path.into_inner();
let (resource_provider_email, node_id, combination_id) = path.into_inner();
// Get slice details for the form
let node_marketplace_service = NodeMarketplaceService::builder()
@@ -963,12 +963,12 @@ impl MarketplaceController {
// Find the specific slice combination by checking product attributes
if let Some(slice_product) = slice_combinations.iter().find(|p| {
// Check if this product matches the requested slice
if let (Some(farmer_attr), Some(node_attr), Some(combo_attr)) = (
p.attributes.get("farmer_email"),
if let (Some(resource_provider_attr), Some(node_attr), Some(combo_attr)) = (
p.attributes.get("resource_provider_email"),
p.attributes.get("node_id"),
p.attributes.get("combination_id")
) {
farmer_attr.value.as_str() == Some(&farmer_email) &&
resource_provider_attr.value.as_str() == Some(&resource_provider_email) &&
node_attr.value.as_str() == Some(&node_id) &&
combo_attr.value.as_str() == Some(&combination_id)
} else {
@@ -998,11 +998,11 @@ impl MarketplaceController {
slice_info.insert("price_per_hour", serde_json::Value::String(slice_product.base_price.to_string()));
slice_info.insert("node_id", serde_json::Value::String(node_id.clone()));
slice_info.insert("farmer_email", serde_json::Value::String(farmer_email.clone()));
slice_info.insert("resource_provider_email", serde_json::Value::String(resource_provider_email.clone()));
slice_info.insert("combination_id", serde_json::Value::String(combination_id.clone()));
ctx.insert("slice", &slice_info);
ctx.insert("farmer_email", &farmer_email);
ctx.insert("resource_provider_email", &resource_provider_email);
ctx.insert("node_id", &node_id);
ctx.insert("combination_id", &combination_id);
}
@@ -1109,7 +1109,7 @@ impl MarketplaceController {
// Attempt to rent the slice with deployment options
match slice_rental_service.rent_slice_combination_with_deployment(
&user_email,
&form.farmer_email,
&form.resource_provider_email,
&form.node_id,
&form.combination_id,
form.quantity,
@@ -1134,7 +1134,7 @@ impl MarketplaceController {
meta.insert("deployment_type".to_string(), serde_json::Value::String(form.deployment_type.clone()));
meta.insert("deployment_name".to_string(), serde_json::Value::String(deployment_name.clone()));
meta.insert("quantity".to_string(), serde_json::Value::Number(serde_json::Number::from(form.quantity)));
meta.insert("farmer_email".to_string(), serde_json::Value::String(form.farmer_email.clone()));
meta.insert("resource_provider_email".to_string(), serde_json::Value::String(form.resource_provider_email.clone()));
if form.deployment_type == "kubernetes" {
meta.insert("k8s_masters".to_string(), serde_json::Value::Number(serde_json::Number::from(form.k8s_masters.unwrap_or(1))));
meta.insert("k8s_workers".to_string(), serde_json::Value::Number(serde_json::Number::from(form.k8s_workers.unwrap_or(1))));
@@ -1206,7 +1206,7 @@ impl MarketplaceController {
// Attempt to rent the slice with deployment options
match slice_rental_service.rent_slice_combination_with_deployment(
&user_email,
&form.farmer_email,
&form.resource_provider_email,
&form.node_id,
&form.combination_id,
form.quantity,
@@ -1231,7 +1231,7 @@ impl MarketplaceController {
meta.insert("deployment_type".to_string(), serde_json::Value::String(form.deployment_type.clone()));
meta.insert("deployment_name".to_string(), serde_json::Value::String(form.deployment_name.clone()));
meta.insert("quantity".to_string(), serde_json::Value::Number(serde_json::Number::from(form.quantity)));
meta.insert("farmer_email".to_string(), serde_json::Value::String(form.farmer_email.clone()));
meta.insert("resource_provider_email".to_string(), serde_json::Value::String(form.resource_provider_email.clone()));
serde_json::Value::Object(meta.into_iter().collect())
}),
category: "slice_rental".to_string(),
@@ -1270,7 +1270,7 @@ impl MarketplaceController {
/// Request structure for slice rental with deployment options
#[derive(serde::Deserialize)]
pub struct SliceRentalRequest {
pub farmer_email: String,
pub resource_provider_email: String,
pub node_id: String,
pub combination_id: String,
pub quantity: u32,
@@ -1503,7 +1503,7 @@ fn reconstruct_service_from_json(service_value: &serde_json::Value) -> Result<cr
// Attempt to rent the slice combination
match slice_rental_service.rent_slice_combination(
&user_email,
&form.farmer_email,
&form.resource_provider_email,
&form.node_id,
&form.combination_id,
form.quantity,
@@ -1602,7 +1602,7 @@ fn reconstruct_service_from_json(service_value: &serde_json::Value) -> Result<cr
// Create SliceAssignmentRequest from the data
let assignment_request_obj = SliceAssignmentRequest {
user_email: user_email.clone(),
farmer_email: assignment_request.get("farmer_email")
resource_provider_email: assignment_request.get("resource_provider_email")
.and_then(|v| v.as_str())
.unwrap_or("unknown@example.com")
.to_string(),

View File

@@ -88,8 +88,8 @@ impl PublicController {
render_template(&tmpl, "legal/terms.html", &ctx)
}
/// Renders the farmers terms page
pub async fn terms_farmers(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
/// Renders the resource providers terms page
pub async fn terms_resource_providers(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
let mut ctx = crate::models::builders::ContextBuilder::new()
.build();
ctx.insert("active_page", "terms");
@@ -105,7 +105,7 @@ impl PublicController {
}
}
render_template(&tmpl, "legal/terms-farmers.html", &ctx)
render_template(&tmpl, "legal/terms-resource_providers.html", &ctx)
}
/// Renders the service providers terms page

View File

@@ -173,7 +173,7 @@ impl RentalController {
rental_id: rental_id.clone(),
slice_combination_id: format!("combo-{}", rental_id),
node_id: "node-placeholder".to_string(), // TODO: Get from product
farmer_email: "farmer@example.com".to_string(), // TODO: Get from product
resource_provider_email: "resource_provider@example.com".to_string(), // TODO: Get from product
slice_allocation: crate::services::slice_calculator::SliceAllocation {
allocation_id: format!("alloc-{}", rental_id),
slice_combination_id: format!("combo-{}", rental_id),

View File

@@ -33,5 +33,5 @@ pub mod utils;
// Re-export commonly used types
pub use models::user::{User, NodeStakingOptions, FarmNode};
pub use services::farmer::FarmerService;
pub use services::resource_provider::ResourceProviderService;
pub use services::user_persistence::UserPersistence;

View File

@@ -1234,11 +1234,11 @@ impl SessionDataBuilder {
// MockDataBuilder removed - using persistent data only
// =============================================================================
// FARMER DATA BUILDER
// RESOURCE_PROVIDER DATA BUILDER
// =============================================================================
#[derive(Default)]
pub struct FarmerDataBuilder {
pub struct ResourceProviderDataBuilder {
total_nodes: Option<i32>,
online_nodes: Option<i32>,
total_capacity: Option<crate::models::user::NodeCapacity>,
@@ -1251,7 +1251,7 @@ pub struct FarmerDataBuilder {
active_slices: Option<i32>,
}
impl FarmerDataBuilder {
impl ResourceProviderDataBuilder {
pub fn new() -> Self {
Self::default()
}
@@ -1373,8 +1373,8 @@ impl FarmerDataBuilder {
self
}
pub fn build(self) -> Result<crate::models::user::FarmerData, String> {
Ok(crate::models::user::FarmerData {
pub fn build(self) -> Result<crate::models::user::ResourceProviderData, String> {
Ok(crate::models::user::ResourceProviderData {
total_nodes: self.total_nodes.unwrap_or(0),
online_nodes: self.online_nodes.unwrap_or(0),
total_capacity: self.total_capacity.unwrap_or(crate::models::user::NodeCapacity {
@@ -1445,8 +1445,8 @@ impl FarmerDataBuilder {
#[derive(Default)]
pub struct SliceProductBuilder {
farmer_id: Option<String>,
farmer_name: Option<String>,
resource_provider_id: Option<String>,
resource_provider_name: Option<String>,
slice_name: Option<String>,
cpu_cores: Option<i32>,
memory_gb: Option<i32>,
@@ -1464,13 +1464,13 @@ impl SliceProductBuilder {
Self::default()
}
pub fn farmer_id(mut self, farmer_id: impl Into<String>) -> Self {
self.farmer_id = Some(farmer_id.into());
pub fn resource_provider_id(mut self, resource_provider_id: impl Into<String>) -> Self {
self.resource_provider_id = Some(resource_provider_id.into());
self
}
pub fn farmer_name(mut self, farmer_name: impl Into<String>) -> Self {
self.farmer_name = Some(farmer_name.into());
pub fn resource_provider_name(mut self, resource_provider_name: impl Into<String>) -> Self {
self.resource_provider_name = Some(resource_provider_name.into());
self
}
@@ -1525,8 +1525,8 @@ impl SliceProductBuilder {
}
pub fn build(self) -> Result<crate::models::product::Product, String> {
let farmer_id = self.farmer_id.ok_or("farmer_id is required")?;
let farmer_name = self.farmer_name.ok_or("farmer_name is required")?;
let resource_provider_id = self.resource_provider_id.ok_or("resource_provider_id is required")?;
let resource_provider_name = self.resource_provider_name.ok_or("resource_provider_name is required")?;
let slice_name = self.slice_name.ok_or("slice_name is required")?;
let cpu_cores = self.cpu_cores.ok_or("cpu_cores is required")?;
let memory_gb = self.memory_gb.ok_or("memory_gb is required")?;
@@ -1552,8 +1552,8 @@ impl SliceProductBuilder {
};
Ok(crate::models::product::Product::create_slice_product(
farmer_id,
farmer_name,
resource_provider_id,
resource_provider_name,
slice_name,
slice_config,
price_per_hour,
@@ -2081,7 +2081,7 @@ impl NodeRentalBuilder {
}
#[derive(Default)]
pub struct FarmerRentalEarningBuilder {
pub struct ResourceProviderRentalEarningBuilder {
id: Option<String>,
node_id: Option<String>,
rental_id: Option<String>,
@@ -2093,7 +2093,7 @@ pub struct FarmerRentalEarningBuilder {
payment_status: Option<crate::models::user::PaymentStatus>,
}
impl FarmerRentalEarningBuilder {
impl ResourceProviderRentalEarningBuilder {
pub fn new() -> Self {
Self::default()
}
@@ -2143,10 +2143,10 @@ impl FarmerRentalEarningBuilder {
self
}
pub fn build(self) -> Result<crate::models::user::FarmerRentalEarning, String> {
pub fn build(self) -> Result<crate::models::user::ResourceProviderRentalEarning, String> {
let id = self.id.unwrap_or_else(|| format!("earning_{}", uuid::Uuid::new_v4()));
Ok(crate::models::user::FarmerRentalEarning {
Ok(crate::models::user::ResourceProviderRentalEarning {
id,
node_id: self.node_id.ok_or("node_id is required")?,
rental_id: self.rental_id.ok_or("rental_id is required")?,
@@ -2469,8 +2469,8 @@ impl NodeCreationDataBuilder {
self
}
pub fn build(self) -> Result<crate::services::farmer::NodeCreationData, String> {
Ok(crate::services::farmer::NodeCreationData {
pub fn build(self) -> Result<crate::services::resource_provider::NodeCreationData, String> {
Ok(crate::services::resource_provider::NodeCreationData {
name: self.name.ok_or("name is required")?,
location: self.location.ok_or("location is required")?,
cpu_cores: self.cpu_cores.unwrap_or(4),

View File

@@ -305,10 +305,10 @@ pub enum SliceType {
}
impl Product {
/// Create a slice product from farmer configuration
/// Create a slice product from resource_provider configuration
pub fn create_slice_product(
farmer_id: String,
farmer_name: String,
resource_provider_id: String,
resource_provider_name: String,
slice_name: String,
slice_config: SliceConfiguration,
price_per_hour: Decimal,
@@ -322,8 +322,8 @@ impl Product {
slice_config.cpu_cores, slice_config.memory_gb, slice_config.storage_gb),
price_per_hour,
"USD".to_string(),
farmer_id,
farmer_name,
resource_provider_id,
resource_provider_name,
);
// Add slice-specific attributes
@@ -448,8 +448,8 @@ impl Product {
/// Create a full node product from a FarmNode
pub fn create_full_node_product(
node: &crate::models::user::FarmNode,
farmer_email: &str,
farmer_name: &str,
resource_provider_email: &str,
resource_provider_name: &str,
) -> Self {
let mut product = Product {
id: format!("fullnode_{}", node.id),
@@ -469,8 +469,8 @@ impl Product {
.unwrap_or_else(|| Decimal::from(200)), // Default price
base_currency: "USD".to_string(),
attributes: HashMap::new(),
provider_id: farmer_email.to_string(),
provider_name: farmer_name.to_string(),
provider_id: resource_provider_email.to_string(),
provider_name: resource_provider_name.to_string(),
availability: match node.availability_status {
crate::models::user::NodeAvailabilityStatus::Available => ProductAvailability::Available,
crate::models::user::NodeAvailabilityStatus::PartiallyRented => ProductAvailability::Limited,

View File

@@ -146,7 +146,7 @@ pub struct RegionDeployments {
pub gateways: i32,
}
/// Node information for farmer dashboard
/// Node information for resource_provider dashboard
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeInfo {
pub id: String,
@@ -200,14 +200,14 @@ impl std::fmt::Display for NodeStatus {
}
}
/// Default maintenance window for farmer settings
/// Default maintenance window for resource_provider settings
pub fn default_maintenance_window() -> String {
"02:00-04:00 UTC".to_string()
}
/// Farmer configuration settings
/// ResourceProvider configuration settings
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FarmerSettings {
pub struct ResourceProviderSettings {
pub auto_accept_reserved_slices: bool,
pub maintenance_window: String, // e.g., "02:00-04:00 UTC"
pub notification_email: Option<String>,
@@ -229,7 +229,7 @@ pub struct FarmerSettings {
pub preferred_regions: Vec<String>,
}
impl Default for FarmerSettings {
impl Default for ResourceProviderSettings {
fn default() -> Self {
Self {
auto_accept_reserved_slices: true,
@@ -324,7 +324,7 @@ impl Default for LiquidityPoolConfig {
}
}
impl Default for FarmerData {
impl Default for ResourceProviderData {
fn default() -> Self {
Self {
total_nodes: 0,
@@ -761,9 +761,9 @@ pub struct QuickAction {
pub enabled: bool,
}
/// Farmer-specific data
/// ResourceProvider-specific data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FarmerData {
pub struct ResourceProviderData {
pub total_nodes: i32,
pub active_nodes: i32,
pub total_monthly_earnings_usd: i32,
@@ -1224,7 +1224,7 @@ where
.map_err(serde::de::Error::custom)
}
/// Node group for farmer organization
/// Node group for resource_provider organization
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeGroup {
pub id: String,
@@ -1358,7 +1358,7 @@ pub struct NodeCapacity {
pub ram_gb: i32,
}
/// Farmer node information
/// ResourceProvider node information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FarmNode {
pub id: String,
@@ -1418,7 +1418,7 @@ pub struct FarmNode {
pub health_score: f32,
}
/// Earnings record for farmer data
/// Earnings record for resource_provider data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EarningsRecord {
pub date: String,
@@ -1428,7 +1428,7 @@ pub struct EarningsRecord {
pub source: String,
}
/// Group statistics for farmer dashboard
/// Group statistics for resource_provider dashboard
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroupStatistics {
pub group_name: String,
@@ -1517,7 +1517,7 @@ pub struct GridNodeData {
/// Additional missing user model types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FarmerRentalEarning {
pub struct ResourceProviderRentalEarning {
pub date: String,
pub amount: Decimal,
pub rental_id: String,

View File

@@ -52,7 +52,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
.route("/marketplace/services", web::get().to(MarketplaceController::services))
.route("/marketplace/statistics", web::get().to(MarketplaceController::statistics))
// Slice rental routes
.route("/marketplace/slice/rent/{farmer_email}/{node_id}/{combination_id}", web::get().to(MarketplaceController::show_slice_rental_form))
.route("/marketplace/slice/rent/{resource_provider_email}/{node_id}/{combination_id}", web::get().to(MarketplaceController::show_slice_rental_form))
.route("/marketplace/slice/rent", web::post().to(MarketplaceController::process_slice_rental))
// .route("/marketplace/rent-slice", web::post().to(MarketplaceController::rent_slice)) // Legacy route [DISABLED]
// Product routes
@@ -107,7 +107,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
.route("/dashboard/slice-rentals/{id}/manage", web::post().to(DashboardController::manage_slice_rental_deployment))
.route("/dashboard/slice-rentals/{id}", web::delete().to(DashboardController::cancel_slice_rental))
.route("/dashboard/user/slice-rentals/{id}", web::post().to(DashboardController::manage_slice_rental))
.route("/dashboard/farmer-data", web::get().to(DashboardController::farmer_data_api))
.route("/dashboard/resource_provider-data", web::get().to(DashboardController::resource_provider_data_api))
.route("/dashboard/app-provider-data", web::get().to(DashboardController::app_provider_data_api))
.route("/dashboard/slice-products", web::get().to(DashboardController::get_slice_products))
.route("/dashboard/slice-products", web::post().to(DashboardController::create_slice_product))
@@ -116,19 +116,19 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
.route("/dashboard/slice-details/{id}", web::get().to(DashboardController::get_slice_details))
.route("/dashboard/slice-configuration/{id}", web::put().to(DashboardController::update_slice_configuration))
.route("/dashboard/service-provider-data", web::get().to(DashboardController::service_provider_data_api))
// Farmer management API routes
.route("/dashboard/farm-nodes", web::post().to(DashboardController::add_farm_node))
.route("/dashboard/farm-nodes-enhanced", web::post().to(DashboardController::add_farm_node_enhanced))
.route("/dashboard/farm-nodes/{id}", web::get().to(DashboardController::get_node_details))
.route("/dashboard/farm-nodes/{id}", web::put().to(DashboardController::update_node_comprehensive))
.route("/dashboard/farm-nodes/{id}/status", web::put().to(DashboardController::update_node_status))
// Farmer slice management API routes
.route("/dashboard/farmer/slice-calculations/refresh", web::post().to(DashboardController::refresh_slice_calculations))
.route("/dashboard/farmer/grid-sync", web::post().to(DashboardController::sync_with_grid))
.route("/dashboard/farmer/nodes/{id}/slices", web::get().to(DashboardController::get_node_slices))
.route("/dashboard/farmer/slice-statistics", web::get().to(DashboardController::get_slice_statistics))
.route("/dashboard/farm-nodes/{id}", web::delete().to(DashboardController::delete_node))
.route("/dashboard/farm-nodes/{id}/configuration", web::put().to(DashboardController::update_node_configuration))
// Resource provider management API routes
.route("/dashboard/resource_provider-nodes", web::post().to(DashboardController::add_resource_provider_node))
.route("/dashboard/resource_provider-nodes-enhanced", web::post().to(DashboardController::add_resource_provider_node_enhanced))
.route("/dashboard/resource_provider-nodes/{id}", web::get().to(DashboardController::get_node_details))
.route("/dashboard/resource_provider-nodes/{id}", web::put().to(DashboardController::update_node_comprehensive))
.route("/dashboard/resource_provider-nodes/{id}/status", web::put().to(DashboardController::update_node_status))
// Resource provider slice management API routes
.route("/dashboard/resource_provider/slice-calculations/refresh", web::post().to(DashboardController::refresh_slice_calculations))
.route("/dashboard/resource_provider/grid-sync", web::post().to(DashboardController::sync_with_grid))
.route("/dashboard/resource_provider/nodes/{id}/slices", web::get().to(DashboardController::get_node_slices))
.route("/dashboard/resource_provider/slice-statistics", web::get().to(DashboardController::get_slice_statistics))
.route("/dashboard/resource_provider-nodes/{id}", web::delete().to(DashboardController::delete_node))
.route("/dashboard/resource_provider-nodes/{id}/configuration", web::put().to(DashboardController::update_node_configuration))
.route("/dashboard/default-slice-formats", web::get().to(DashboardController::get_default_slice_formats))
.route("/dashboard/default-slice-details/{id}", web::get().to(DashboardController::get_default_slice_details))
.route("/dashboard/default-slice-customization/{id}", web::put().to(DashboardController::save_default_slice_customization))
@@ -148,8 +148,8 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
.route("/dashboard/node-groups/{id}", web::delete().to(DashboardController::delete_custom_node_group))
.route("/dashboard/nodes/assign-group", web::post().to(DashboardController::assign_node_to_group))
// Node staking API routes
.route("/dashboard/farm-nodes/{id}/stake", web::post().to(DashboardController::stake_on_node))
.route("/dashboard/farm-nodes/{id}/staking", web::put().to(DashboardController::update_node_staking))
.route("/dashboard/resource_provider-nodes/{id}/stake", web::post().to(DashboardController::stake_on_node))
.route("/dashboard/resource_provider-nodes/{id}/staking", web::put().to(DashboardController::update_node_staking))
.route("/dashboard/staking/statistics", web::get().to(DashboardController::get_staking_statistics))
// Service management API routes
.route("/dashboard/services", web::get().to(DashboardController::get_user_services))
@@ -260,7 +260,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
.wrap(JwtAuth) // Apply authentication middleware to all dashboard routes
.route("", web::get().to(DashboardController::index))
.route("/user", web::get().to(DashboardController::user_section))
.route("/farmer", web::get().to(DashboardController::farmer_section))
.route("/resource_provider", web::get().to(DashboardController::resource_provider_section))
.route("/app-provider", web::get().to(DashboardController::app_provider_section))
.route("/service-provider", web::get().to(DashboardController::service_provider_section))
@@ -282,7 +282,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
// Public information routes (legal, changelog, roadmap)
.route("/privacy", web::get().to(PublicController::privacy))
.route("/terms", web::get().to(PublicController::terms))
.route("/terms/farmers", web::get().to(PublicController::terms_farmers))
.route("/terms/resource_providers", web::get().to(PublicController::terms_resource_providers))
.route("/terms/service-providers", web::get().to(PublicController::terms_service_providers))
.route("/terms/solution-providers", web::get().to(PublicController::terms_solution_providers))
.route("/terms/users", web::get().to(PublicController::terms_users))

View File

@@ -2,7 +2,7 @@
pub mod auto_topup;
pub mod currency;
pub mod factory;
pub mod farmer;
pub mod resource_provider;
pub mod grid;
pub mod instant_purchase;
pub mod navbar;

View File

@@ -1,4 +1,4 @@
//! Node marketplace service for aggregating farmer nodes into marketplace products
//! Node marketplace service for aggregating resource_provider nodes into marketplace products
//! Follows the established builder pattern for consistent API design
use crate::models::user::FarmNode;
@@ -11,7 +11,7 @@ use rust_decimal::prelude::ToPrimitive;
use std::collections::HashMap;
use std::str::FromStr;
/// Service for converting farmer nodes to marketplace products
/// Service for converting resource_provider nodes to marketplace products
#[derive(Clone)]
pub struct NodeMarketplaceService {
currency_service: CurrencyService,
@@ -89,7 +89,7 @@ impl NodeMarketplaceService {
}
}
/// Get all farmer nodes as marketplace products
/// Get all resource_provider nodes as marketplace products
pub fn get_all_marketplace_nodes(&self) -> Vec<Product> {
let mut all_products = Vec::new();
@@ -125,16 +125,16 @@ impl NodeMarketplaceService {
}
/// Convert FarmNode to Product using builder pattern
pub fn convert_node_to_product(&self, node: &FarmNode, farmer_email: &str) -> Result<Product, String> {
pub fn convert_node_to_product(&self, node: &FarmNode, resource_provider_email: &str) -> Result<Product, String> {
// Calculate price based on node capacity
let hourly_price = self.calculate_node_price(node)?;
// Create product attributes with node specifications
let mut attributes = HashMap::new();
attributes.insert("farmer_email".to_string(), crate::models::product::ProductAttribute {
key: "farmer_email".to_string(),
value: serde_json::Value::String(farmer_email.to_string()),
attributes.insert("resource_provider_email".to_string(), crate::models::product::ProductAttribute {
key: "resource_provider_email".to_string(),
value: serde_json::Value::String(resource_provider_email.to_string()),
attribute_type: crate::models::product::AttributeType::Text,
is_searchable: true,
is_filterable: true,
@@ -200,8 +200,8 @@ impl NodeMarketplaceService {
display_order: Some(6),
});
// Get farmer display name
let farmer_display_name = self.get_farmer_display_name(farmer_email);
// Get resource_provider display name
let resource_provider_display_name = self.get_resource_provider_display_name(resource_provider_email);
// Create metadata with location
let metadata = crate::models::product::ProductMetadata {
@@ -215,7 +215,7 @@ impl NodeMarketplaceService {
// Use Product builder pattern with add_attribute for each attribute
let mut builder = crate::models::product::Product::builder()
.id(format!("node_{}", node.id))
.name(format!("{} - {}", node.name, farmer_display_name))
.name(format!("{} - {}", node.name, resource_provider_display_name))
.description(format!("Mycelium Node with {} CPU cores, {} GB RAM, {} GB storage in {}. Uptime: {:.1}%, Health Score: {:.1}",
node.capacity.cpu_cores,
node.capacity.memory_gb,
@@ -226,8 +226,8 @@ impl NodeMarketplaceService {
.base_price(hourly_price)
.base_currency("USD".to_string())
.category_id("hardware".to_string())
.provider_id(farmer_email.to_string())
.provider_name(farmer_display_name)
.provider_id(resource_provider_email.to_string())
.provider_name(resource_provider_display_name)
.metadata(metadata)
.availability(if self.is_node_online(node) {
crate::models::product::ProductAvailability::Available
@@ -276,17 +276,17 @@ impl NodeMarketplaceService {
format!("{}", node.status) == "Online"
}
/// Get farmer display name from email
fn get_farmer_display_name(&self, farmer_email: &str) -> String {
/// Get resource_provider display name from email
fn get_resource_provider_display_name(&self, resource_provider_email: &str) -> String {
// Try to get actual name from persistent data
if let Some(user_data) = UserPersistence::load_user_data(farmer_email) {
if let Some(user_data) = UserPersistence::load_user_data(resource_provider_email) {
if let Some(name) = user_data.name {
return name;
}
}
// Fallback to email username
farmer_email.split('@').next().unwrap_or("Farmer").to_string()
resource_provider_email.split('@').next().unwrap_or("ResourceProvider").to_string()
}
/// Apply marketplace filters to node products
@@ -438,7 +438,7 @@ impl NodeMarketplaceService {
let mut total_cpu_cores = 0u32;
let mut total_memory_gb = 0u32;
let mut total_storage_gb = 0u32;
let mut unique_farmers = std::collections::HashSet::new();
let mut unique_resource_providers = std::collections::HashSet::new();
let mut unique_locations = std::collections::HashSet::new();
for product in &all_slices {
@@ -456,8 +456,8 @@ impl NodeMarketplaceService {
total_storage_gb += (storage * quantity) as u32;
}
if let Some(farmer) = product.attributes.get("farmer_email").and_then(|f| f.value.as_str()) {
unique_farmers.insert(farmer.to_string());
if let Some(resource_provider) = product.attributes.get("resource_provider_email").and_then(|f| f.value.as_str()) {
unique_resource_providers.insert(resource_provider.to_string());
}
if let Some(location) = &product.metadata.location {
@@ -471,9 +471,9 @@ impl NodeMarketplaceService {
"total_cpu_cores": total_cpu_cores,
"total_memory_gb": total_memory_gb,
"total_storage_gb": total_storage_gb,
"unique_farmers": unique_farmers.len(),
"unique_resource_providers": unique_resource_providers.len(),
"unique_locations": unique_locations.len(),
"farmers": unique_farmers.into_iter().collect::<Vec<_>>(),
"resource_providers": unique_resource_providers.into_iter().collect::<Vec<_>>(),
"locations": unique_locations.into_iter().collect::<Vec<_>>()
})
}
@@ -531,7 +531,7 @@ impl NodeMarketplaceService {
pub fn get_all_slice_combinations(&self) -> Vec<Product> {
let mut all_slice_products = Vec::new();
// Read all user data files to find farmers with nodes
// Read all user data files to find resource_providers with nodes
if let Ok(entries) = std::fs::read_dir("./user_data") {
for entry in entries.flatten() {
if let Some(filename) = entry.file_name().to_str() {
@@ -585,14 +585,14 @@ impl NodeMarketplaceService {
&self,
combination: &SliceCombination,
_node: &FarmNode,
farmer_email: &str
resource_provider_email: &str
) -> Result<Product, String> {
let mut attributes = HashMap::new();
// Farmer information
attributes.insert("farmer_email".to_string(), crate::models::product::ProductAttribute {
key: "farmer_email".to_string(),
value: serde_json::Value::String(farmer_email.to_string()),
// ResourceProvider information
attributes.insert("resource_provider_email".to_string(), crate::models::product::ProductAttribute {
key: "resource_provider_email".to_string(),
value: serde_json::Value::String(resource_provider_email.to_string()),
attribute_type: crate::models::product::AttributeType::Text,
is_searchable: true,
is_filterable: true,
@@ -701,15 +701,15 @@ impl NodeMarketplaceService {
display_order: Some(10),
});
// Get farmer display name
let farmer_display_name = self.get_farmer_display_name(farmer_email);
// Get resource_provider display name
let resource_provider_display_name = self.get_resource_provider_display_name(resource_provider_email);
// Create metadata
let metadata = crate::models::product::ProductMetadata {
location: Some(combination.node_location.clone()),
custom_fields: {
let mut fields = std::collections::HashMap::new();
fields.insert("provider".to_string(), serde_json::Value::String(farmer_display_name.clone()));
fields.insert("provider".to_string(), serde_json::Value::String(resource_provider_display_name.clone()));
fields.insert("certification".to_string(), serde_json::Value::String(combination.node_certification_type.clone()));
fields.insert("created_at".to_string(), serde_json::Value::String(chrono::Utc::now().to_rfc3339()));
fields.insert("updated_at".to_string(), serde_json::Value::String(chrono::Utc::now().to_rfc3339()));
@@ -727,7 +727,7 @@ impl NodeMarketplaceService {
// Build product using the builder pattern
let mut product = crate::models::product::Product::builder()
.id(format!("slice_{}_{}", combination.node_id, combination.id))
.name(format!("{} Slice ({}x Base Unit)", farmer_display_name, combination.multiplier))
.name(format!("{} Slice ({}x Base Unit)", resource_provider_display_name, combination.multiplier))
.description(format!(
"Compute slice with {} vCPU, {}GB RAM, {}GB storage from {} ({}% uptime)",
combination.cpu_cores,
@@ -739,8 +739,8 @@ impl NodeMarketplaceService {
.category_id("compute_slices".to_string())
.base_price(combination.price_per_hour)
.base_currency("USD".to_string())
.provider_id(farmer_email.to_string())
.provider_name(farmer_display_name)
.provider_id(resource_provider_email.to_string())
.provider_name(resource_provider_display_name)
.metadata(metadata)
.build()
.map_err(|e| format!("Failed to build slice product: {}", e))?;

View File

@@ -1,7 +1,7 @@
//! Node rental service for managing node rentals and farmer earnings
//! Node rental service for managing node rentals and resource_provider earnings
//! Follows the established builder pattern for consistent API design
use crate::models::user::{NodeRental, NodeRentalType, NodeRentalStatus, FarmerRentalEarning, PaymentStatus, NodeAvailabilityStatus};
use crate::models::user::{NodeRental, NodeRentalType, NodeRentalStatus, ResourceProviderRentalEarning, PaymentStatus, NodeAvailabilityStatus};
use crate::services::user_persistence::{UserPersistence, ProductRental};
use rust_decimal::Decimal;
use chrono::{Utc, Duration};
@@ -65,7 +65,7 @@ impl NodeRentalService {
duration_months: u32,
rental_type: NodeRentalType,
monthly_cost: Decimal,
) -> Result<(NodeRental, FarmerRentalEarning), String> {
) -> Result<(NodeRental, ResourceProviderRentalEarning), String> {
// Extract node ID from product ID
let node_id = if product_id.starts_with("fullnode_") {
product_id.strip_prefix("fullnode_").unwrap_or(product_id)
@@ -99,8 +99,8 @@ impl NodeRentalService {
.payment_method("USD".to_string())
.build()?;
// Create farmer earning record
let farmer_earning = crate::models::builders::FarmerRentalEarningBuilder::new()
// Create resource_provider earning record
let resource_provider_earning = crate::models::builders::ResourceProviderRentalEarningBuilder::new()
.node_id(node_id.to_string())
.rental_id(rental.id.clone())
.renter_email(renter_email.to_string())
@@ -111,29 +111,29 @@ impl NodeRentalService {
.payment_status(PaymentStatus::Completed)
.build()?;
// Find the farmer who owns this node
let farmer_email = self.find_node_owner(node_id)?;
// Find the resource_provider who owns this node
let resource_provider_email = self.find_node_owner(node_id)?;
// Save rental to renter's data
self.save_rental_to_user(&rental, renter_email, product_id)?;
// Save earning to farmer's data
self.save_earning_to_farmer(&farmer_earning, &farmer_email)?;
// Save earning to resource_provider's data
self.save_earning_to_resource_provider(&resource_provider_earning, &resource_provider_email)?;
// Update node availability status
self.update_node_availability(node_id, &farmer_email)?;
self.update_node_availability(node_id, &resource_provider_email)?;
Ok((rental, farmer_earning))
Ok((rental, resource_provider_earning))
}
/// Check for rental conflicts
fn check_rental_conflicts(&self, node_id: &str, rental_type: &NodeRentalType) -> Result<(), String> {
// Find the farmer who owns this node
let farmer_email = self.find_node_owner(node_id)?;
// Find the resource_provider who owns this node
let resource_provider_email = self.find_node_owner(node_id)?;
if let Some(farmer_data) = UserPersistence::load_user_data(&farmer_email) {
if let Some(resource_provider_data) = UserPersistence::load_user_data(&resource_provider_email) {
// Check existing rentals for this node
let existing_rentals: Vec<_> = farmer_data.node_rentals.iter()
let existing_rentals: Vec<_> = resource_provider_data.node_rentals.iter()
.filter(|r| r.node_id == node_id && r.is_active())
.collect();
@@ -166,7 +166,7 @@ impl NodeRentalService {
Ok(())
}
/// Find the farmer who owns a specific node
/// Find the resource_provider who owns a specific node
fn find_node_owner(&self, node_id: &str) -> Result<String, String> {
// Scan all user files to find the node owner
if let Ok(entries) = std::fs::read_dir("./user_data/") {
@@ -226,31 +226,31 @@ impl NodeRentalService {
Ok(())
}
/// Save earning record to farmer's persistent data
fn save_earning_to_farmer(&self, earning: &FarmerRentalEarning, farmer_email: &str) -> Result<(), String> {
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
.unwrap_or_else(|| self.create_default_user_data(farmer_email));
/// Save earning record to resource_provider's persistent data
fn save_earning_to_resource_provider(&self, earning: &ResourceProviderRentalEarning, resource_provider_email: &str) -> Result<(), String> {
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
.unwrap_or_else(|| self.create_default_user_data(resource_provider_email));
// Add to farmer rental earnings
farmer_data.farmer_rental_earnings.push(earning.clone());
// Add to resource_provider rental earnings
resource_provider_data.resource_provider_rental_earnings.push(earning.clone());
// Update wallet balance
farmer_data.wallet_balance_usd += earning.amount;
resource_provider_data.wallet_balance_usd += earning.amount;
UserPersistence::save_user_data(&farmer_data)
.map_err(|e| format!("Failed to save farmer data: {}", e))?;
UserPersistence::save_user_data(&resource_provider_data)
.map_err(|e| format!("Failed to save resource_provider data: {}", e))?;
Ok(())
}
/// Update node availability status based on current rentals
fn update_node_availability(&self, node_id: &str, farmer_email: &str) -> Result<(), String> {
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
.ok_or("Farmer data not found")?;
fn update_node_availability(&self, node_id: &str, resource_provider_email: &str) -> Result<(), String> {
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
.ok_or("ResourceProvider data not found")?;
if let Some(node) = farmer_data.nodes.iter_mut().find(|n| n.id == node_id) {
if let Some(node) = resource_provider_data.nodes.iter_mut().find(|n| n.id == node_id) {
// Count active rentals for this node
let active_rentals: Vec<_> = farmer_data.node_rentals.iter()
let active_rentals: Vec<_> = resource_provider_data.node_rentals.iter()
.filter(|r| r.node_id == node_id && r.is_active())
.collect();
@@ -262,7 +262,7 @@ impl NodeRentalService {
NodeAvailabilityStatus::PartiallyRented
};
UserPersistence::save_user_data(&farmer_data)
UserPersistence::save_user_data(&resource_provider_data)
.map_err(|e| format!("Failed to update node availability: {}", e))?;
}
@@ -285,10 +285,10 @@ impl NodeRentalService {
}
}
/// Get farmer earnings from rentals
pub fn get_farmer_rental_earnings(&self, farmer_email: &str) -> Vec<FarmerRentalEarning> {
if let Some(farmer_data) = UserPersistence::load_user_data(farmer_email) {
farmer_data.farmer_rental_earnings
/// Get resource_provider earnings from rentals
pub fn get_resource_provider_rental_earnings(&self, resource_provider_email: &str) -> Vec<ResourceProviderRentalEarning> {
if let Some(resource_provider_data) = UserPersistence::load_user_data(resource_provider_email) {
resource_provider_data.resource_provider_rental_earnings
} else {
Vec::new()
}
@@ -309,8 +309,8 @@ impl NodeRentalService {
}
// Update node availability
let farmer_email = self.find_node_owner(&rental.node_id)?;
self.update_node_availability(&rental.node_id, &farmer_email)?;
let resource_provider_email = self.find_node_owner(&rental.node_id)?;
self.update_node_availability(&rental.node_id, &resource_provider_email)?;
UserPersistence::save_user_data(&user_data)
.map_err(|e| format!("Failed to save user data: {}", e))?;

View File

@@ -241,8 +241,8 @@ impl ProductService {
if let Some(combination_id) = product.attributes.get("combination_id") {
details["combination_id"] = combination_id.value.clone();
}
if let Some(farmer_email) = product.attributes.get("farmer_email") {
details["farmer_email"] = farmer_email.value.clone();
if let Some(resource_provider_email) = product.attributes.get("resource_provider_email") {
details["resource_provider_email"] = resource_provider_email.value.clone();
}
if let Some(cpu_cores) = product.attributes.get("cpu_cores") {
details["cpu_cores"] = cpu_cores.value.clone();

View File

@@ -1,4 +1,4 @@
//! Farmer service for managing nodes, slice allocation, and earnings
//! ResourceProvider service for managing nodes, slice allocation, and earnings
//! Follows the established builder pattern for consistent API design
use crate::models::user::{FarmNode, NodeCapacity, NodeStatus, EarningsRecord, NodeGroup, GroupStatistics, MarketplaceSLA};
@@ -12,7 +12,7 @@ use std::str::FromStr;
use chrono::{Utc, DateTime};
use serde::{Serialize, Deserialize};
/// Staking statistics for a farmer
/// Staking statistics for a resource_provider
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StakingStatistics {
pub total_staked_amount: Decimal,
@@ -30,25 +30,25 @@ impl Default for StakingStatistics {
}
}
/// Service for farmer-specific operations
/// Service for resource_provider-specific operations
#[derive(Clone)]
pub struct FarmerService {
pub struct ResourceProviderService {
auto_sync_enabled: bool,
metrics_collection: bool,
grid_service: GridService,
slice_calculator: SliceCalculatorService,
}
/// Builder for FarmerService
/// Builder for ResourceProviderService
#[derive(Default)]
pub struct FarmerServiceBuilder {
pub struct ResourceProviderServiceBuilder {
auto_sync_enabled: Option<bool>,
metrics_collection: Option<bool>,
grid_service: Option<GridService>,
slice_calculator: Option<SliceCalculatorService>,
}
impl FarmerServiceBuilder {
impl ResourceProviderServiceBuilder {
pub fn new() -> Self {
Self::default()
}
@@ -73,7 +73,7 @@ impl FarmerServiceBuilder {
self
}
pub fn build(self) -> Result<FarmerService, String> {
pub fn build(self) -> Result<ResourceProviderService, String> {
let grid_service = self.grid_service.unwrap_or_else(|| {
GridService::builder().build().expect("Failed to create default GridService")
});
@@ -82,7 +82,7 @@ impl FarmerServiceBuilder {
SliceCalculatorService::builder().build().expect("Failed to create default SliceCalculatorService")
});
Ok(FarmerService {
Ok(ResourceProviderService {
auto_sync_enabled: self.auto_sync_enabled.unwrap_or(true),
metrics_collection: self.metrics_collection.unwrap_or(true),
grid_service,
@@ -91,13 +91,13 @@ impl FarmerServiceBuilder {
}
}
impl FarmerService {
pub fn builder() -> FarmerServiceBuilder {
FarmerServiceBuilder::new()
impl ResourceProviderService {
pub fn builder() -> ResourceProviderServiceBuilder {
ResourceProviderServiceBuilder::new()
}
/// Get all nodes for a farmer
pub fn get_farmer_nodes(&self, user_email: &str) -> Vec<FarmNode> {
/// Get all nodes for a resource_provider
pub fn get_resource_provider_nodes(&self, user_email: &str) -> Vec<FarmNode> {
if let Some(data) = UserPersistence::load_user_data(user_email) {
// Debug: Log marketplace SLA data for all nodes
for node in &data.nodes {
@@ -111,10 +111,10 @@ impl FarmerService {
}
}
/// Add a new node for a farmer (manual creation)
/// Add a new node for a resource_provider (manual creation)
pub fn add_node(&self, user_email: &str, node_data: NodeCreationData) -> Result<FarmNode, String> {
// Check for duplicate node names first
let existing_nodes = self.get_farmer_nodes(user_email);
let existing_nodes = self.get_resource_provider_nodes(user_email);
if existing_nodes.iter().any(|n| n.name == node_data.name) {
return Err(format!("Node '{}' is already registered", node_data.name));
}
@@ -234,7 +234,7 @@ impl FarmerService {
.map_err(|e| e.to_string())?;
// Auto-generate marketplace products if rental options are configured
self.auto_generate_marketplace_products(&node, user_email, &persistent_data.name.unwrap_or_else(|| "Unknown Farmer".to_string()), node_data.slice_prices.as_ref())?;
self.auto_generate_marketplace_products(&node, user_email, &persistent_data.name.unwrap_or_else(|| "Unknown ResourceProvider".to_string()), node_data.slice_prices.as_ref())?;
Ok(node)
}
@@ -434,10 +434,10 @@ impl FarmerService {
/// Sync node capacity and slices with grid data
pub async fn sync_node_with_grid(&self, user_email: &str, node_id: &str) -> Result<(), String> {
let mut farmer_data = UserPersistence::load_user_data(user_email)
.ok_or("Farmer data not found")?;
let mut resource_provider_data = UserPersistence::load_user_data(user_email)
.ok_or("ResourceProvider data not found")?;
if let Some(node) = farmer_data.nodes.iter_mut().find(|n| n.id == node_id) {
if let Some(node) = resource_provider_data.nodes.iter_mut().find(|n| n.id == node_id) {
if let Some(grid_node_id) = &node.grid_node_id {
// Fetch latest capacity from grid
let grid_id: u32 = grid_node_id.parse().unwrap_or(0);
@@ -472,7 +472,7 @@ impl FarmerService {
}
// Save updated data
UserPersistence::save_user_data(&farmer_data)
UserPersistence::save_user_data(&resource_provider_data)
.map_err(|e| format!("Failed to save user data: {}", e))?;
} else {
return Err("Node is not linked to grid".to_string());
@@ -486,7 +486,7 @@ impl FarmerService {
/// Auto-generate marketplace products for a node based on rental options
/// Products are now managed through persistent user data and aggregated by ProductService
fn auto_generate_marketplace_products(&self, _node: &FarmNode, _farmer_email: &str, _farmer_name: &str, _slice_prices: Option<&std::collections::HashMap<String, rust_decimal::Decimal>>) -> Result<(), String> {
fn auto_generate_marketplace_products(&self, _node: &FarmNode, _resource_provider_email: &str, _resource_provider_name: &str, _slice_prices: Option<&std::collections::HashMap<String, rust_decimal::Decimal>>) -> Result<(), String> {
// Product generation is now handled through persistent user data
// ProductService automatically aggregates products from user-owned data
Ok(())
@@ -754,7 +754,7 @@ impl FarmerService {
}
/// Create a slice product from a node and slice format
fn create_slice_product_from_node(&self, node: &FarmNode, slice_format_id: &str, farmer_email: &str, farmer_name: &str, custom_prices: Option<&std::collections::HashMap<String, rust_decimal::Decimal>>) -> Result<crate::models::product::Product, String> {
fn create_slice_product_from_node(&self, node: &FarmNode, slice_format_id: &str, resource_provider_email: &str, resource_provider_name: &str, custom_prices: Option<&std::collections::HashMap<String, rust_decimal::Decimal>>) -> Result<crate::models::product::Product, String> {
// Get slice format details and default pricing
let (cpu_cores, memory_gb, storage_gb, bandwidth_mbps, default_price) = match slice_format_id {
"basic" => (2, 4, 100, 100, 25),
@@ -789,8 +789,8 @@ impl FarmerService {
base_price: price,
base_currency: "USD".to_string(),
attributes: std::collections::HashMap::new(),
provider_id: farmer_email.to_string(),
provider_name: farmer_name.to_string(),
provider_id: resource_provider_email.to_string(),
provider_name: resource_provider_name.to_string(),
availability: match node.availability_status {
crate::models::user::NodeAvailabilityStatus::Available => crate::models::product::ProductAvailability::Available,
crate::models::user::NodeAvailabilityStatus::PartiallyRented => crate::models::product::ProductAvailability::Limited,
@@ -880,19 +880,19 @@ impl FarmerService {
Ok(())
}
/// Get farmer earnings
pub fn get_farmer_earnings(&self, user_email: &str) -> Vec<EarningsRecord> {
/// Get resource_provider earnings
pub fn get_resource_provider_earnings(&self, user_email: &str) -> Vec<EarningsRecord> {
if let Some(data) = UserPersistence::load_user_data(user_email) {
data.farmer_earnings
data.resource_provider_earnings
} else {
Vec::new()
}
}
/// Get farmer statistics
pub fn get_farmer_statistics(&self, user_email: &str) -> FarmerStatistics {
let nodes = self.get_farmer_nodes(user_email);
let earnings = self.get_farmer_earnings(user_email);
/// Get resource_provider statistics
pub fn get_resource_provider_statistics(&self, user_email: &str) -> FarmerStatistics {
let nodes = self.get_resource_provider_nodes(user_email);
let earnings = self.get_resource_provider_earnings(user_email);
let total_nodes = nodes.len() as i32;
let online_nodes = nodes.iter()
@@ -990,7 +990,7 @@ impl FarmerService {
slice_config.bandwidth_mbps <= available_bandwidth)
}
/// Get default slice formats available to all farmers
/// Get default slice formats available to all resource providers
pub fn get_default_slice_formats(&self) -> Vec<DefaultSliceFormat> {
vec![
DefaultSliceFormat {
@@ -1039,8 +1039,8 @@ impl FarmerService {
// Load user customizations from persistent data
if let Some(persistent_data) = UserPersistence::load_user_data(user_email) {
if let Some(farmer_settings) = persistent_data.farmer_settings {
if let Some(customizations) = farmer_settings.default_slice_customizations {
if let Some(resource_provider_settings) = persistent_data.resource_provider_settings {
if let Some(customizations) = resource_provider_settings.default_slice_customizations {
if let Some(custom_format) = customizations.get(format_id) {
// Apply user customizations
if let Some(cpu_cores) = custom_format.get("cpu_cores").and_then(|v| v.as_u64()).map(|v| v as u32) {
@@ -1075,9 +1075,9 @@ impl FarmerService {
pub fn save_default_slice_customization(&self, user_email: &str, format_id: &str, customization: DefaultSliceFormat) -> Result<(), String> {
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
// Initialize farmer settings if needed
if persistent_data.farmer_settings.is_none() {
persistent_data.farmer_settings = Some(crate::models::user::FarmerSettings {
// Initialize resource_provider settings if needed
if persistent_data.resource_provider_settings.is_none() {
persistent_data.resource_provider_settings = Some(crate::models::user::FarmerSettings {
auto_accept_reserved_slices: true,
maintenance_window: "02:00-04:00 UTC".to_string(),
notification_email: None,
@@ -1096,12 +1096,12 @@ impl FarmerService {
}
// Initialize default slice customizations if needed
if let Some(ref mut farmer_settings) = persistent_data.farmer_settings {
if farmer_settings.default_slice_customizations.is_none() {
farmer_settings.default_slice_customizations = Some(serde_json::to_value(std::collections::HashMap::<String, serde_json::Value>::new()).unwrap_or_default());
if let Some(ref mut resource_provider_settings) = persistent_data.resource_provider_settings {
if resource_provider_settings.default_slice_customizations.is_none() {
resource_provider_settings.default_slice_customizations = Some(serde_json::to_value(std::collections::HashMap::<String, serde_json::Value>::new()).unwrap_or_default());
}
if let Some(ref mut customizations) = farmer_settings.default_slice_customizations {
if let Some(ref mut customizations) = resource_provider_settings.default_slice_customizations {
if let Some(obj) = customizations.as_object_mut() {
obj.insert(format_id.to_string(), serde_json::to_value(customization).unwrap_or_default());
}
@@ -1288,7 +1288,7 @@ impl FarmerService {
/// Add a node from ThreeFold Grid by node ID
pub async fn add_grid_node(&self, user_email: &str, grid_node_id: u32, _slice_format: Option<String>, _slice_price: Option<Decimal>) -> Result<FarmNode, String> {
// Check for duplicate grid node IDs first
let existing_nodes = self.get_farmer_nodes(user_email);
let existing_nodes = self.get_resource_provider_nodes(user_email);
if existing_nodes.iter().any(|n| n.grid_node_id == Some(grid_node_id.to_string())) {
return Err(format!("Node {} is already registered", grid_node_id));
}
@@ -1845,8 +1845,8 @@ impl FarmerService {
.unwrap_or(false);
if slice_rental_enabled || full_node_rental_enabled {
let farmer_name = persistent_data.name.unwrap_or_else(|| "Unknown Farmer".to_string());
self.auto_generate_marketplace_products(&node, user_email, &farmer_name, None)?;
let resource_provider_name = persistent_data.name.unwrap_or_else(|| "Unknown ResourceProvider".to_string());
self.auto_generate_marketplace_products(&node, user_email, &resource_provider_name, None)?;
}
}
Ok(node)
@@ -1856,7 +1856,7 @@ impl FarmerService {
// NODE GROUP MANAGEMENT
// =============================================================================
/// Ensure default node groups exist for a farmer
/// Ensure default node groups exist for a resource_provider
pub fn ensure_default_node_groups(&self, user_email: &str) -> Result<(), String> {
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
@@ -1898,7 +1898,7 @@ impl FarmerService {
Ok(group)
}
/// Get all node groups for a farmer (ensures defaults exist)
/// Get all node groups for a resource_provider (ensures defaults exist)
pub fn get_node_groups(&self, user_email: &str) -> Vec<NodeGroup> {
// Ensure default groups exist first
if let Err(e) = self.ensure_default_node_groups(user_email) {
@@ -2165,7 +2165,7 @@ impl FarmerService {
/// Get node by name (for duplicate checking)
pub fn get_node_by_name(&self, user_email: &str, node_name: &str) -> Option<FarmNode> {
let nodes = self.get_farmer_nodes(user_email);
let nodes = self.get_resource_provider_nodes(user_email);
nodes.into_iter().find(|n| n.name == node_name)
}
@@ -2278,12 +2278,12 @@ impl FarmerService {
Ok(())
}
/// Create default user data for new farmers
/// Create default user data for new resource providers
fn create_default_user_data(user_email: &str) -> UserPersistentData {
crate::models::builders::SessionDataBuilder::new_user(user_email)
}
/// Refresh all slice calculations for a farmer
/// Refresh all slice calculations for a resource_provider
pub fn refresh_all_slice_calculations(&self, user_email: &str) -> Result<(), String> {
let mut persistent_data = UserPersistence::load_user_data(user_email)
.ok_or("User data not found")?;
@@ -2395,7 +2395,7 @@ impl FarmerService {
Ok(slices)
}
/// Get comprehensive slice statistics for a farmer
/// Get comprehensive slice statistics for a resource_provider
pub fn get_slice_statistics(&self, user_email: &str) -> Result<serde_json::Value, String> {
let persistent_data = UserPersistence::load_user_data(user_email)
.ok_or("User data not found")?;
@@ -2821,7 +2821,7 @@ impl FarmerService {
Ok(repaired_count)
}
/// Refresh all slice calculations for a farmer (async version)
/// Refresh all slice calculations for a resource_provider (async version)
pub async fn refresh_all_slice_calculations_async(&self, user_email: &str) -> Result<u32, String> {
let mut persistent_data = UserPersistence::load_user_data(user_email)
.ok_or("User data not found")?;
@@ -2971,7 +2971,7 @@ pub struct NodeUpdateData {
pub marketplace_sla: Option<MarketplaceSLA>,
}
/// Default slice formats available to all farmers
/// Default slice formats available to all resource providers
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DefaultSliceFormat {
pub id: String,
@@ -2984,7 +2984,7 @@ pub struct DefaultSliceFormat {
pub price_per_hour: rust_decimal::Decimal,
}
/// Farmer statistics summary
/// ResourceProvider statistics summary
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FarmerStatistics {
pub total_nodes: i32,

View File

@@ -18,7 +18,7 @@ pub struct SliceAssignmentService {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SliceAssignmentRequest {
pub user_email: String,
pub farmer_email: String,
pub resource_provider_email: String,
pub node_id: String,
pub combination_id: String,
pub quantity: u32,
@@ -127,7 +127,7 @@ pub struct SecurityConfiguration {
pub struct SliceAssignment {
pub assignment_id: String,
pub user_email: String,
pub farmer_email: String,
pub resource_provider_email: String,
pub node_id: String,
pub combination_id: String,
pub slice_allocations: Vec<SliceAllocation>,
@@ -241,7 +241,7 @@ impl SliceAssignmentService {
let assignment = SliceAssignment {
assignment_id,
user_email: request.user_email,
farmer_email: request.farmer_email,
resource_provider_email: request.resource_provider_email,
node_id: request.node_id,
combination_id: request.combination_id,
slice_allocations,
@@ -377,7 +377,7 @@ impl SliceAssignmentService {
"status": "deploying",
"deployment_type": "vm",
"node_id": assignment.node_id,
"farmer_email": assignment.farmer_email,
"resource_provider_email": assignment.resource_provider_email,
"started_at": Utc::now(),
"estimated_completion": Utc::now() + chrono::Duration::minutes(5)
});

View File

@@ -42,7 +42,7 @@ pub struct SliceCombination {
pub node_location: String,
pub node_certification_type: String,
pub node_id: String,
pub farmer_email: String,
pub resource_provider_email: String,
}
/// Track individual slice rentals
@@ -70,7 +70,7 @@ pub enum AllocationStatus {
pub struct SlicePricing {
pub base_price_per_hour: Decimal, // Price for 1 base slice per hour
pub currency: String,
pub pricing_multiplier: Decimal, // Farmer can adjust pricing (0.5x - 2.0x)
pub pricing_multiplier: Decimal, // ResourceProvider can adjust pricing (0.5x - 2.0x)
}
impl Default for SlicePricing {
@@ -157,7 +157,7 @@ impl SliceCalculatorService {
max_base_slices: u32,
allocated_slices: u32,
node: &FarmNode,
farmer_email: &str
resource_provider_email: &str
) -> Vec<SliceCombination> {
let available_base_slices = max_base_slices.saturating_sub(allocated_slices);
let mut combinations = Vec::new();
@@ -208,7 +208,7 @@ impl SliceCalculatorService {
.to_string())
.unwrap_or_else(|| "DIY".to_string()),
node_id: node.id.clone(),
farmer_email: farmer_email.to_string(),
resource_provider_email: resource_provider_email.to_string(),
};
combinations.push(combination);
@@ -225,7 +225,7 @@ impl SliceCalculatorService {
max_base_slices: u32,
allocated_slices: u32,
node: &FarmNode,
farmer_email: &str,
resource_provider_email: &str,
uptime_percentage: f64,
bandwidth_mbps: u32,
base_price_per_hour: Decimal
@@ -283,7 +283,7 @@ impl SliceCalculatorService {
.to_string())
.unwrap_or_else(|| "DIY".to_string()),
node_id: node.id.clone(),
farmer_email: farmer_email.to_string(),
resource_provider_email: resource_provider_email.to_string(),
};
combinations.push(combination);
@@ -304,7 +304,7 @@ impl SliceCalculatorService {
&self,
node: &mut FarmNode,
rented_base_slices: u32,
farmer_email: &str
resource_provider_email: &str
) -> Result<(), String> {
// Update allocated count
node.allocated_base_slices += rented_base_slices as i32;
@@ -314,7 +314,7 @@ impl SliceCalculatorService {
node.total_base_slices as u32,
node.allocated_base_slices as u32,
node,
farmer_email
resource_provider_email
);
node.available_combinations = combinations.iter()
.map(|c| serde_json::to_value(c).unwrap_or_default())
@@ -328,7 +328,7 @@ impl SliceCalculatorService {
&self,
node: &mut FarmNode,
released_base_slices: u32,
farmer_email: &str
resource_provider_email: &str
) -> Result<(), String> {
// Update allocated count
node.allocated_base_slices = node.allocated_base_slices.saturating_sub(released_base_slices as i32);
@@ -338,7 +338,7 @@ impl SliceCalculatorService {
node.total_base_slices as u32,
node.allocated_base_slices as u32,
node,
farmer_email
resource_provider_email
).iter()
.map(|c| serde_json::to_value(c).unwrap_or_default())
.collect();
@@ -364,7 +364,7 @@ pub struct SliceRental {
pub rental_id: String,
pub slice_combination_id: String,
pub node_id: String,
pub farmer_email: String,
pub resource_provider_email: String,
pub slice_allocation: SliceAllocation,
pub total_cost: Decimal,
pub payment_status: PaymentStatus,

View File

@@ -56,11 +56,11 @@ impl SliceRentalService {
SliceRentalServiceBuilder::new()
}
/// Rent a slice combination from a farmer's node
/// Rent a slice combination from a resource_provider's node
pub fn rent_slice_combination(
&self,
renter_email: &str,
farmer_email: &str,
resource_provider_email: &str,
node_id: &str,
combination_id: &str,
quantity: u32,
@@ -68,9 +68,9 @@ impl SliceRentalService {
) -> Result<SliceRental, String> {
// Atomic operation with file locking to prevent conflicts
if self.enable_file_locking {
self.rent_with_file_lock(renter_email, farmer_email, node_id, combination_id, quantity, rental_duration_hours)
self.rent_with_file_lock(renter_email, resource_provider_email, node_id, combination_id, quantity, rental_duration_hours)
} else {
self.rent_without_lock(renter_email, farmer_email, node_id, combination_id, quantity, rental_duration_hours)
self.rent_without_lock(renter_email, resource_provider_email, node_id, combination_id, quantity, rental_duration_hours)
}
}
@@ -78,7 +78,7 @@ impl SliceRentalService {
pub fn rent_slice_combination_with_deployment(
&self,
renter_email: &str,
farmer_email: &str,
resource_provider_email: &str,
node_id: &str,
combination_id: &str,
quantity: u32,
@@ -89,7 +89,7 @@ impl SliceRentalService {
) -> Result<SliceRental, String> {
// First rent the slice combination
let mut rental = self.rent_slice_combination(
renter_email, farmer_email, node_id, combination_id, quantity, rental_duration_hours
renter_email, resource_provider_email, node_id, combination_id, quantity, rental_duration_hours
)?;
// Add deployment metadata to the rental
@@ -133,21 +133,21 @@ impl SliceRentalService {
fn rent_with_file_lock(
&self,
renter_email: &str,
farmer_email: &str,
resource_provider_email: &str,
node_id: &str,
combination_id: &str,
quantity: u32,
rental_duration_hours: u32,
) -> Result<SliceRental, String> {
// Create lock file
let lock_file_path = format!("./user_data/.lock_{}_{}", farmer_email.replace("@", "_"), node_id);
let lock_file_path = format!("./user_data/.lock_{}_{}", resource_provider_email.replace("@", "_"), node_id);
let _lock_file = OpenOptions::new()
.create(true)
.write(true)
.open(&lock_file_path)
.map_err(|e| format!("Failed to create lock file: {}", e))?;
let result = self.rent_without_lock(renter_email, farmer_email, node_id, combination_id, quantity, rental_duration_hours);
let result = self.rent_without_lock(renter_email, resource_provider_email, node_id, combination_id, quantity, rental_duration_hours);
// Clean up lock file
let _ = std::fs::remove_file(&lock_file_path);
@@ -159,21 +159,21 @@ impl SliceRentalService {
fn rent_without_lock(
&self,
renter_email: &str,
farmer_email: &str,
resource_provider_email: &str,
node_id: &str,
combination_id: &str,
quantity: u32,
rental_duration_hours: u32,
) -> Result<SliceRental, String> {
// Load farmer data
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
.ok_or_else(|| "Farmer not found".to_string())?;
// Load resource_provider data
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
.ok_or_else(|| "ResourceProvider not found".to_string())?;
// Find the node
let node_index = farmer_data.nodes.iter().position(|n| n.id == node_id)
let node_index = resource_provider_data.nodes.iter().position(|n| n.id == node_id)
.ok_or_else(|| "Node not found".to_string())?;
let node = &mut farmer_data.nodes[node_index];
let node = &mut resource_provider_data.nodes[node_index];
// Find the slice combination
let combination = node.available_combinations.iter()
@@ -226,7 +226,7 @@ impl SliceRentalService {
self.slice_calculator.update_availability_after_rental(
node,
total_base_slices_needed,
farmer_email
resource_provider_email
)?;
// Add allocation to node
@@ -237,7 +237,7 @@ impl SliceRentalService {
rental_id: rental_id.clone(),
slice_combination_id: combination_id.to_string(),
node_id: node_id.to_string(),
farmer_email: farmer_email.to_string(),
resource_provider_email: resource_provider_email.to_string(),
slice_allocation: allocation,
total_cost,
payment_status: PaymentStatus::Paid,
@@ -260,12 +260,12 @@ impl SliceRentalService {
renter_data.wallet_balance_usd -= total_cost;
renter_data.slice_rentals.push(slice_rental.clone());
// Add earnings to farmer
farmer_data.wallet_balance_usd += total_cost;
// Add earnings to resource_provider
resource_provider_data.wallet_balance_usd += total_cost;
// Save both user data
UserPersistence::save_user_data(&farmer_data)
.map_err(|e| format!("Failed to save farmer data: {}", e))?;
UserPersistence::save_user_data(&resource_provider_data)
.map_err(|e| format!("Failed to save resource_provider data: {}", e))?;
UserPersistence::save_user_data(&renter_data)
.map_err(|e| format!("Failed to save renter data: {}", e))?;
@@ -273,14 +273,14 @@ impl SliceRentalService {
}
/// Release expired slice rentals
pub fn release_expired_rentals(&self, farmer_email: &str) -> Result<u32, String> {
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
.ok_or_else(|| "Farmer not found".to_string())?;
pub fn release_expired_rentals(&self, resource_provider_email: &str) -> Result<u32, String> {
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
.ok_or_else(|| "ResourceProvider not found".to_string())?;
let mut released_count = 0;
let now = Utc::now();
for node in &mut farmer_data.nodes {
for node in &mut resource_provider_data.nodes {
let mut expired_allocations = Vec::new();
// Find expired allocations
@@ -314,7 +314,7 @@ impl SliceRentalService {
self.slice_calculator.update_availability_after_release(
node,
base_slices_used,
farmer_email
resource_provider_email
)?;
released_count += 1;
@@ -322,20 +322,20 @@ impl SliceRentalService {
}
if released_count > 0 {
UserPersistence::save_user_data(&farmer_data)
.map_err(|e| format!("Failed to save farmer data: {}", e))?;
UserPersistence::save_user_data(&resource_provider_data)
.map_err(|e| format!("Failed to save resource_provider data: {}", e))?;
}
Ok(released_count)
}
/// Get slice rental statistics for a farmer
pub fn get_farmer_slice_statistics(&self, farmer_email: &str) -> SliceRentalStatistics {
if let Some(farmer_data) = UserPersistence::load_user_data(farmer_email) {
/// Get slice rental statistics for a resource_provider
pub fn get_resource_provider_slice_statistics(&self, resource_provider_email: &str) -> SliceRentalStatistics {
if let Some(resource_provider_data) = UserPersistence::load_user_data(resource_provider_email) {
let mut stats = SliceRentalStatistics::default();
for node in &farmer_data.nodes {
for node in &resource_provider_data.nodes {
stats.total_nodes += 1;
stats.total_base_slices += node.total_base_slices as u32;
stats.allocated_base_slices += node.allocated_base_slices as u32;
@@ -379,7 +379,7 @@ impl SliceRentalService {
}
}
/// Statistics for farmer slice rentals
/// Statistics for resource_provider slice rentals
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SliceRentalStatistics {
pub total_nodes: u32,

View File

@@ -46,10 +46,10 @@ pub struct UserPersistentData {
pub deleted: Option<bool>,
pub deleted_at: Option<String>,
pub deletion_reason: Option<String>,
// Farmer-specific data
// ResourceProvider-specific data
pub nodes: Vec<crate::models::user::FarmNode>,
pub farmer_earnings: Vec<crate::models::user::EarningsRecord>,
pub farmer_settings: Option<crate::models::user::FarmerSettings>,
pub resource_provider_earnings: Vec<crate::models::user::EarningsRecord>,
pub resource_provider_settings: Option<crate::models::user::FarmerSettings>,
#[serde(default)]
pub slice_products: Vec<crate::models::product::Product>,
// User activity tracking
@@ -63,10 +63,10 @@ pub struct UserPersistentData {
#[serde(default)]
pub active_product_rentals: Vec<ProductRental>,
#[serde(default)]
pub farmer_rental_earnings: Vec<crate::models::user::FarmerRentalEarning>,
pub resource_provider_rental_earnings: Vec<crate::models::user::FarmerRentalEarning>,
#[serde(default)]
pub node_rentals: Vec<crate::models::user::NodeRental>,
// Node groups for farmer organization
// Node groups for resource_provider organization
#[serde(default)]
pub node_groups: Vec<crate::models::user::NodeGroup>,
// NEW: Slice rental tracking for users
@@ -142,15 +142,15 @@ impl Default for UserPersistentData {
deleted_at: None,
deletion_reason: None,
nodes: Vec::new(),
farmer_earnings: Vec::new(),
farmer_settings: None,
resource_provider_earnings: Vec::new(),
resource_provider_settings: None,
slice_products: Vec::new(),
user_activities: Vec::new(),
user_preferences: None,
usage_statistics: None,
orders: Vec::new(),
active_product_rentals: Vec::new(),
farmer_rental_earnings: Vec::new(),
resource_provider_rental_earnings: Vec::new(),
node_rentals: Vec::new(),
node_groups: Vec::new(),
slice_rentals: Vec::new(),
@@ -1306,19 +1306,19 @@ impl UserPersistence {
}
}
/// Get farmer earnings for a user
pub fn get_farmer_earnings(user_email: &str) -> Vec<crate::models::user::EarningsRecord> {
/// Get resource_provider earnings for a user
pub fn get_resource_provider_earnings(user_email: &str) -> Vec<crate::models::user::EarningsRecord> {
if let Some(data) = Self::load_user_data(user_email) {
data.farmer_earnings
data.resource_provider_earnings
} else {
Vec::default()
}
}
/// Get farmer settings for a user
pub fn get_farmer_settings(user_email: &str) -> Option<crate::models::user::FarmerSettings> {
/// Get resource_provider settings for a user
pub fn get_resource_provider_settings(user_email: &str) -> Option<crate::models::user::FarmerSettings> {
if let Some(data) = Self::load_user_data(user_email) {
data.farmer_settings
data.resource_provider_settings
} else {
None
}

View File

@@ -1,12 +1,12 @@
// Dashboard Farmer JavaScript
// Handles farmer dashboard functionality including automatic slice management, grid integration, and node management
// Dashboard ResourceProvider JavaScript
// Handles resource_provider dashboard functionality including automatic slice management, grid integration, and node management
if (window.farmerDashboardInitialized) {
console.debug('Farmer dashboard already initialized; skipping');
if (window.resourceProviderDashboardInitialized) {
console.debug('ResourceProvider dashboard already initialized; skipping');
} else {
window.farmerDashboardInitialized = true;
window.resourceProviderDashboardInitialized = true;
document.addEventListener('DOMContentLoaded', function() {
console.log('🚜 Farmer Dashboard JavaScript loaded - Automatic Slice System');
console.log('🚜 ResourceProvider Dashboard JavaScript loaded - Automatic Slice System');
// Initialize dashboard
initializeFarmerDashboard();
@@ -762,7 +762,7 @@ function showNodeDetailsModal(node) {
function loadSliceStatistics() {
console.log('📊 Loading slice statistics');
window.apiJson('/api/dashboard/farmer/slice-statistics')
window.apiJson('/api/dashboard/resource_provider/slice-statistics')
.then(data => {
// apiJson returns unwrapped data; support either {statistics: {...}} or {...}
const stats = (data && data.statistics) ? data.statistics : (data || {});
@@ -1173,12 +1173,12 @@ function createSimpleIndividualPricingForms() {
}
/**
* Initialize farmer dashboard functionality
* Initialize resource_provider dashboard functionality
*/
function initializeFarmerDashboard() {
console.log('🚜 Initializing farmer dashboard');
console.log('🚜 Initializing resource_provider dashboard');
// Load farmer data
// Load resource_provider data
loadFarmerData();
// Load slice templates
@@ -2911,12 +2911,12 @@ function resetSliceConfigurationForm() {
}
/**
* Load farmer data from API
* Load resource_provider data from API
*/
async function loadFarmerData() {
try {
const data = await window.apiJson('/api/dashboard/farmer-data');
console.log('🚜 Loaded farmer data:', data);
const data = await window.apiJson('/api/dashboard/resource_provider-data');
console.log('🚜 Loaded resource_provider data:', data);
// Load node groups as well
const groupsResult = await window.apiJson('/api/dashboard/node-groups');
@@ -2924,8 +2924,8 @@ async function loadFarmerData() {
data.nodeGroups = nodeGroups;
console.log('🚜 Node groups loaded:', nodeGroups);
// Store farmer data globally for slice status checking
window.farmerData = data;
// Store resource_provider data globally for slice status checking
window.resourceProviderData = data;
// Update dashboard stats
updateDashboardStats(data);
@@ -2940,8 +2940,8 @@ async function loadFarmerData() {
loadSliceTemplates();
} catch (error) {
console.error('🚜 Error loading farmer data:', error);
showNotification('Failed to load farmer data', 'error');
console.error('🚜 Error loading resource_provider data:', error);
showNotification('Failed to load resource_provider data', 'error');
}
}
@@ -3130,13 +3130,13 @@ function showSliceTemplatesError() {
* Returns 'Active' if at least one node is using this slice format, 'Available' otherwise
*/
function getSliceFormatStatus(sliceFormatId) {
// Check if we have farmer data loaded
if (!window.farmerData || !window.farmerData.nodes) {
// Check if we have resource_provider data loaded
if (!window.resourceProviderData || !window.resourceProviderData.nodes) {
return 'Available'; // Default to Available if no data
}
// Check if any node has this slice format in their slice_formats array
const isUsedByAnyNode = window.farmerData.nodes.some(node => {
const isUsedByAnyNode = window.resourceProviderData.nodes.some(node => {
return node.slice_formats &&
Array.isArray(node.slice_formats) &&
node.slice_formats.includes(sliceFormatId);
@@ -3507,8 +3507,8 @@ function updateNodesTable(nodes) {
// Group info with enhanced display - get actual group name from loaded groups
let groupInfo = '<span class="badge bg-secondary">Single</span>';
if (node.node_group_id && window.farmerData && window.farmerData.nodeGroups) {
const group = window.farmerData.nodeGroups.find(g => g.id === node.node_group_id);
if (node.node_group_id && window.resourceProviderData && window.resourceProviderData.nodeGroups) {
const group = window.resourceProviderData.nodeGroups.find(g => g.id === node.node_group_id);
if (group) {
groupInfo = `<span class="badge bg-info">${group.name}</span>`;
}
@@ -3966,7 +3966,7 @@ async function addGridNodes() {
// Reset form
resetAddNodeForm();
// Reload farmer data and node groups with small delay for backend processing
// Reload resource_provider data and node groups with small delay for backend processing
setTimeout(async () => {
await loadFarmerData();
await loadNodeGroups(); // FARMER FIX: Refresh node groups table after adding new nodes
@@ -4155,7 +4155,7 @@ async function confirmNodeDeletion() {
deleteModal.hide();
}
// Reload farmer data and node groups with small delay for backend processing
// Reload resource_provider data and node groups with small delay for backend processing
setTimeout(() => {
loadFarmerData();
loadNodeGroups(); // FARMER FIX: Refresh node groups table after node deletion
@@ -4925,7 +4925,7 @@ async function saveNodeConfiguration() {
modal.hide();
}
// Reload farmer data and node groups with small delay for backend processing
// Reload resource_provider data and node groups with small delay for backend processing
setTimeout(async () => {
await loadFarmerData();
await loadNodeGroups(); // FARMER FIX: Refresh node groups table after node configuration changes
@@ -5627,7 +5627,7 @@ function createSliceFormatCard(format, type) {
</div>
`;
} else {
// Use persistent data from farmer settings (price_per_hour) instead of hardcoded fallback
// Use persistent data from resource_provider settings (price_per_hour) instead of hardcoded fallback
const hourlyPrice = format.price_per_hour || format.price || 10; // Default to 10 if no price found
pricingDisplay = `<small class="text-muted">${hourlyPrice} ${currency}/hour</small>`;
}
@@ -5706,15 +5706,15 @@ function getSliceFormatDisplayName(formatId, formatName) {
return formatName;
}
// Look up custom slice products from loaded farmer data
if (window.farmerData && window.farmerData.slice_products) {
const sliceProduct = window.farmerData.slice_products.find(product => product.id === formatId);
// Look up custom slice products from loaded resource_provider data
if (window.resourceProviderData && window.resourceProviderData.slice_products) {
const sliceProduct = window.resourceProviderData.slice_products.find(product => product.id === formatId);
if (sliceProduct && sliceProduct.name) {
return sliceProduct.name;
}
}
// Look up from globally loaded slice products if farmer data not available
// Look up from globally loaded slice products if resource_provider data not available
if (window.loadedSliceProducts) {
const sliceProduct = window.loadedSliceProducts.find(product => product.id === formatId);
if (sliceProduct && sliceProduct.name) {
@@ -7189,7 +7189,7 @@ function clearValidationError(input) {
*/
async function updateStakingDisplay() {
try {
const data = await window.apiJson('/api/dashboard/farmer-data');
const data = await window.apiJson('/api/dashboard/resource_provider-data');
const nodes = data.nodes || [];
// Calculate staking statistics
@@ -7523,7 +7523,7 @@ function showStakeNodeModal(nodeId) {
console.log('🛡️ Showing stake modal for node:', nodeId);
// Find the node data
const node = window.farmerData?.nodes?.find(n => n.id === nodeId);
const node = window.resourceProviderData?.nodes?.find(n => n.id === nodeId);
if (!node) {
showNotification('Node not found', 'error');
return;
@@ -7657,7 +7657,7 @@ async function stakeOnNode(nodeId, modal) {
showNotification(`Successfully staked ${stakeAmount} TFP on node`, 'success');
modal.hide();
// Refresh farmer data to show updated staking
// Refresh resource_provider data to show updated staking
await loadFarmerData();
// Update wallet balance display
@@ -7683,7 +7683,7 @@ async function unstakeFromNode(nodeId) {
console.log('🛡️ Unstaking TFP from node:', nodeId);
// Find the node data
const node = window.farmerData?.nodes?.find(n => n.id === nodeId);
const node = window.resourceProviderData?.nodes?.find(n => n.id === nodeId);
if (!node || !node.staking_options || !node.staking_options.staking_enabled) {
showNotification('Node is not currently staked', 'error');
return;
@@ -7712,7 +7712,7 @@ async function unstakeFromNode(nodeId) {
const returnedAmount = result?.returned_amount || stakedAmount;
showNotification(`Successfully unstaked ${returnedAmount} TFP from node`, 'success');
// Refresh farmer data to show updated staking
// Refresh resource_provider data to show updated staking
await loadFarmerData();
// Update wallet balance display
@@ -7731,7 +7731,7 @@ function showUpdateStakeModal(nodeId) {
console.log('🛡️ Showing update stake modal for node:', nodeId);
// Find the node data
const node = window.farmerData?.nodes?.find(n => n.id === nodeId);
const node = window.resourceProviderData?.nodes?.find(n => n.id === nodeId);
if (!node || !node.staking_options || !node.staking_options.staking_enabled) {
showNotification('Node is not currently staked', 'error');
return;
@@ -7847,7 +7847,7 @@ async function updateNodeStaking(nodeId, modal) {
showNotification(`Successfully updated staking to ${newStakeAmount} TFP`, 'success');
modal.hide();
// Refresh farmer data to show updated staking
// Refresh resource_provider data to show updated staking
await loadFarmerData();
// Update wallet balance display

View File

@@ -31,7 +31,7 @@ class DemoWorkflow {
action: () => this.demoAppDeployment()
},
{
title: "Farmer: Node Management",
title: "ResourceProvider: Node Management",
description: "Manage your farming nodes and monitor capacity.",
action: () => this.demoNodeManagement()
},
@@ -265,7 +265,7 @@ class DemoWorkflow {
}
demoNodeManagement() {
showNotification('Demo: Simulating farmer node management...', 'info');
showNotification('Demo: Simulating resource_provider node management...', 'info');
setTimeout(() => {
// Simulate node status change

View File

@@ -431,7 +431,7 @@ class MarketplaceIntegration {
if (!sessionStorage.getItem('marketplaceSlices')) {
// Get real users from user database
const alexUser = userDB.getUser('user-001'); // Alex Thompson - Farmer
const alexUser = userDB.getUser('user-001'); // Alex Thompson - ResourceProvider
const mockSlices = [
{

View File

@@ -12,11 +12,11 @@ class UserDatabase {
const mockUsers = [
{
id: 'user-001',
username: 'sara_farmer',
username: 'sara_resource_provider',
display_name: 'Sara Nicks',
email: 'user1@example.com',
password: 'password',
role: 'farmer',
role: 'resource_provider',
location: 'Amsterdam, Netherlands',
joined_date: '2024-01-15',
reputation: 4.8,
@@ -84,7 +84,7 @@ class UserDatabase {
display_name: 'Jordan Mitchell',
email: 'user5@example.com',
password: 'password',
role: 'multi', // Can be farmer, app_provider, service_provider, user
role: 'multi', // Can be resource_provider, app_provider, service_provider, user
location: 'Toronto, Canada',
joined_date: new Date().toISOString().split('T')[0],
reputation: 5.0,

View File

@@ -14,7 +14,7 @@ impl DataValidator {
if let Value::Object(ref mut obj) = value {
Self::repair_user_activities(obj)?;
Self::repair_farmer_settings(obj)?;
Self::repair_resource_provider_settings(obj)?;
Self::ensure_required_fields(obj)?;
}
@@ -47,20 +47,20 @@ impl DataValidator {
Ok(())
}
/// Repairs farmer settings to include all required fields
fn repair_farmer_settings(obj: &mut Map<String, Value>) -> Result<(), String> {
if let Some(Value::Object(ref mut farmer_settings)) = obj.get_mut("farmer_settings") {
/// Repairs resource_provider settings to include all required fields
fn repair_resource_provider_settings(obj: &mut Map<String, Value>) -> Result<(), String> {
if let Some(Value::Object(ref mut resource_provider_settings)) = obj.get_mut("resource_provider_settings") {
// Ensure minimum_deployment_duration exists
if !farmer_settings.contains_key("minimum_deployment_duration") {
farmer_settings.insert(
if !resource_provider_settings.contains_key("minimum_deployment_duration") {
resource_provider_settings.insert(
"minimum_deployment_duration".to_string(),
Value::Number(serde_json::Number::from(24))
);
}
// Ensure preferred_regions exists
if !farmer_settings.contains_key("preferred_regions") {
farmer_settings.insert(
if !resource_provider_settings.contains_key("preferred_regions") {
resource_provider_settings.insert(
"preferred_regions".to_string(),
Value::Array(vec![
Value::String("NA".to_string()),
@@ -83,7 +83,7 @@ impl DataValidator {
("apps", Value::Array(vec![])),
("app_deployments", Value::Array(vec![])),
("nodes", Value::Array(vec![])),
("farmer_earnings", Value::Array(vec![])),
("resource_provider_earnings", Value::Array(vec![])),
("user_activities", Value::Array(vec![])),
("pool_positions", Value::Object(Map::new())),
];

View File

@@ -78,7 +78,7 @@
</a>
</div>
<div class="col-md-3">
<a href="/dashboard/farmer" class="btn btn-outline-info w-100 mb-2">
<a href="/dashboard/resource_provider" class="btn btn-outline-info w-100 mb-2">
<i class="bi bi-hdd-rack me-2"></i> Add a Mycelium Node
</a>
</div>
@@ -117,11 +117,11 @@
</div>
<div class="col-md-6 col-lg-3 mb-4">
<div class="dashboard-card">
<span class="badge bg-success badge-role">FARMER</span>
<h4>Farmer Dashboard</h4>
<span class="badge bg-success badge-role">RESOURCE PROVIDER</span>
<h4>Resource Provider Dashboard</h4>
<p>Manage your nodes, create slices, set pricing, and track earnings.</p>
<div class="d-grid">
<a href="/dashboard/farmer" class="btn btn-sm btn-outline-success">Access Farmer Dashboard</a>
<a href="/dashboard/resource_provider" class="btn btn-sm btn-outline-success">Access Resource Provider Dashboard</a>
</div>
</div>
</div>

View File

@@ -28,9 +28,9 @@
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if active_section == 'farmer' %}active{% endif %}" href="/dashboard/farmer">
<a class="nav-link {% if active_section == 'resource_provider' %}active{% endif %}" href="/dashboard/resource_provider">
<i class="bi bi-hdd-rack me-1"></i>
Farmer
Resource Provider
</a>
</li>
<li class="nav-item">

View File

@@ -1,10 +1,10 @@
{% extends "dashboard/layout.html" %}
{% block title %}ThreeFold Dashboard - Farmer{% endblock %}
{% block title %}ThreeFold Dashboard - Resource Provider{% endblock %}
{% block dashboard_content %}
<div class="my-4">
<h1>Farmer Dashboard</h1>
<h1>Resource Provider Dashboard</h1>
<p class="lead">Manage your nodes, configure slices, and monitor earnings</p>
<!-- Status Summary -->
@@ -13,8 +13,8 @@
<div class="stats-card success">
<h5 class="card-title">Active Nodes</h5>
<div class="d-flex justify-content-between align-items-end">
<h2 class="mb-0" id="active-nodes-count">{{ farmer_stats.online_nodes }}</h2>
<small class="text-muted">of {{ farmer_stats.total_nodes }} total</small>
<h2 class="mb-0" id="active-nodes-count">{{ resource provider_stats.online_nodes }}</h2>
<small class="text-muted">of {{ resource provider_stats.total_nodes }} total</small>
</div>
</div>
</div>
@@ -22,8 +22,8 @@
<div class="stats-card primary">
<h5 class="card-title">Allocated Slices</h5>
<div class="d-flex justify-content-between align-items-end">
<h2 class="mb-0" id="active-slices-count">{{ farmer_stats.allocated_base_slices }}</h2>
<small class="text-muted">of {{ farmer_stats.total_base_slices }} total</small>
<h2 class="mb-0" id="active-slices-count">{{ resource provider_stats.allocated_base_slices }}</h2>
<small class="text-muted">of {{ resource provider_stats.total_base_slices }} total</small>
</div>
</div>
</div>
@@ -31,7 +31,7 @@
<div class="stats-card warning">
<h5 class="card-title">Monthly Earnings</h5>
<div class="d-flex justify-content-between align-items-end">
<h2 class="mb-0" id="monthly-earnings">{{ farmer_stats.monthly_earnings }}</h2>
<h2 class="mb-0" id="monthly-earnings">{{ resource provider_stats.monthly_earnings }}</h2>
<small class="text-muted">$/month</small>
</div>
</div>
@@ -187,7 +187,7 @@
<div class="stats-card primary">
<h6 class="card-title">Total Base Slices</h6>
<div class="d-flex justify-content-between align-items-end">
<h3 class="mb-0" id="total-base-slices">{{ farmer_stats.total_base_slices }}</h3>
<h3 class="mb-0" id="total-base-slices">{{ resource provider_stats.total_base_slices }}</h3>
<small class="text-muted">Available</small>
</div>
</div>
@@ -196,7 +196,7 @@
<div class="stats-card success">
<h6 class="card-title">Allocated Slices</h6>
<div class="d-flex justify-content-between align-items-end">
<h3 class="mb-0" id="allocated-base-slices">{{ farmer_stats.allocated_base_slices }}</h3>
<h3 class="mb-0" id="allocated-base-slices">{{ resource provider_stats.allocated_base_slices }}</h3>
<small class="text-muted">Rented</small>
</div>
</div>
@@ -205,7 +205,7 @@
<div class="stats-card info">
<h6 class="card-title">Available Slices</h6>
<div class="d-flex justify-content-between align-items-end">
<h3 class="mb-0" id="available-base-slices">{{ farmer_stats.available_base_slices }}</h3>
<h3 class="mb-0" id="available-base-slices">{{ resource provider_stats.available_base_slices }}</h3>
<small class="text-muted">For Rent</small>
</div>
</div>
@@ -214,7 +214,7 @@
<div class="stats-card warning">
<h6 class="card-title">Utilization</h6>
<div class="d-flex justify-content-between align-items-end">
<h3 class="mb-0" id="slice-utilization">{{ farmer_stats.slice_utilization_percentage }}%</h3>
<h3 class="mb-0" id="slice-utilization">{{ resource provider_stats.slice_utilization_percentage }}%</h3>
<small class="text-muted">Capacity</small>
</div>
</div>
@@ -238,8 +238,8 @@
</tr>
</thead>
<tbody id="node-slices-table">
{% if farmer_nodes %}
{% for node in farmer_nodes %}
{% if resource provider_nodes %}
{% for node in resource provider_nodes %}
<tr>
<td>
<div class="d-flex align-items-center">
@@ -396,8 +396,8 @@
{{ super() }}
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
<!-- Load farmer dashboard JavaScript -->
<script src="/static/js/dashboard-farmer.js"></script>
<!-- Load resource provider dashboard JavaScript -->
<script src="/static/js/dashboard-resource_provider.js"></script>
<style>
/* Ensure charts have consistent sizes */

View File

@@ -55,7 +55,7 @@
<div class="display-4 mb-3 text-success">
<i class="bi bi-hdd-rack"></i>
</div>
<h5>As a Farmer</h5>
<h5>As a Resource Provider</h5>
<p>Manage nodes, configure slices, set pricing</p>
</div>
</div>

View File

@@ -341,7 +341,7 @@
<div class="card h-100">
<div class="card-body">
<h5 class="card-title"><i class="bi bi-people me-2 text-success"></i>Community Building</h5>
<p class="card-text">Connects hardware providers with potential farmers</p>
<p class="card-text">Connects hardware providers with potential resource providers</p>
</div>
</div>
</div>

View File

@@ -78,7 +78,7 @@
<div class="col-md-6">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title"><i class="bi bi-hdd-rack me-2"></i>Farmers</h5>
<h5 class="card-title"><i class="bi bi-hdd-rack me-2"></i>Resource Providers</h5>
<p class="card-text">Contribute compute capacity to the ThreeFold Grid and earn through the platform's ecosystem.</p>
<a href="/docs" class="btn btn-outline-primary">Learn More</a>
</div>

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Farmers Terms and Conditions - Project Mycelium{% endblock %}
{% block title %}Resource Providers Terms and Conditions - Project Mycelium{% endblock %}
{% block content %}
<div class="container my-5">
@@ -9,25 +9,25 @@
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/terms">Terms and Conditions</a></li>
<li class="breadcrumb-item active" aria-current="page">Farmers</li>
<li class="breadcrumb-item active" aria-current="page">Resource Providers</li>
</ol>
</nav>
<div class="d-flex align-items-center mb-4">
<i class="bi bi-hdd-rack fs-1 me-3 text-primary"></i>
<h1>Farmers Terms and Conditions</h1>
<h1>Resource Providers Terms and Conditions</h1>
</div>
<p class="lead mb-4">Last updated: May 22, 2025</p>
<div class="alert alert-info">
<p class="mb-0">These terms specifically apply to Farmers (Resource Providers) on the Project Mycelium who contribute capacity to the Mycelium Grid.</p>
<p class="mb-0">These terms specifically apply to Resource Providers (Resource Providers) on the Project Mycelium who contribute capacity to the Mycelium Grid.</p>
</div>
<h2>1. Definition of a Farmer</h2>
<p>A "Farmer" refers to any individual or entity that connects hardware resources to the Mycelium Grid, including but not limited to compute nodes (Mycelium Nodes), storage capacity, network infrastructure, or other compatible devices that contribute to the Mycelium Grid's capacity.</p>
<h2>1. Definition of a Resource Provider</h2>
<p>A "Resource Provider" refers to any individual or entity that connects hardware resources to the Mycelium Grid, including but not limited to compute nodes (Mycelium Nodes), storage capacity, network infrastructure, or other compatible devices that contribute to the Mycelium Grid's capacity.</p>
<h2>2. Farmer Responsibilities</h2>
<p>As a Farmer on the Project Mycelium, you agree to:</p>
<h2>2. Resource Provider Responsibilities</h2>
<p>As a Resource Provider on the Project Mycelium, you agree to:</p>
<ul>
<li>Maintain your connected hardware in good working condition with adequate internet connectivity</li>
<li>Ensure your hardware meets the minimum technical requirements specified in the Farming documentation</li>
@@ -37,7 +37,7 @@
</ul>
<h2>3. Reputation System and Staking</h2>
<p>The Project Mycelium employs a reputation system that affects farmer visibility and rewards:</p>
<p>The Project Mycelium employs a reputation system that affects resource provider visibility and rewards:</p>
<ul>
<li>Your reputation score is calculated based on multiple factors including uptime, staked Credits, and performance metrics</li>
<li>Staking Credits increases your reputation score and may qualify you for additional benefits</li>
@@ -48,10 +48,10 @@
<h2>4. Rewards and Credits</h2>
<p>Compensation for resource contribution is governed by the following principles:</p>
<ul>
<li>Farmers receive USD Credits based on the resources utilized from their contributed capacity</li>
<li>Resource Providers receive USD Credits based on the resources utilized from their contributed capacity</li>
<li>Credits have a fixed value of 1.0 USD per Credit</li>
<li>Earned Credits can be exchanged for fiat currencies or other supported tokens through the available liquidity pools</li>
<li>Payment schedules and minimum thresholds are detailed in the Farmer dashboard</li>
<li>Payment schedules and minimum thresholds are detailed in the Resource Provider dashboard</li>
</ul>
<h2>5. Hardware and Capacity</h2>
@@ -72,8 +72,8 @@
<li>Slashing penalties may include reputation reduction, temporary suspension, or in severe cases, permanent removal from the marketplace</li>
</ul>
<h2>7. Termination of Farmer Status</h2>
<p>You may cease being a Farmer by:</p>
<h2>7. Termination of Resource Provider Status</h2>
<p>You may cease being a Resource Provider by:</p>
<ul>
<li>Disconnecting your hardware from the Mycelium Grid</li>
<li>Providing notice through your dashboard at least 30 days prior to complete disconnection</li>
@@ -81,7 +81,7 @@
</ul>
<h2>8. Liability Limitation</h2>
<p>As a Farmer, you acknowledge that:</p>
<p>As a Resource Provider, you acknowledge that:</p>
<ul>
<li>ThreeFold is not responsible for any damage to your hardware resulting from normal operation</li>
<li>ThreeFold does not guarantee minimum income or utilization rates for your contributed capacity</li>
@@ -90,7 +90,7 @@
<div class="alert alert-warning mt-5">
<h5 class="alert-heading">Important Note</h5>
<p class="mb-0">These Farmer-specific terms are in addition to the <a href="/terms">General Terms and Conditions</a> that apply to all users of the Project Mycelium. Please ensure you have reviewed both documents.</p>
<p class="mb-0">These Resource Provider-specific terms are in addition to the <a href="/terms">General Terms and Conditions</a> that apply to all users of the Project Mycelium. Please ensure you have reviewed both documents.</p>
</div>
<div class="text-center mt-5 mb-3">

View File

@@ -18,9 +18,9 @@
<div class="card h-100 shadow-sm">
<div class="card-body text-center">
<i class="bi bi-hdd-rack fs-1 mb-3 text-primary"></i>
<h5 class="card-title">Farmers</h5>
<h5 class="card-title">Resource Providers</h5>
<p class="card-text">Resource Providers contributing capacity to the ThreeFold Grid</p>
<a href="/terms/farmers" class="btn btn-outline-primary mt-3">View Terms</a>
<a href="/terms/resource providers" class="btn btn-outline-primary mt-3">View Terms</a>
</div>
</div>
</div>

View File

@@ -129,8 +129,8 @@
</td>
<td>
<div class="provider-name">
{% if product_data.product.attributes.farmer_email %}
{{ product_data.product.attributes.farmer_email.value | truncate(length=15) }}
{% if product_data.product.attributes.resource provider_email %}
{{ product_data.product.attributes.resource provider_email.value | truncate(length=15) }}
{% else %}
{% if product_data.product.provider %}{{ product_data.product.provider }}{% else %}Unknown{% endif %}
{% endif %}

View File

@@ -17,7 +17,7 @@
<h5 class="alert-heading">What are Mycelium Nodes?</h5>
<p>Mycelium Nodes are the physical hardware units that make up the Mycelium Grid. These certified servers provide compute, storage, and network capacity to the decentralized internet infrastructure.</p>
<hr>
<p class="mb-0">By purchasing a Mycelium Node, you become a farmer in the Mycelium ecosystem, earning MC rewards while contributing to the decentralized internet.</p>
<p class="mb-0">By purchasing a Mycelium Node, you become a resource provider in the Mycelium ecosystem, earning MC rewards while contributing to the decentralized internet.</p>
</div>
</div>
</div>
@@ -302,7 +302,7 @@
<div class="col-12">
<div class="card">
<div class="card-body">
<h3 class="card-title">Become a Mycelium Farmer</h3>
<h3 class="card-title">Become a Mycelium Resource Provider</h3>
<div class="row">
<div class="col-md-6">
<h5>1. Purchase Your Mycelium Node</h5>
@@ -322,7 +322,7 @@
<div class="alert alert-info mt-3">
<i class="bi bi-info-circle me-2"></i>
<strong>ROI Potential:</strong> Mycelium Node farmers typically see return on investment within 2-4 years, depending on grid utilization and MC price.
<strong>ROI Potential:</strong> Mycelium Node resource providers typically see return on investment within 2-4 years, depending on grid utilization and MC price.
</div>
</div>
</div>

View File

@@ -24,7 +24,7 @@
<strong>Node:</strong> {{ slice.node_id }}
</div>
<div class="mb-3">
<strong>Farmer:</strong> {{ slice.farmer_email }}
<strong>Resource Provider:</strong> {{ slice.resource provider_email }}
</div>
<div class="mb-3">
<strong>Specifications:</strong>
@@ -54,7 +54,7 @@
<div class="card-body">
<form id="sliceRentalForm" method="POST" action="/marketplace/slice/rent">
<!-- Hidden fields -->
<input type="hidden" name="farmer_email" value="{{ farmer_email }}">
<input type="hidden" name="resource provider_email" value="{{ resource provider_email }}">
<input type="hidden" name="node_id" value="{{ node_id }}">
<input type="hidden" name="combination_id" value="{{ combination_id }}">