feat: rename farmer to resource provider across codebase and update terminology
This commit is contained in:
@@ -392,11 +392,11 @@ impl DashboardController {
|
|||||||
render_template(&tmpl, "dashboard/user.html", &ctx)
|
render_template(&tmpl, "dashboard/user.html", &ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the farmer section of the dashboard
|
/// Renders the resource provider section of the dashboard
|
||||||
pub async fn farmer_section(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
pub async fn resource_provider_section(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||||
let mut ctx = crate::models::builders::ContextBuilder::new()
|
let mut ctx = crate::models::builders::ContextBuilder::new()
|
||||||
.active_page("dashboard")
|
.active_page("dashboard")
|
||||||
.active_section("farmer")
|
.active_section("resource_provider")
|
||||||
.gitea_enabled(get_app_config().is_gitea_enabled())
|
.gitea_enabled(get_app_config().is_gitea_enabled())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -406,17 +406,17 @@ impl DashboardController {
|
|||||||
return render_template(&tmpl, "dashboard/welcome.html", &ctx);
|
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") {
|
if let Ok(Some(user_email)) = session.get::<String>("user_email") {
|
||||||
ctx.insert("user_email", &user_email);
|
ctx.insert("user_email", &user_email);
|
||||||
// Initialize farmer service with slice calculator
|
// Initialize resource provider service with slice calculator
|
||||||
if let Ok(farmer_service) = crate::services::farmer::FarmerService::builder().build() {
|
if let Ok(resource_provider_service) = crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||||
// Repair node-group data consistency when farmer dashboard loads
|
// Repair node-group data consistency when resource provider dashboard loads
|
||||||
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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repair missing marketplace SLA data for existing nodes
|
// 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,
|
&user_email,
|
||||||
99.8, // default uptime
|
99.8, // default uptime
|
||||||
100, // default bandwidth
|
100, // default bandwidth
|
||||||
@@ -424,18 +424,18 @@ impl DashboardController {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get farmer nodes with updated slice calculations
|
// Get resource provider nodes with updated slice calculations
|
||||||
let farmer_nodes = farmer_service.get_farmer_nodes(&user_email);
|
let resource_provider_nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
|
||||||
|
|
||||||
// Calculate farmer statistics from nodes
|
// Calculate resource_provider statistics from nodes
|
||||||
let total_nodes = farmer_nodes.len() as u32;
|
let total_nodes = resource_provider_nodes.len() as u32;
|
||||||
let mut online_nodes = 0u32;
|
let mut online_nodes = 0u32;
|
||||||
let mut total_base_slices = 0u32;
|
let mut total_base_slices = 0u32;
|
||||||
let mut allocated_base_slices = 0u32;
|
let mut allocated_base_slices = 0u32;
|
||||||
let mut total_monthly_earnings = rust_decimal::Decimal::ZERO;
|
let mut total_monthly_earnings = rust_decimal::Decimal::ZERO;
|
||||||
let mut average_uptime = 0.0f32;
|
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) {
|
if matches!(node.status, crate::models::user::NodeStatus::Online) {
|
||||||
online_nodes += 1;
|
online_nodes += 1;
|
||||||
}
|
}
|
||||||
@@ -449,8 +449,8 @@ impl DashboardController {
|
|||||||
average_uptime /= total_nodes as f32;
|
average_uptime /= total_nodes as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create farmer statistics for the dashboard
|
// Create resource_provider statistics for the dashboard
|
||||||
let farmer_stats = serde_json::json!({
|
let resource_provider_stats = serde_json::json!({
|
||||||
"total_nodes": total_nodes,
|
"total_nodes": total_nodes,
|
||||||
"online_nodes": online_nodes,
|
"online_nodes": online_nodes,
|
||||||
"total_base_slices": total_base_slices,
|
"total_base_slices": total_base_slices,
|
||||||
@@ -465,8 +465,8 @@ impl DashboardController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.insert("farmer_stats", &farmer_stats);
|
ctx.insert("resource_provider_stats", &resource_provider_stats);
|
||||||
ctx.insert("farmer_nodes", &farmer_nodes);
|
ctx.insert("resource_provider_nodes", &resource_provider_nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load user data from session (without mock data override)
|
// 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("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);
|
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() {
|
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);
|
let resource_provider_slice_stats = slice_rental_service.get_resource_provider_slice_statistics(&user_email);
|
||||||
ctx.insert("slice_rental_statistics", &farmer_slice_stats);
|
ctx.insert("slice_rental_statistics", &resource_provider_slice_stats);
|
||||||
|
|
||||||
// Release any expired rentals
|
// Release any expired rentals
|
||||||
if let Err(_e) = slice_rental_service.release_expired_rentals(&user_email) {
|
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
|
/// Renders the app provider section of the dashboard
|
||||||
@@ -837,13 +837,13 @@ impl DashboardController {
|
|||||||
render_template(&tmpl, "dashboard/pools.html", &ctx)
|
render_template(&tmpl, "dashboard/pools.html", &ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// API endpoint to return farmer dashboard data as JSON
|
/// API endpoint to return resource_provider dashboard data as JSON
|
||||||
pub async fn farmer_data_api(session: Session) -> Result<impl Responder> {
|
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();
|
let user_email = session.get::<String>("user_email").unwrap_or_default().unwrap_or_default();
|
||||||
|
|
||||||
// FARMER FIX: Use farmer service to ensure data consistency
|
// RESOURCE_PROVIDER FIX: Use resource_provider service to ensure data consistency
|
||||||
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,
|
Ok(service) => service,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -853,16 +853,16 @@ impl DashboardController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Repair data consistency before loading
|
// 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
|
// Load real resource_provider data from persistence using resource_provider service
|
||||||
let nodes = farmer_service.get_farmer_nodes(&user_email);
|
let nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
|
||||||
let earnings = farmer_service.get_farmer_earnings(&user_email);
|
let earnings = resource_provider_service.get_resource_provider_earnings(&user_email);
|
||||||
let stats = farmer_service.get_farmer_statistics(&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
|
// Always use persistent data - no fallback to mock data for resource_provider dashboard
|
||||||
// If no data exists, return empty but valid farmer data structure
|
// If no data exists, return empty but valid resource_provider data structure
|
||||||
if nodes.is_empty() {
|
if nodes.is_empty() {
|
||||||
return Ok(ResponseBuilder::ok()
|
return Ok(ResponseBuilder::ok()
|
||||||
.json(serde_json::json!({
|
.json(serde_json::json!({
|
||||||
@@ -885,12 +885,12 @@ impl DashboardController {
|
|||||||
.build());
|
.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 slice_products = crate::services::user_persistence::UserPersistence::get_slice_products(&user_email);
|
||||||
let active_slices = slice_products.len() as i32;
|
let active_slices = slice_products.len() as i32;
|
||||||
|
|
||||||
// Build comprehensive farmer data using statistics from farmer service
|
// Build comprehensive resource_provider data using statistics from resource_provider service
|
||||||
let farmer_data = serde_json::json!({
|
let resource_provider_data = serde_json::json!({
|
||||||
"total_nodes": stats.total_nodes,
|
"total_nodes": stats.total_nodes,
|
||||||
"online_nodes": stats.online_nodes,
|
"online_nodes": stats.online_nodes,
|
||||||
"total_capacity": stats.total_capacity,
|
"total_capacity": stats.total_capacity,
|
||||||
@@ -904,13 +904,13 @@ impl DashboardController {
|
|||||||
"slice_products": slice_products
|
"slice_products": slice_products
|
||||||
});
|
});
|
||||||
Ok(ResponseBuilder::ok()
|
Ok(ResponseBuilder::ok()
|
||||||
.json(farmer_data)
|
.json(resource_provider_data)
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enhanced farmer dashboard with node management
|
/// Enhanced resource_provider dashboard with node management
|
||||||
pub async fn farmer_dashboard_enhanced(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
pub async fn resource_provider_dashboard_enhanced(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||||
let farmer_service = crate::services::farmer::FarmerService::builder()
|
let resource_provider_service = crate::services::resource_provider::ResourceProviderService::builder()
|
||||||
.auto_sync_enabled(true)
|
.auto_sync_enabled(true)
|
||||||
.metrics_collection(true)
|
.metrics_collection(true)
|
||||||
.build()
|
.build()
|
||||||
@@ -922,14 +922,14 @@ impl DashboardController {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
// Load farmer data using the service
|
// Load resource_provider data using the service
|
||||||
let nodes = farmer_service.get_farmer_nodes(&user_email);
|
let nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
|
||||||
let earnings = farmer_service.get_farmer_earnings(&user_email);
|
let earnings = resource_provider_service.get_resource_provider_earnings(&user_email);
|
||||||
let stats = farmer_service.get_farmer_statistics(&user_email);
|
let stats = resource_provider_service.get_resource_provider_statistics(&user_email);
|
||||||
|
|
||||||
let mut ctx = crate::models::builders::ContextBuilder::new()
|
let mut ctx = crate::models::builders::ContextBuilder::new()
|
||||||
.active_page("dashboard")
|
.active_page("dashboard")
|
||||||
.active_section("farmer")
|
.active_section("resource_provider")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ctx.insert("nodes", &nodes);
|
ctx.insert("nodes", &nodes);
|
||||||
@@ -944,10 +944,10 @@ impl DashboardController {
|
|||||||
ctx.insert("user", &user);
|
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> {
|
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")
|
let user_email = session.get::<String>("user_email")
|
||||||
@@ -960,8 +960,8 @@ impl DashboardController {
|
|||||||
})).build());
|
})).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize farmer service
|
// Initialize resource_provider service
|
||||||
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,
|
Ok(service) => service,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -1064,7 +1064,7 @@ impl DashboardController {
|
|||||||
.bandwidth_mbps(node_data_json.get("bandwidth_mbps")
|
.bandwidth_mbps(node_data_json.get("bandwidth_mbps")
|
||||||
.and_then(|v| v.as_i64())
|
.and_then(|v| v.as_i64())
|
||||||
.unwrap_or(100) as i32)
|
.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
|
// Add optional fields
|
||||||
if let Some(region) = node_data_json.get("region").and_then(|v| v.as_str()) {
|
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))
|
actix_web::error::ErrorBadRequest(format!("Invalid node data: {}", e))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Add node using farmer service
|
// Add node using resource_provider service
|
||||||
match farmer_service.add_node(&user_email, node_data) {
|
match resource_provider_service.add_node(&user_email, node_data) {
|
||||||
Ok(node) => {
|
Ok(node) => {
|
||||||
|
|
||||||
// Add activity record
|
// Add activity record
|
||||||
@@ -1143,7 +1143,7 @@ impl DashboardController {
|
|||||||
_ => crate::models::user::NodeStatus::Offline,
|
_ => 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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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(()) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -1182,7 +1182,7 @@ impl DashboardController {
|
|||||||
|
|
||||||
let node_id = path.into_inner();
|
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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) => {
|
Some(mut node) => {
|
||||||
|
|
||||||
// MARKETPLACE SLA FIX: Override grid data with marketplace SLA values when available
|
// MARKETPLACE SLA FIX: Override grid data with marketplace SLA values when available
|
||||||
@@ -1235,7 +1235,7 @@ impl DashboardController {
|
|||||||
})).build());
|
})).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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -1262,7 +1262,7 @@ impl DashboardController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// API endpoint to update node configuration
|
/// 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")
|
let user_email = session.get::<String>("user_email")
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
@@ -1275,7 +1275,7 @@ impl DashboardController {
|
|||||||
|
|
||||||
let node_id = path.into_inner();
|
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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(()) => {
|
Ok(()) => {
|
||||||
|
|
||||||
// Add activity record
|
// Add activity record
|
||||||
@@ -1324,7 +1324,7 @@ impl DashboardController {
|
|||||||
})).build());
|
})).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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -1338,7 +1338,7 @@ impl DashboardController {
|
|||||||
let mut customized_formats = Vec::new();
|
let mut customized_formats = Vec::new();
|
||||||
|
|
||||||
for format_id in default_format_ids {
|
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);
|
customized_formats.push(format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1358,7 +1358,7 @@ impl DashboardController {
|
|||||||
})).build());
|
})).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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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())
|
Ok(ResponseBuilder::ok().json(groups).build())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1383,7 +1383,7 @@ impl DashboardController {
|
|||||||
})).build());
|
})).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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -1402,7 +1402,7 @@ impl DashboardController {
|
|||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.map(|s| s.to_string());
|
.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(group) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -1431,7 +1431,7 @@ impl DashboardController {
|
|||||||
})).build());
|
})).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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -1449,10 +1449,10 @@ impl DashboardController {
|
|||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.map(|s| s.to_string());
|
.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) => {
|
Ok(group_name) => {
|
||||||
// FARMER FIX: Repair consistency after group assignment change
|
// RESOURCE_PROVIDER FIX: Repair consistency after group assignment change
|
||||||
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) {
|
||||||
}
|
}
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -1482,7 +1482,7 @@ impl DashboardController {
|
|||||||
})).build());
|
})).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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -1493,7 +1493,7 @@ impl DashboardController {
|
|||||||
|
|
||||||
let group_id = path.into_inner();
|
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(()) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -1523,7 +1523,7 @@ impl DashboardController {
|
|||||||
|
|
||||||
let format_id = path.into_inner();
|
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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) => {
|
Some(format) => {
|
||||||
Ok(ResponseBuilder::ok().json(format).build())
|
Ok(ResponseBuilder::ok().json(format).build())
|
||||||
}
|
}
|
||||||
@@ -1558,7 +1558,7 @@ impl DashboardController {
|
|||||||
|
|
||||||
let format_id = path.into_inner();
|
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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 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 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(),
|
id: format_id.clone(),
|
||||||
name,
|
name,
|
||||||
cpu_cores,
|
cpu_cores,
|
||||||
@@ -1587,7 +1587,7 @@ impl DashboardController {
|
|||||||
price_per_hour,
|
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(_) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": true,
|
"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)))
|
.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
|
.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 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
|
// Create slice configuration with pricing
|
||||||
let slice_pricing = crate::models::product::SlicePricing::from_hourly(
|
let slice_pricing = crate::models::product::SlicePricing::from_hourly(
|
||||||
@@ -1657,7 +1657,7 @@ impl DashboardController {
|
|||||||
// Create slice product
|
// Create slice product
|
||||||
let slice_product = crate::models::product::Product::create_slice_product(
|
let slice_product = crate::models::product::Product::create_slice_product(
|
||||||
user_email.clone(),
|
user_email.clone(),
|
||||||
farmer_name,
|
resource_provider_name,
|
||||||
name,
|
name,
|
||||||
slice_config,
|
slice_config,
|
||||||
price_per_hour,
|
price_per_hour,
|
||||||
@@ -2225,18 +2225,18 @@ impl DashboardController {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize farmer service to check for existing nodes
|
// Initialize resource_provider service to check for existing nodes
|
||||||
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
"error": "Failed to initialize farmer service"
|
"error": "Failed to initialize resource_provider service"
|
||||||
})).build());
|
})).build());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get existing nodes to check for duplicates
|
// 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
|
// Validate each node and fetch data
|
||||||
let mut validated_nodes = Vec::new();
|
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_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 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
|
// Initialize resource_provider service
|
||||||
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
"error": "Failed to initialize farmer service"
|
"error": "Failed to initialize resource_provider service"
|
||||||
})).build());
|
})).build());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2515,7 +2515,7 @@ impl DashboardController {
|
|||||||
// Add nodes with comprehensive configuration
|
// Add nodes with comprehensive configuration
|
||||||
log::info!(
|
log::info!(
|
||||||
target: "api.dashboard",
|
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,
|
req_id,
|
||||||
user_email,
|
user_email,
|
||||||
node_ids.len(),
|
node_ids.len(),
|
||||||
@@ -2556,19 +2556,19 @@ impl DashboardController {
|
|||||||
// For multi-node scenarios, apply pricing configuration based on user choice
|
// 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() {
|
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() {
|
} 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
|
// Choose the appropriate method based on pricing mode
|
||||||
if pricing_mode == "individual" && individual_node_pricing.is_some() {
|
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,
|
&user_email,
|
||||||
node_ids.clone(),
|
node_ids.clone(),
|
||||||
slice_formats,
|
slice_formats,
|
||||||
individual_node_pricing.unwrap()
|
individual_node_pricing.unwrap()
|
||||||
).await
|
).await
|
||||||
} else {
|
} else {
|
||||||
farmer_service.add_multiple_grid_nodes_with_comprehensive_config(
|
resource_provider_service.add_multiple_grid_nodes_with_comprehensive_config(
|
||||||
&user_email,
|
&user_email,
|
||||||
node_ids.clone(),
|
node_ids.clone(),
|
||||||
slice_formats,
|
slice_formats,
|
||||||
@@ -2576,7 +2576,7 @@ impl DashboardController {
|
|||||||
).await
|
).await
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
match add_result {
|
||||||
@@ -2594,7 +2594,7 @@ impl DashboardController {
|
|||||||
// If node_group_id is provided, assign nodes to existing group
|
// If node_group_id is provided, assign nodes to existing group
|
||||||
if let Some(group_id) = node_group_id {
|
if let Some(group_id) = node_group_id {
|
||||||
for node in &added_nodes {
|
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 {
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2606,7 +2606,7 @@ impl DashboardController {
|
|||||||
group_data.get("description").and_then(|v| v.as_str())
|
group_data.get("description").and_then(|v| v.as_str())
|
||||||
) {
|
) {
|
||||||
// Create node group
|
// Create node group
|
||||||
match farmer_service.create_custom_node_group(
|
match resource_provider_service.create_custom_node_group(
|
||||||
&user_email,
|
&user_email,
|
||||||
group_name.to_string(),
|
group_name.to_string(),
|
||||||
Some(group_description.to_string()),
|
Some(group_description.to_string()),
|
||||||
@@ -2626,7 +2626,7 @@ impl DashboardController {
|
|||||||
|
|
||||||
// Add nodes to group
|
// Add nodes to group
|
||||||
for node in &added_nodes {
|
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 {
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2691,7 +2691,7 @@ impl DashboardController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for node in &added_nodes {
|
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 {
|
} 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_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 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,
|
Ok(service) => service,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
"error": "Failed to initialize farmer service"
|
"error": "Failed to initialize resource_provider service"
|
||||||
})).build());
|
})).build());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2774,7 +2774,7 @@ impl DashboardController {
|
|||||||
resource_optimization: crate::models::user::ResourceOptimization::default(),
|
resource_optimization: crate::models::user::ResourceOptimization::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match farmer_service.create_custom_node_group(
|
match resource_provider_service.create_custom_node_group(
|
||||||
&user_email,
|
&user_email,
|
||||||
name.to_string(),
|
name.to_string(),
|
||||||
description,
|
description,
|
||||||
@@ -2810,7 +2810,7 @@ impl DashboardController {
|
|||||||
})).build()),
|
})).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,
|
Ok(service) => service,
|
||||||
Err(e) => return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
Err(e) => return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
"success": false,
|
"success": false,
|
||||||
@@ -2818,15 +2818,15 @@ impl DashboardController {
|
|||||||
})).build()),
|
})).build()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// FARMER FIX: Repair node-group data consistency before getting statistics
|
// RESOURCE_PROVIDER FIX: Repair node-group data consistency before getting statistics
|
||||||
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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
let mut groups_with_stats = Vec::new();
|
||||||
|
|
||||||
for group in groups {
|
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) => {
|
Ok(stats) => {
|
||||||
groups_with_stats.push(serde_json::json!({
|
groups_with_stats.push(serde_json::json!({
|
||||||
"group": group,
|
"group": group,
|
||||||
@@ -5387,7 +5387,7 @@ impl DashboardController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check if node exists and get its details first
|
// 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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -5398,7 +5398,7 @@ impl DashboardController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Verify node exists and belongs to user
|
// 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,
|
Some(node) => node,
|
||||||
None => {
|
None => {
|
||||||
return Ok(ResponseBuilder::not_found().json(serde_json::json!({
|
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -5970,7 +5970,7 @@ impl DashboardController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Stake on node
|
// 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(()) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": true,
|
"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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -6030,7 +6030,7 @@ impl DashboardController {
|
|||||||
match action {
|
match action {
|
||||||
"unstake" => {
|
"unstake" => {
|
||||||
// Unstake from node
|
// 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(returned_amount) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -6078,7 +6078,7 @@ impl DashboardController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Update node staking
|
// 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(()) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": true,
|
"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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": false,
|
"success": false,
|
||||||
@@ -6293,7 +6293,7 @@ impl DashboardController {
|
|||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Refresh slice calculations for farmer
|
/// Refresh slice calculations for resource_provider
|
||||||
pub async fn refresh_slice_calculations(session: Session) -> Result<impl Responder> {
|
pub async fn refresh_slice_calculations(session: Session) -> Result<impl Responder> {
|
||||||
let user_email = match session.get::<String>("user_email") {
|
let user_email = match session.get::<String>("user_email") {
|
||||||
Ok(Some(email)) => email,
|
Ok(Some(email)) => email,
|
||||||
@@ -6303,7 +6303,7 @@ impl DashboardController {
|
|||||||
})).build())
|
})).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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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(_) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": false,
|
"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> {
|
pub async fn sync_with_grid(session: Session) -> Result<impl Responder> {
|
||||||
// Check authentication
|
// Check authentication
|
||||||
if let Err(response) = Self::check_authentication(&session) {
|
if let Err(response) = Self::check_authentication(&session) {
|
||||||
@@ -6463,7 +6463,7 @@ impl DashboardController {
|
|||||||
|
|
||||||
let node_id = path.into_inner();
|
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
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(slices) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": false,
|
"success": false,
|
||||||
@@ -6525,7 +6525,7 @@ impl DashboardController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize services
|
// 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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -6550,7 +6550,7 @@ impl DashboardController {
|
|||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
for node_id in &node_ids {
|
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) => {
|
Ok(node_data) => {
|
||||||
// Calculate automatic slices
|
// Calculate automatic slices
|
||||||
let total_base_slices = slice_calculator.calculate_max_base_slices(&node_data.capacity);
|
let total_base_slices = slice_calculator.calculate_max_base_slices(&node_data.capacity);
|
||||||
@@ -6709,8 +6709,8 @@ impl DashboardController {
|
|||||||
})).build());
|
})).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize farmer service
|
// Initialize resource_provider service
|
||||||
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -6722,7 +6722,7 @@ impl DashboardController {
|
|||||||
|
|
||||||
// Add nodes with automatic slice management
|
// 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,
|
&user_email,
|
||||||
node_ids.clone(),
|
node_ids.clone(),
|
||||||
base_slice_price,
|
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> {
|
pub async fn refresh_slice_calculations_api(session: Session) -> Result<impl Responder> {
|
||||||
|
|
||||||
let user_email = session.get::<String>("user_email")
|
let user_email = session.get::<String>("user_email")
|
||||||
@@ -6773,8 +6773,8 @@ impl DashboardController {
|
|||||||
})).build());
|
})).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize farmer service
|
// Initialize resource_provider service
|
||||||
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -6785,7 +6785,7 @@ impl DashboardController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Refresh slice calculations for all nodes
|
// 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(updated_nodes) => {
|
||||||
|
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
@@ -6817,8 +6817,8 @@ impl DashboardController {
|
|||||||
})).build());
|
})).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize farmer service
|
// Initialize resource_provider service
|
||||||
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -6829,7 +6829,7 @@ impl DashboardController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Sync all nodes with grid
|
// 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(synced_nodes) => {
|
||||||
|
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
@@ -6863,8 +6863,8 @@ impl DashboardController {
|
|||||||
|
|
||||||
let node_id = path.into_inner();
|
let node_id = path.into_inner();
|
||||||
|
|
||||||
// Initialize farmer service
|
// Initialize resource_provider service
|
||||||
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,
|
Ok(service) => service,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||||
@@ -6875,7 +6875,7 @@ impl DashboardController {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get node slice details
|
// 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(slice_details) => {
|
||||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||||
"success": false,
|
"success": false,
|
||||||
|
@@ -13,7 +13,7 @@ use chrono::Utc;
|
|||||||
/// Form data for slice rental requests
|
/// Form data for slice rental requests
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct SliceRentalForm {
|
pub struct SliceRentalForm {
|
||||||
pub farmer_email: String,
|
pub resource_provider_email: String,
|
||||||
pub node_id: String,
|
pub node_id: String,
|
||||||
pub combination_id: String,
|
pub combination_id: String,
|
||||||
pub quantity: u32,
|
pub quantity: u32,
|
||||||
@@ -377,7 +377,7 @@ impl MarketplaceController {
|
|||||||
render_template(&tmpl, "marketplace/compute_resources.html", &ctx)
|
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> {
|
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
|
// Build services using established builder pattern
|
||||||
let currency_service = CurrencyService::builder()
|
let currency_service = CurrencyService::builder()
|
||||||
@@ -411,7 +411,7 @@ impl MarketplaceController {
|
|||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let page_size = 12;
|
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();
|
let all_node_products = node_marketplace_service.get_all_marketplace_nodes();
|
||||||
|
|
||||||
// Clone query for reuse
|
// Clone query for reuse
|
||||||
@@ -933,7 +933,7 @@ impl MarketplaceController {
|
|||||||
pub async fn show_slice_rental_form(
|
pub async fn show_slice_rental_form(
|
||||||
tmpl: web::Data<Tera>,
|
tmpl: web::Data<Tera>,
|
||||||
session: Session,
|
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> {
|
) -> Result<impl Responder> {
|
||||||
let mut ctx = crate::models::builders::ContextBuilder::new()
|
let mut ctx = crate::models::builders::ContextBuilder::new()
|
||||||
.active_page("marketplace")
|
.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
|
// Get slice details for the form
|
||||||
let node_marketplace_service = NodeMarketplaceService::builder()
|
let node_marketplace_service = NodeMarketplaceService::builder()
|
||||||
@@ -963,12 +963,12 @@ impl MarketplaceController {
|
|||||||
// Find the specific slice combination by checking product attributes
|
// Find the specific slice combination by checking product attributes
|
||||||
if let Some(slice_product) = slice_combinations.iter().find(|p| {
|
if let Some(slice_product) = slice_combinations.iter().find(|p| {
|
||||||
// Check if this product matches the requested slice
|
// Check if this product matches the requested slice
|
||||||
if let (Some(farmer_attr), Some(node_attr), Some(combo_attr)) = (
|
if let (Some(resource_provider_attr), Some(node_attr), Some(combo_attr)) = (
|
||||||
p.attributes.get("farmer_email"),
|
p.attributes.get("resource_provider_email"),
|
||||||
p.attributes.get("node_id"),
|
p.attributes.get("node_id"),
|
||||||
p.attributes.get("combination_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) &&
|
node_attr.value.as_str() == Some(&node_id) &&
|
||||||
combo_attr.value.as_str() == Some(&combination_id)
|
combo_attr.value.as_str() == Some(&combination_id)
|
||||||
} else {
|
} 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("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("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()));
|
slice_info.insert("combination_id", serde_json::Value::String(combination_id.clone()));
|
||||||
|
|
||||||
ctx.insert("slice", &slice_info);
|
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("node_id", &node_id);
|
||||||
ctx.insert("combination_id", &combination_id);
|
ctx.insert("combination_id", &combination_id);
|
||||||
}
|
}
|
||||||
@@ -1109,7 +1109,7 @@ impl MarketplaceController {
|
|||||||
// Attempt to rent the slice with deployment options
|
// Attempt to rent the slice with deployment options
|
||||||
match slice_rental_service.rent_slice_combination_with_deployment(
|
match slice_rental_service.rent_slice_combination_with_deployment(
|
||||||
&user_email,
|
&user_email,
|
||||||
&form.farmer_email,
|
&form.resource_provider_email,
|
||||||
&form.node_id,
|
&form.node_id,
|
||||||
&form.combination_id,
|
&form.combination_id,
|
||||||
form.quantity,
|
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_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("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("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" {
|
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_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))));
|
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
|
// Attempt to rent the slice with deployment options
|
||||||
match slice_rental_service.rent_slice_combination_with_deployment(
|
match slice_rental_service.rent_slice_combination_with_deployment(
|
||||||
&user_email,
|
&user_email,
|
||||||
&form.farmer_email,
|
&form.resource_provider_email,
|
||||||
&form.node_id,
|
&form.node_id,
|
||||||
&form.combination_id,
|
&form.combination_id,
|
||||||
form.quantity,
|
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_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("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("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())
|
serde_json::Value::Object(meta.into_iter().collect())
|
||||||
}),
|
}),
|
||||||
category: "slice_rental".to_string(),
|
category: "slice_rental".to_string(),
|
||||||
@@ -1270,7 +1270,7 @@ impl MarketplaceController {
|
|||||||
/// Request structure for slice rental with deployment options
|
/// Request structure for slice rental with deployment options
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct SliceRentalRequest {
|
pub struct SliceRentalRequest {
|
||||||
pub farmer_email: String,
|
pub resource_provider_email: String,
|
||||||
pub node_id: String,
|
pub node_id: String,
|
||||||
pub combination_id: String,
|
pub combination_id: String,
|
||||||
pub quantity: u32,
|
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
|
// Attempt to rent the slice combination
|
||||||
match slice_rental_service.rent_slice_combination(
|
match slice_rental_service.rent_slice_combination(
|
||||||
&user_email,
|
&user_email,
|
||||||
&form.farmer_email,
|
&form.resource_provider_email,
|
||||||
&form.node_id,
|
&form.node_id,
|
||||||
&form.combination_id,
|
&form.combination_id,
|
||||||
form.quantity,
|
form.quantity,
|
||||||
@@ -1602,7 +1602,7 @@ fn reconstruct_service_from_json(service_value: &serde_json::Value) -> Result<cr
|
|||||||
// Create SliceAssignmentRequest from the data
|
// Create SliceAssignmentRequest from the data
|
||||||
let assignment_request_obj = SliceAssignmentRequest {
|
let assignment_request_obj = SliceAssignmentRequest {
|
||||||
user_email: user_email.clone(),
|
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())
|
.and_then(|v| v.as_str())
|
||||||
.unwrap_or("unknown@example.com")
|
.unwrap_or("unknown@example.com")
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
@@ -88,8 +88,8 @@ impl PublicController {
|
|||||||
render_template(&tmpl, "legal/terms.html", &ctx)
|
render_template(&tmpl, "legal/terms.html", &ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the farmers terms page
|
/// Renders the resource providers terms page
|
||||||
pub async fn terms_farmers(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
pub async fn terms_resource_providers(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||||
let mut ctx = crate::models::builders::ContextBuilder::new()
|
let mut ctx = crate::models::builders::ContextBuilder::new()
|
||||||
.build();
|
.build();
|
||||||
ctx.insert("active_page", "terms");
|
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
|
/// Renders the service providers terms page
|
||||||
|
@@ -173,7 +173,7 @@ impl RentalController {
|
|||||||
rental_id: rental_id.clone(),
|
rental_id: rental_id.clone(),
|
||||||
slice_combination_id: format!("combo-{}", rental_id),
|
slice_combination_id: format!("combo-{}", rental_id),
|
||||||
node_id: "node-placeholder".to_string(), // TODO: Get from product
|
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 {
|
slice_allocation: crate::services::slice_calculator::SliceAllocation {
|
||||||
allocation_id: format!("alloc-{}", rental_id),
|
allocation_id: format!("alloc-{}", rental_id),
|
||||||
slice_combination_id: format!("combo-{}", rental_id),
|
slice_combination_id: format!("combo-{}", rental_id),
|
||||||
|
@@ -33,5 +33,5 @@ pub mod utils;
|
|||||||
|
|
||||||
// Re-export commonly used types
|
// Re-export commonly used types
|
||||||
pub use models::user::{User, NodeStakingOptions, FarmNode};
|
pub use models::user::{User, NodeStakingOptions, FarmNode};
|
||||||
pub use services::farmer::FarmerService;
|
pub use services::resource_provider::ResourceProviderService;
|
||||||
pub use services::user_persistence::UserPersistence;
|
pub use services::user_persistence::UserPersistence;
|
||||||
|
@@ -1234,11 +1234,11 @@ impl SessionDataBuilder {
|
|||||||
|
|
||||||
// MockDataBuilder removed - using persistent data only
|
// MockDataBuilder removed - using persistent data only
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// FARMER DATA BUILDER
|
// RESOURCE_PROVIDER DATA BUILDER
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FarmerDataBuilder {
|
pub struct ResourceProviderDataBuilder {
|
||||||
total_nodes: Option<i32>,
|
total_nodes: Option<i32>,
|
||||||
online_nodes: Option<i32>,
|
online_nodes: Option<i32>,
|
||||||
total_capacity: Option<crate::models::user::NodeCapacity>,
|
total_capacity: Option<crate::models::user::NodeCapacity>,
|
||||||
@@ -1251,7 +1251,7 @@ pub struct FarmerDataBuilder {
|
|||||||
active_slices: Option<i32>,
|
active_slices: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FarmerDataBuilder {
|
impl ResourceProviderDataBuilder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
@@ -1373,8 +1373,8 @@ impl FarmerDataBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Result<crate::models::user::FarmerData, String> {
|
pub fn build(self) -> Result<crate::models::user::ResourceProviderData, String> {
|
||||||
Ok(crate::models::user::FarmerData {
|
Ok(crate::models::user::ResourceProviderData {
|
||||||
total_nodes: self.total_nodes.unwrap_or(0),
|
total_nodes: self.total_nodes.unwrap_or(0),
|
||||||
online_nodes: self.online_nodes.unwrap_or(0),
|
online_nodes: self.online_nodes.unwrap_or(0),
|
||||||
total_capacity: self.total_capacity.unwrap_or(crate::models::user::NodeCapacity {
|
total_capacity: self.total_capacity.unwrap_or(crate::models::user::NodeCapacity {
|
||||||
@@ -1445,8 +1445,8 @@ impl FarmerDataBuilder {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SliceProductBuilder {
|
pub struct SliceProductBuilder {
|
||||||
farmer_id: Option<String>,
|
resource_provider_id: Option<String>,
|
||||||
farmer_name: Option<String>,
|
resource_provider_name: Option<String>,
|
||||||
slice_name: Option<String>,
|
slice_name: Option<String>,
|
||||||
cpu_cores: Option<i32>,
|
cpu_cores: Option<i32>,
|
||||||
memory_gb: Option<i32>,
|
memory_gb: Option<i32>,
|
||||||
@@ -1464,13 +1464,13 @@ impl SliceProductBuilder {
|
|||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn farmer_id(mut self, farmer_id: impl Into<String>) -> Self {
|
pub fn resource_provider_id(mut self, resource_provider_id: impl Into<String>) -> Self {
|
||||||
self.farmer_id = Some(farmer_id.into());
|
self.resource_provider_id = Some(resource_provider_id.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn farmer_name(mut self, farmer_name: impl Into<String>) -> Self {
|
pub fn resource_provider_name(mut self, resource_provider_name: impl Into<String>) -> Self {
|
||||||
self.farmer_name = Some(farmer_name.into());
|
self.resource_provider_name = Some(resource_provider_name.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1525,8 +1525,8 @@ impl SliceProductBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Result<crate::models::product::Product, String> {
|
pub fn build(self) -> Result<crate::models::product::Product, String> {
|
||||||
let farmer_id = self.farmer_id.ok_or("farmer_id is required")?;
|
let resource_provider_id = self.resource_provider_id.ok_or("resource_provider_id is required")?;
|
||||||
let farmer_name = self.farmer_name.ok_or("farmer_name 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 slice_name = self.slice_name.ok_or("slice_name is required")?;
|
||||||
let cpu_cores = self.cpu_cores.ok_or("cpu_cores 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")?;
|
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(
|
Ok(crate::models::product::Product::create_slice_product(
|
||||||
farmer_id,
|
resource_provider_id,
|
||||||
farmer_name,
|
resource_provider_name,
|
||||||
slice_name,
|
slice_name,
|
||||||
slice_config,
|
slice_config,
|
||||||
price_per_hour,
|
price_per_hour,
|
||||||
@@ -2081,7 +2081,7 @@ impl NodeRentalBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FarmerRentalEarningBuilder {
|
pub struct ResourceProviderRentalEarningBuilder {
|
||||||
id: Option<String>,
|
id: Option<String>,
|
||||||
node_id: Option<String>,
|
node_id: Option<String>,
|
||||||
rental_id: Option<String>,
|
rental_id: Option<String>,
|
||||||
@@ -2093,7 +2093,7 @@ pub struct FarmerRentalEarningBuilder {
|
|||||||
payment_status: Option<crate::models::user::PaymentStatus>,
|
payment_status: Option<crate::models::user::PaymentStatus>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FarmerRentalEarningBuilder {
|
impl ResourceProviderRentalEarningBuilder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
@@ -2143,10 +2143,10 @@ impl FarmerRentalEarningBuilder {
|
|||||||
self
|
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()));
|
let id = self.id.unwrap_or_else(|| format!("earning_{}", uuid::Uuid::new_v4()));
|
||||||
|
|
||||||
Ok(crate::models::user::FarmerRentalEarning {
|
Ok(crate::models::user::ResourceProviderRentalEarning {
|
||||||
id,
|
id,
|
||||||
node_id: self.node_id.ok_or("node_id is required")?,
|
node_id: self.node_id.ok_or("node_id is required")?,
|
||||||
rental_id: self.rental_id.ok_or("rental_id is required")?,
|
rental_id: self.rental_id.ok_or("rental_id is required")?,
|
||||||
@@ -2469,8 +2469,8 @@ impl NodeCreationDataBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Result<crate::services::farmer::NodeCreationData, String> {
|
pub fn build(self) -> Result<crate::services::resource_provider::NodeCreationData, String> {
|
||||||
Ok(crate::services::farmer::NodeCreationData {
|
Ok(crate::services::resource_provider::NodeCreationData {
|
||||||
name: self.name.ok_or("name is required")?,
|
name: self.name.ok_or("name is required")?,
|
||||||
location: self.location.ok_or("location is required")?,
|
location: self.location.ok_or("location is required")?,
|
||||||
cpu_cores: self.cpu_cores.unwrap_or(4),
|
cpu_cores: self.cpu_cores.unwrap_or(4),
|
||||||
|
@@ -305,10 +305,10 @@ pub enum SliceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Product {
|
impl Product {
|
||||||
/// Create a slice product from farmer configuration
|
/// Create a slice product from resource_provider configuration
|
||||||
pub fn create_slice_product(
|
pub fn create_slice_product(
|
||||||
farmer_id: String,
|
resource_provider_id: String,
|
||||||
farmer_name: String,
|
resource_provider_name: String,
|
||||||
slice_name: String,
|
slice_name: String,
|
||||||
slice_config: SliceConfiguration,
|
slice_config: SliceConfiguration,
|
||||||
price_per_hour: Decimal,
|
price_per_hour: Decimal,
|
||||||
@@ -322,8 +322,8 @@ impl Product {
|
|||||||
slice_config.cpu_cores, slice_config.memory_gb, slice_config.storage_gb),
|
slice_config.cpu_cores, slice_config.memory_gb, slice_config.storage_gb),
|
||||||
price_per_hour,
|
price_per_hour,
|
||||||
"USD".to_string(),
|
"USD".to_string(),
|
||||||
farmer_id,
|
resource_provider_id,
|
||||||
farmer_name,
|
resource_provider_name,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add slice-specific attributes
|
// Add slice-specific attributes
|
||||||
@@ -448,8 +448,8 @@ impl Product {
|
|||||||
/// Create a full node product from a FarmNode
|
/// Create a full node product from a FarmNode
|
||||||
pub fn create_full_node_product(
|
pub fn create_full_node_product(
|
||||||
node: &crate::models::user::FarmNode,
|
node: &crate::models::user::FarmNode,
|
||||||
farmer_email: &str,
|
resource_provider_email: &str,
|
||||||
farmer_name: &str,
|
resource_provider_name: &str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut product = Product {
|
let mut product = Product {
|
||||||
id: format!("fullnode_{}", node.id),
|
id: format!("fullnode_{}", node.id),
|
||||||
@@ -469,8 +469,8 @@ impl Product {
|
|||||||
.unwrap_or_else(|| Decimal::from(200)), // Default price
|
.unwrap_or_else(|| Decimal::from(200)), // Default price
|
||||||
base_currency: "USD".to_string(),
|
base_currency: "USD".to_string(),
|
||||||
attributes: HashMap::new(),
|
attributes: HashMap::new(),
|
||||||
provider_id: farmer_email.to_string(),
|
provider_id: resource_provider_email.to_string(),
|
||||||
provider_name: farmer_name.to_string(),
|
provider_name: resource_provider_name.to_string(),
|
||||||
availability: match node.availability_status {
|
availability: match node.availability_status {
|
||||||
crate::models::user::NodeAvailabilityStatus::Available => ProductAvailability::Available,
|
crate::models::user::NodeAvailabilityStatus::Available => ProductAvailability::Available,
|
||||||
crate::models::user::NodeAvailabilityStatus::PartiallyRented => ProductAvailability::Limited,
|
crate::models::user::NodeAvailabilityStatus::PartiallyRented => ProductAvailability::Limited,
|
||||||
|
@@ -146,7 +146,7 @@ pub struct RegionDeployments {
|
|||||||
pub gateways: i32,
|
pub gateways: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Node information for farmer dashboard
|
/// Node information for resource_provider dashboard
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct NodeInfo {
|
pub struct NodeInfo {
|
||||||
pub id: String,
|
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 {
|
pub fn default_maintenance_window() -> String {
|
||||||
"02:00-04:00 UTC".to_string()
|
"02:00-04:00 UTC".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Farmer configuration settings
|
/// ResourceProvider configuration settings
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct FarmerSettings {
|
pub struct ResourceProviderSettings {
|
||||||
pub auto_accept_reserved_slices: bool,
|
pub auto_accept_reserved_slices: bool,
|
||||||
pub maintenance_window: String, // e.g., "02:00-04:00 UTC"
|
pub maintenance_window: String, // e.g., "02:00-04:00 UTC"
|
||||||
pub notification_email: Option<String>,
|
pub notification_email: Option<String>,
|
||||||
@@ -229,7 +229,7 @@ pub struct FarmerSettings {
|
|||||||
pub preferred_regions: Vec<String>,
|
pub preferred_regions: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FarmerSettings {
|
impl Default for ResourceProviderSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
auto_accept_reserved_slices: true,
|
auto_accept_reserved_slices: true,
|
||||||
@@ -324,7 +324,7 @@ impl Default for LiquidityPoolConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FarmerData {
|
impl Default for ResourceProviderData {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
total_nodes: 0,
|
total_nodes: 0,
|
||||||
@@ -761,9 +761,9 @@ pub struct QuickAction {
|
|||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Farmer-specific data
|
/// ResourceProvider-specific data
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct FarmerData {
|
pub struct ResourceProviderData {
|
||||||
pub total_nodes: i32,
|
pub total_nodes: i32,
|
||||||
pub active_nodes: i32,
|
pub active_nodes: i32,
|
||||||
pub total_monthly_earnings_usd: i32,
|
pub total_monthly_earnings_usd: i32,
|
||||||
@@ -1224,7 +1224,7 @@ where
|
|||||||
.map_err(serde::de::Error::custom)
|
.map_err(serde::de::Error::custom)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Node group for farmer organization
|
/// Node group for resource_provider organization
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct NodeGroup {
|
pub struct NodeGroup {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@@ -1358,7 +1358,7 @@ pub struct NodeCapacity {
|
|||||||
pub ram_gb: i32,
|
pub ram_gb: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Farmer node information
|
/// ResourceProvider node information
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct FarmNode {
|
pub struct FarmNode {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@@ -1418,7 +1418,7 @@ pub struct FarmNode {
|
|||||||
pub health_score: f32,
|
pub health_score: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Earnings record for farmer data
|
/// Earnings record for resource_provider data
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct EarningsRecord {
|
pub struct EarningsRecord {
|
||||||
pub date: String,
|
pub date: String,
|
||||||
@@ -1428,7 +1428,7 @@ pub struct EarningsRecord {
|
|||||||
pub source: String,
|
pub source: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Group statistics for farmer dashboard
|
/// Group statistics for resource_provider dashboard
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct GroupStatistics {
|
pub struct GroupStatistics {
|
||||||
pub group_name: String,
|
pub group_name: String,
|
||||||
@@ -1517,7 +1517,7 @@ pub struct GridNodeData {
|
|||||||
|
|
||||||
/// Additional missing user model types
|
/// Additional missing user model types
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct FarmerRentalEarning {
|
pub struct ResourceProviderRentalEarning {
|
||||||
pub date: String,
|
pub date: String,
|
||||||
pub amount: Decimal,
|
pub amount: Decimal,
|
||||||
pub rental_id: String,
|
pub rental_id: String,
|
||||||
|
@@ -52,7 +52,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
|||||||
.route("/marketplace/services", web::get().to(MarketplaceController::services))
|
.route("/marketplace/services", web::get().to(MarketplaceController::services))
|
||||||
.route("/marketplace/statistics", web::get().to(MarketplaceController::statistics))
|
.route("/marketplace/statistics", web::get().to(MarketplaceController::statistics))
|
||||||
// Slice rental routes
|
// 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/slice/rent", web::post().to(MarketplaceController::process_slice_rental))
|
||||||
// .route("/marketplace/rent-slice", web::post().to(MarketplaceController::rent_slice)) // Legacy route [DISABLED]
|
// .route("/marketplace/rent-slice", web::post().to(MarketplaceController::rent_slice)) // Legacy route [DISABLED]
|
||||||
// Product routes
|
// 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}/manage", web::post().to(DashboardController::manage_slice_rental_deployment))
|
||||||
.route("/dashboard/slice-rentals/{id}", web::delete().to(DashboardController::cancel_slice_rental))
|
.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/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/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::get().to(DashboardController::get_slice_products))
|
||||||
.route("/dashboard/slice-products", web::post().to(DashboardController::create_slice_product))
|
.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-details/{id}", web::get().to(DashboardController::get_slice_details))
|
||||||
.route("/dashboard/slice-configuration/{id}", web::put().to(DashboardController::update_slice_configuration))
|
.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))
|
.route("/dashboard/service-provider-data", web::get().to(DashboardController::service_provider_data_api))
|
||||||
// Farmer management API routes
|
// Resource provider management API routes
|
||||||
.route("/dashboard/farm-nodes", web::post().to(DashboardController::add_farm_node))
|
.route("/dashboard/resource_provider-nodes", web::post().to(DashboardController::add_resource_provider_node))
|
||||||
.route("/dashboard/farm-nodes-enhanced", web::post().to(DashboardController::add_farm_node_enhanced))
|
.route("/dashboard/resource_provider-nodes-enhanced", web::post().to(DashboardController::add_resource_provider_node_enhanced))
|
||||||
.route("/dashboard/farm-nodes/{id}", web::get().to(DashboardController::get_node_details))
|
.route("/dashboard/resource_provider-nodes/{id}", web::get().to(DashboardController::get_node_details))
|
||||||
.route("/dashboard/farm-nodes/{id}", web::put().to(DashboardController::update_node_comprehensive))
|
.route("/dashboard/resource_provider-nodes/{id}", web::put().to(DashboardController::update_node_comprehensive))
|
||||||
.route("/dashboard/farm-nodes/{id}/status", web::put().to(DashboardController::update_node_status))
|
.route("/dashboard/resource_provider-nodes/{id}/status", web::put().to(DashboardController::update_node_status))
|
||||||
// Farmer slice management API routes
|
// Resource provider slice management API routes
|
||||||
.route("/dashboard/farmer/slice-calculations/refresh", web::post().to(DashboardController::refresh_slice_calculations))
|
.route("/dashboard/resource_provider/slice-calculations/refresh", web::post().to(DashboardController::refresh_slice_calculations))
|
||||||
.route("/dashboard/farmer/grid-sync", web::post().to(DashboardController::sync_with_grid))
|
.route("/dashboard/resource_provider/grid-sync", web::post().to(DashboardController::sync_with_grid))
|
||||||
.route("/dashboard/farmer/nodes/{id}/slices", web::get().to(DashboardController::get_node_slices))
|
.route("/dashboard/resource_provider/nodes/{id}/slices", web::get().to(DashboardController::get_node_slices))
|
||||||
.route("/dashboard/farmer/slice-statistics", web::get().to(DashboardController::get_slice_statistics))
|
.route("/dashboard/resource_provider/slice-statistics", web::get().to(DashboardController::get_slice_statistics))
|
||||||
.route("/dashboard/farm-nodes/{id}", web::delete().to(DashboardController::delete_node))
|
.route("/dashboard/resource_provider-nodes/{id}", web::delete().to(DashboardController::delete_node))
|
||||||
.route("/dashboard/farm-nodes/{id}/configuration", web::put().to(DashboardController::update_node_configuration))
|
.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-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-details/{id}", web::get().to(DashboardController::get_default_slice_details))
|
||||||
.route("/dashboard/default-slice-customization/{id}", web::put().to(DashboardController::save_default_slice_customization))
|
.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/node-groups/{id}", web::delete().to(DashboardController::delete_custom_node_group))
|
||||||
.route("/dashboard/nodes/assign-group", web::post().to(DashboardController::assign_node_to_group))
|
.route("/dashboard/nodes/assign-group", web::post().to(DashboardController::assign_node_to_group))
|
||||||
// Node staking API routes
|
// Node staking API routes
|
||||||
.route("/dashboard/farm-nodes/{id}/stake", web::post().to(DashboardController::stake_on_node))
|
.route("/dashboard/resource_provider-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}/staking", web::put().to(DashboardController::update_node_staking))
|
||||||
.route("/dashboard/staking/statistics", web::get().to(DashboardController::get_staking_statistics))
|
.route("/dashboard/staking/statistics", web::get().to(DashboardController::get_staking_statistics))
|
||||||
// Service management API routes
|
// Service management API routes
|
||||||
.route("/dashboard/services", web::get().to(DashboardController::get_user_services))
|
.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
|
.wrap(JwtAuth) // Apply authentication middleware to all dashboard routes
|
||||||
.route("", web::get().to(DashboardController::index))
|
.route("", web::get().to(DashboardController::index))
|
||||||
.route("/user", web::get().to(DashboardController::user_section))
|
.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("/app-provider", web::get().to(DashboardController::app_provider_section))
|
||||||
.route("/service-provider", web::get().to(DashboardController::service_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)
|
// Public information routes (legal, changelog, roadmap)
|
||||||
.route("/privacy", web::get().to(PublicController::privacy))
|
.route("/privacy", web::get().to(PublicController::privacy))
|
||||||
.route("/terms", web::get().to(PublicController::terms))
|
.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/service-providers", web::get().to(PublicController::terms_service_providers))
|
||||||
.route("/terms/solution-providers", web::get().to(PublicController::terms_solution_providers))
|
.route("/terms/solution-providers", web::get().to(PublicController::terms_solution_providers))
|
||||||
.route("/terms/users", web::get().to(PublicController::terms_users))
|
.route("/terms/users", web::get().to(PublicController::terms_users))
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
pub mod auto_topup;
|
pub mod auto_topup;
|
||||||
pub mod currency;
|
pub mod currency;
|
||||||
pub mod factory;
|
pub mod factory;
|
||||||
pub mod farmer;
|
pub mod resource_provider;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
pub mod instant_purchase;
|
pub mod instant_purchase;
|
||||||
pub mod navbar;
|
pub mod navbar;
|
||||||
|
@@ -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
|
//! Follows the established builder pattern for consistent API design
|
||||||
|
|
||||||
use crate::models::user::FarmNode;
|
use crate::models::user::FarmNode;
|
||||||
@@ -11,7 +11,7 @@ use rust_decimal::prelude::ToPrimitive;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
/// Service for converting farmer nodes to marketplace products
|
/// Service for converting resource_provider nodes to marketplace products
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct NodeMarketplaceService {
|
pub struct NodeMarketplaceService {
|
||||||
currency_service: CurrencyService,
|
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> {
|
pub fn get_all_marketplace_nodes(&self) -> Vec<Product> {
|
||||||
let mut all_products = Vec::new();
|
let mut all_products = Vec::new();
|
||||||
|
|
||||||
@@ -125,16 +125,16 @@ impl NodeMarketplaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert FarmNode to Product using builder pattern
|
/// 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
|
// Calculate price based on node capacity
|
||||||
let hourly_price = self.calculate_node_price(node)?;
|
let hourly_price = self.calculate_node_price(node)?;
|
||||||
|
|
||||||
// Create product attributes with node specifications
|
// Create product attributes with node specifications
|
||||||
let mut attributes = HashMap::new();
|
let mut attributes = HashMap::new();
|
||||||
|
|
||||||
attributes.insert("farmer_email".to_string(), crate::models::product::ProductAttribute {
|
attributes.insert("resource_provider_email".to_string(), crate::models::product::ProductAttribute {
|
||||||
key: "farmer_email".to_string(),
|
key: "resource_provider_email".to_string(),
|
||||||
value: serde_json::Value::String(farmer_email.to_string()),
|
value: serde_json::Value::String(resource_provider_email.to_string()),
|
||||||
attribute_type: crate::models::product::AttributeType::Text,
|
attribute_type: crate::models::product::AttributeType::Text,
|
||||||
is_searchable: true,
|
is_searchable: true,
|
||||||
is_filterable: true,
|
is_filterable: true,
|
||||||
@@ -200,8 +200,8 @@ impl NodeMarketplaceService {
|
|||||||
display_order: Some(6),
|
display_order: Some(6),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get farmer display name
|
// Get resource_provider display name
|
||||||
let farmer_display_name = self.get_farmer_display_name(farmer_email);
|
let resource_provider_display_name = self.get_resource_provider_display_name(resource_provider_email);
|
||||||
|
|
||||||
// Create metadata with location
|
// Create metadata with location
|
||||||
let metadata = crate::models::product::ProductMetadata {
|
let metadata = crate::models::product::ProductMetadata {
|
||||||
@@ -215,7 +215,7 @@ impl NodeMarketplaceService {
|
|||||||
// Use Product builder pattern with add_attribute for each attribute
|
// Use Product builder pattern with add_attribute for each attribute
|
||||||
let mut builder = crate::models::product::Product::builder()
|
let mut builder = crate::models::product::Product::builder()
|
||||||
.id(format!("node_{}", node.id))
|
.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}",
|
.description(format!("Mycelium Node with {} CPU cores, {} GB RAM, {} GB storage in {}. Uptime: {:.1}%, Health Score: {:.1}",
|
||||||
node.capacity.cpu_cores,
|
node.capacity.cpu_cores,
|
||||||
node.capacity.memory_gb,
|
node.capacity.memory_gb,
|
||||||
@@ -226,8 +226,8 @@ impl NodeMarketplaceService {
|
|||||||
.base_price(hourly_price)
|
.base_price(hourly_price)
|
||||||
.base_currency("USD".to_string())
|
.base_currency("USD".to_string())
|
||||||
.category_id("hardware".to_string())
|
.category_id("hardware".to_string())
|
||||||
.provider_id(farmer_email.to_string())
|
.provider_id(resource_provider_email.to_string())
|
||||||
.provider_name(farmer_display_name)
|
.provider_name(resource_provider_display_name)
|
||||||
.metadata(metadata)
|
.metadata(metadata)
|
||||||
.availability(if self.is_node_online(node) {
|
.availability(if self.is_node_online(node) {
|
||||||
crate::models::product::ProductAvailability::Available
|
crate::models::product::ProductAvailability::Available
|
||||||
@@ -276,17 +276,17 @@ impl NodeMarketplaceService {
|
|||||||
format!("{}", node.status) == "Online"
|
format!("{}", node.status) == "Online"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get farmer display name from email
|
/// Get resource_provider display name from email
|
||||||
fn get_farmer_display_name(&self, farmer_email: &str) -> String {
|
fn get_resource_provider_display_name(&self, resource_provider_email: &str) -> String {
|
||||||
// Try to get actual name from persistent data
|
// 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 {
|
if let Some(name) = user_data.name {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to email username
|
// 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
|
/// Apply marketplace filters to node products
|
||||||
@@ -438,7 +438,7 @@ impl NodeMarketplaceService {
|
|||||||
let mut total_cpu_cores = 0u32;
|
let mut total_cpu_cores = 0u32;
|
||||||
let mut total_memory_gb = 0u32;
|
let mut total_memory_gb = 0u32;
|
||||||
let mut total_storage_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();
|
let mut unique_locations = std::collections::HashSet::new();
|
||||||
|
|
||||||
for product in &all_slices {
|
for product in &all_slices {
|
||||||
@@ -456,8 +456,8 @@ impl NodeMarketplaceService {
|
|||||||
total_storage_gb += (storage * quantity) as u32;
|
total_storage_gb += (storage * quantity) as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(farmer) = product.attributes.get("farmer_email").and_then(|f| f.value.as_str()) {
|
if let Some(resource_provider) = product.attributes.get("resource_provider_email").and_then(|f| f.value.as_str()) {
|
||||||
unique_farmers.insert(farmer.to_string());
|
unique_resource_providers.insert(resource_provider.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(location) = &product.metadata.location {
|
if let Some(location) = &product.metadata.location {
|
||||||
@@ -471,9 +471,9 @@ impl NodeMarketplaceService {
|
|||||||
"total_cpu_cores": total_cpu_cores,
|
"total_cpu_cores": total_cpu_cores,
|
||||||
"total_memory_gb": total_memory_gb,
|
"total_memory_gb": total_memory_gb,
|
||||||
"total_storage_gb": total_storage_gb,
|
"total_storage_gb": total_storage_gb,
|
||||||
"unique_farmers": unique_farmers.len(),
|
"unique_resource_providers": unique_resource_providers.len(),
|
||||||
"unique_locations": unique_locations.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<_>>()
|
"locations": unique_locations.into_iter().collect::<Vec<_>>()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -531,7 +531,7 @@ impl NodeMarketplaceService {
|
|||||||
pub fn get_all_slice_combinations(&self) -> Vec<Product> {
|
pub fn get_all_slice_combinations(&self) -> Vec<Product> {
|
||||||
let mut all_slice_products = Vec::new();
|
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") {
|
if let Ok(entries) = std::fs::read_dir("./user_data") {
|
||||||
for entry in entries.flatten() {
|
for entry in entries.flatten() {
|
||||||
if let Some(filename) = entry.file_name().to_str() {
|
if let Some(filename) = entry.file_name().to_str() {
|
||||||
@@ -585,14 +585,14 @@ impl NodeMarketplaceService {
|
|||||||
&self,
|
&self,
|
||||||
combination: &SliceCombination,
|
combination: &SliceCombination,
|
||||||
_node: &FarmNode,
|
_node: &FarmNode,
|
||||||
farmer_email: &str
|
resource_provider_email: &str
|
||||||
) -> Result<Product, String> {
|
) -> Result<Product, String> {
|
||||||
let mut attributes = HashMap::new();
|
let mut attributes = HashMap::new();
|
||||||
|
|
||||||
// Farmer information
|
// ResourceProvider information
|
||||||
attributes.insert("farmer_email".to_string(), crate::models::product::ProductAttribute {
|
attributes.insert("resource_provider_email".to_string(), crate::models::product::ProductAttribute {
|
||||||
key: "farmer_email".to_string(),
|
key: "resource_provider_email".to_string(),
|
||||||
value: serde_json::Value::String(farmer_email.to_string()),
|
value: serde_json::Value::String(resource_provider_email.to_string()),
|
||||||
attribute_type: crate::models::product::AttributeType::Text,
|
attribute_type: crate::models::product::AttributeType::Text,
|
||||||
is_searchable: true,
|
is_searchable: true,
|
||||||
is_filterable: true,
|
is_filterable: true,
|
||||||
@@ -701,15 +701,15 @@ impl NodeMarketplaceService {
|
|||||||
display_order: Some(10),
|
display_order: Some(10),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get farmer display name
|
// Get resource_provider display name
|
||||||
let farmer_display_name = self.get_farmer_display_name(farmer_email);
|
let resource_provider_display_name = self.get_resource_provider_display_name(resource_provider_email);
|
||||||
|
|
||||||
// Create metadata
|
// Create metadata
|
||||||
let metadata = crate::models::product::ProductMetadata {
|
let metadata = crate::models::product::ProductMetadata {
|
||||||
location: Some(combination.node_location.clone()),
|
location: Some(combination.node_location.clone()),
|
||||||
custom_fields: {
|
custom_fields: {
|
||||||
let mut fields = std::collections::HashMap::new();
|
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("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("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()));
|
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
|
// Build product using the builder pattern
|
||||||
let mut product = crate::models::product::Product::builder()
|
let mut product = crate::models::product::Product::builder()
|
||||||
.id(format!("slice_{}_{}", combination.node_id, combination.id))
|
.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!(
|
.description(format!(
|
||||||
"Compute slice with {} vCPU, {}GB RAM, {}GB storage from {} ({}% uptime)",
|
"Compute slice with {} vCPU, {}GB RAM, {}GB storage from {} ({}% uptime)",
|
||||||
combination.cpu_cores,
|
combination.cpu_cores,
|
||||||
@@ -739,8 +739,8 @@ impl NodeMarketplaceService {
|
|||||||
.category_id("compute_slices".to_string())
|
.category_id("compute_slices".to_string())
|
||||||
.base_price(combination.price_per_hour)
|
.base_price(combination.price_per_hour)
|
||||||
.base_currency("USD".to_string())
|
.base_currency("USD".to_string())
|
||||||
.provider_id(farmer_email.to_string())
|
.provider_id(resource_provider_email.to_string())
|
||||||
.provider_name(farmer_display_name)
|
.provider_name(resource_provider_display_name)
|
||||||
.metadata(metadata)
|
.metadata(metadata)
|
||||||
.build()
|
.build()
|
||||||
.map_err(|e| format!("Failed to build slice product: {}", e))?;
|
.map_err(|e| format!("Failed to build slice product: {}", e))?;
|
||||||
|
@@ -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
|
//! 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 crate::services::user_persistence::{UserPersistence, ProductRental};
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
use chrono::{Utc, Duration};
|
use chrono::{Utc, Duration};
|
||||||
@@ -65,7 +65,7 @@ impl NodeRentalService {
|
|||||||
duration_months: u32,
|
duration_months: u32,
|
||||||
rental_type: NodeRentalType,
|
rental_type: NodeRentalType,
|
||||||
monthly_cost: Decimal,
|
monthly_cost: Decimal,
|
||||||
) -> Result<(NodeRental, FarmerRentalEarning), String> {
|
) -> Result<(NodeRental, ResourceProviderRentalEarning), String> {
|
||||||
// Extract node ID from product ID
|
// Extract node ID from product ID
|
||||||
let node_id = if product_id.starts_with("fullnode_") {
|
let node_id = if product_id.starts_with("fullnode_") {
|
||||||
product_id.strip_prefix("fullnode_").unwrap_or(product_id)
|
product_id.strip_prefix("fullnode_").unwrap_or(product_id)
|
||||||
@@ -99,8 +99,8 @@ impl NodeRentalService {
|
|||||||
.payment_method("USD".to_string())
|
.payment_method("USD".to_string())
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
// Create farmer earning record
|
// Create resource_provider earning record
|
||||||
let farmer_earning = crate::models::builders::FarmerRentalEarningBuilder::new()
|
let resource_provider_earning = crate::models::builders::ResourceProviderRentalEarningBuilder::new()
|
||||||
.node_id(node_id.to_string())
|
.node_id(node_id.to_string())
|
||||||
.rental_id(rental.id.clone())
|
.rental_id(rental.id.clone())
|
||||||
.renter_email(renter_email.to_string())
|
.renter_email(renter_email.to_string())
|
||||||
@@ -111,29 +111,29 @@ impl NodeRentalService {
|
|||||||
.payment_status(PaymentStatus::Completed)
|
.payment_status(PaymentStatus::Completed)
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
// Find the farmer who owns this node
|
// Find the resource_provider who owns this node
|
||||||
let farmer_email = self.find_node_owner(node_id)?;
|
let resource_provider_email = self.find_node_owner(node_id)?;
|
||||||
|
|
||||||
// Save rental to renter's data
|
// Save rental to renter's data
|
||||||
self.save_rental_to_user(&rental, renter_email, product_id)?;
|
self.save_rental_to_user(&rental, renter_email, product_id)?;
|
||||||
|
|
||||||
// Save earning to farmer's data
|
// Save earning to resource_provider's data
|
||||||
self.save_earning_to_farmer(&farmer_earning, &farmer_email)?;
|
self.save_earning_to_resource_provider(&resource_provider_earning, &resource_provider_email)?;
|
||||||
|
|
||||||
// Update node availability status
|
// 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
|
/// Check for rental conflicts
|
||||||
fn check_rental_conflicts(&self, node_id: &str, rental_type: &NodeRentalType) -> Result<(), String> {
|
fn check_rental_conflicts(&self, node_id: &str, rental_type: &NodeRentalType) -> Result<(), String> {
|
||||||
// Find the farmer who owns this node
|
// Find the resource_provider who owns this node
|
||||||
let farmer_email = self.find_node_owner(node_id)?;
|
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
|
// 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())
|
.filter(|r| r.node_id == node_id && r.is_active())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ impl NodeRentalService {
|
|||||||
Ok(())
|
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> {
|
fn find_node_owner(&self, node_id: &str) -> Result<String, String> {
|
||||||
// Scan all user files to find the node owner
|
// Scan all user files to find the node owner
|
||||||
if let Ok(entries) = std::fs::read_dir("./user_data/") {
|
if let Ok(entries) = std::fs::read_dir("./user_data/") {
|
||||||
@@ -226,31 +226,31 @@ impl NodeRentalService {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Save earning record to farmer's persistent data
|
/// Save earning record to resource_provider's persistent data
|
||||||
fn save_earning_to_farmer(&self, earning: &FarmerRentalEarning, farmer_email: &str) -> Result<(), String> {
|
fn save_earning_to_resource_provider(&self, earning: &ResourceProviderRentalEarning, resource_provider_email: &str) -> Result<(), String> {
|
||||||
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
|
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
|
||||||
.unwrap_or_else(|| self.create_default_user_data(farmer_email));
|
.unwrap_or_else(|| self.create_default_user_data(resource_provider_email));
|
||||||
|
|
||||||
// Add to farmer rental earnings
|
// Add to resource_provider rental earnings
|
||||||
farmer_data.farmer_rental_earnings.push(earning.clone());
|
resource_provider_data.resource_provider_rental_earnings.push(earning.clone());
|
||||||
|
|
||||||
// Update wallet balance
|
// Update wallet balance
|
||||||
farmer_data.wallet_balance_usd += earning.amount;
|
resource_provider_data.wallet_balance_usd += earning.amount;
|
||||||
|
|
||||||
UserPersistence::save_user_data(&farmer_data)
|
UserPersistence::save_user_data(&resource_provider_data)
|
||||||
.map_err(|e| format!("Failed to save farmer data: {}", e))?;
|
.map_err(|e| format!("Failed to save resource_provider data: {}", e))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update node availability status based on current rentals
|
/// Update node availability status based on current rentals
|
||||||
fn update_node_availability(&self, node_id: &str, farmer_email: &str) -> Result<(), String> {
|
fn update_node_availability(&self, node_id: &str, resource_provider_email: &str) -> Result<(), String> {
|
||||||
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
|
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
|
||||||
.ok_or("Farmer data not found")?;
|
.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
|
// 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())
|
.filter(|r| r.node_id == node_id && r.is_active())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -262,7 +262,7 @@ impl NodeRentalService {
|
|||||||
NodeAvailabilityStatus::PartiallyRented
|
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))?;
|
.map_err(|e| format!("Failed to update node availability: {}", e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,10 +285,10 @@ impl NodeRentalService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get farmer earnings from rentals
|
/// Get resource_provider earnings from rentals
|
||||||
pub fn get_farmer_rental_earnings(&self, farmer_email: &str) -> Vec<FarmerRentalEarning> {
|
pub fn get_resource_provider_rental_earnings(&self, resource_provider_email: &str) -> Vec<ResourceProviderRentalEarning> {
|
||||||
if let Some(farmer_data) = UserPersistence::load_user_data(farmer_email) {
|
if let Some(resource_provider_data) = UserPersistence::load_user_data(resource_provider_email) {
|
||||||
farmer_data.farmer_rental_earnings
|
resource_provider_data.resource_provider_rental_earnings
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
@@ -309,8 +309,8 @@ impl NodeRentalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update node availability
|
// Update node availability
|
||||||
let farmer_email = self.find_node_owner(&rental.node_id)?;
|
let resource_provider_email = self.find_node_owner(&rental.node_id)?;
|
||||||
self.update_node_availability(&rental.node_id, &farmer_email)?;
|
self.update_node_availability(&rental.node_id, &resource_provider_email)?;
|
||||||
|
|
||||||
UserPersistence::save_user_data(&user_data)
|
UserPersistence::save_user_data(&user_data)
|
||||||
.map_err(|e| format!("Failed to save user data: {}", e))?;
|
.map_err(|e| format!("Failed to save user data: {}", e))?;
|
||||||
|
@@ -241,8 +241,8 @@ impl ProductService {
|
|||||||
if let Some(combination_id) = product.attributes.get("combination_id") {
|
if let Some(combination_id) = product.attributes.get("combination_id") {
|
||||||
details["combination_id"] = combination_id.value.clone();
|
details["combination_id"] = combination_id.value.clone();
|
||||||
}
|
}
|
||||||
if let Some(farmer_email) = product.attributes.get("farmer_email") {
|
if let Some(resource_provider_email) = product.attributes.get("resource_provider_email") {
|
||||||
details["farmer_email"] = farmer_email.value.clone();
|
details["resource_provider_email"] = resource_provider_email.value.clone();
|
||||||
}
|
}
|
||||||
if let Some(cpu_cores) = product.attributes.get("cpu_cores") {
|
if let Some(cpu_cores) = product.attributes.get("cpu_cores") {
|
||||||
details["cpu_cores"] = cpu_cores.value.clone();
|
details["cpu_cores"] = cpu_cores.value.clone();
|
||||||
|
@@ -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
|
//! Follows the established builder pattern for consistent API design
|
||||||
|
|
||||||
use crate::models::user::{FarmNode, NodeCapacity, NodeStatus, EarningsRecord, NodeGroup, GroupStatistics, MarketplaceSLA};
|
use crate::models::user::{FarmNode, NodeCapacity, NodeStatus, EarningsRecord, NodeGroup, GroupStatistics, MarketplaceSLA};
|
||||||
@@ -12,7 +12,7 @@ use std::str::FromStr;
|
|||||||
use chrono::{Utc, DateTime};
|
use chrono::{Utc, DateTime};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
/// Staking statistics for a farmer
|
/// Staking statistics for a resource_provider
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct StakingStatistics {
|
pub struct StakingStatistics {
|
||||||
pub total_staked_amount: Decimal,
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct FarmerService {
|
pub struct ResourceProviderService {
|
||||||
auto_sync_enabled: bool,
|
auto_sync_enabled: bool,
|
||||||
metrics_collection: bool,
|
metrics_collection: bool,
|
||||||
grid_service: GridService,
|
grid_service: GridService,
|
||||||
slice_calculator: SliceCalculatorService,
|
slice_calculator: SliceCalculatorService,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder for FarmerService
|
/// Builder for ResourceProviderService
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FarmerServiceBuilder {
|
pub struct ResourceProviderServiceBuilder {
|
||||||
auto_sync_enabled: Option<bool>,
|
auto_sync_enabled: Option<bool>,
|
||||||
metrics_collection: Option<bool>,
|
metrics_collection: Option<bool>,
|
||||||
grid_service: Option<GridService>,
|
grid_service: Option<GridService>,
|
||||||
slice_calculator: Option<SliceCalculatorService>,
|
slice_calculator: Option<SliceCalculatorService>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FarmerServiceBuilder {
|
impl ResourceProviderServiceBuilder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ impl FarmerServiceBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Result<FarmerService, String> {
|
pub fn build(self) -> Result<ResourceProviderService, String> {
|
||||||
let grid_service = self.grid_service.unwrap_or_else(|| {
|
let grid_service = self.grid_service.unwrap_or_else(|| {
|
||||||
GridService::builder().build().expect("Failed to create default GridService")
|
GridService::builder().build().expect("Failed to create default GridService")
|
||||||
});
|
});
|
||||||
@@ -82,7 +82,7 @@ impl FarmerServiceBuilder {
|
|||||||
SliceCalculatorService::builder().build().expect("Failed to create default SliceCalculatorService")
|
SliceCalculatorService::builder().build().expect("Failed to create default SliceCalculatorService")
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(FarmerService {
|
Ok(ResourceProviderService {
|
||||||
auto_sync_enabled: self.auto_sync_enabled.unwrap_or(true),
|
auto_sync_enabled: self.auto_sync_enabled.unwrap_or(true),
|
||||||
metrics_collection: self.metrics_collection.unwrap_or(true),
|
metrics_collection: self.metrics_collection.unwrap_or(true),
|
||||||
grid_service,
|
grid_service,
|
||||||
@@ -91,13 +91,13 @@ impl FarmerServiceBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FarmerService {
|
impl ResourceProviderService {
|
||||||
pub fn builder() -> FarmerServiceBuilder {
|
pub fn builder() -> ResourceProviderServiceBuilder {
|
||||||
FarmerServiceBuilder::new()
|
ResourceProviderServiceBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all nodes for a farmer
|
/// Get all nodes for a resource_provider
|
||||||
pub fn get_farmer_nodes(&self, user_email: &str) -> Vec<FarmNode> {
|
pub fn get_resource_provider_nodes(&self, user_email: &str) -> Vec<FarmNode> {
|
||||||
if let Some(data) = UserPersistence::load_user_data(user_email) {
|
if let Some(data) = UserPersistence::load_user_data(user_email) {
|
||||||
// Debug: Log marketplace SLA data for all nodes
|
// Debug: Log marketplace SLA data for all nodes
|
||||||
for node in &data.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> {
|
pub fn add_node(&self, user_email: &str, node_data: NodeCreationData) -> Result<FarmNode, String> {
|
||||||
// Check for duplicate node names first
|
// 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) {
|
if existing_nodes.iter().any(|n| n.name == node_data.name) {
|
||||||
return Err(format!("Node '{}' is already registered", 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())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
// Auto-generate marketplace products if rental options are configured
|
// 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)
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,10 +434,10 @@ impl FarmerService {
|
|||||||
|
|
||||||
/// Sync node capacity and slices with grid data
|
/// Sync node capacity and slices with grid data
|
||||||
pub async fn sync_node_with_grid(&self, user_email: &str, node_id: &str) -> Result<(), String> {
|
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)
|
let mut resource_provider_data = UserPersistence::load_user_data(user_email)
|
||||||
.ok_or("Farmer data not found")?;
|
.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 {
|
if let Some(grid_node_id) = &node.grid_node_id {
|
||||||
// Fetch latest capacity from grid
|
// Fetch latest capacity from grid
|
||||||
let grid_id: u32 = grid_node_id.parse().unwrap_or(0);
|
let grid_id: u32 = grid_node_id.parse().unwrap_or(0);
|
||||||
@@ -472,7 +472,7 @@ impl FarmerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save updated data
|
// 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))?;
|
.map_err(|e| format!("Failed to save user data: {}", e))?;
|
||||||
} else {
|
} else {
|
||||||
return Err("Node is not linked to grid".to_string());
|
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
|
/// Auto-generate marketplace products for a node based on rental options
|
||||||
/// Products are now managed through persistent user data and aggregated by ProductService
|
/// 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
|
// Product generation is now handled through persistent user data
|
||||||
// ProductService automatically aggregates products from user-owned data
|
// ProductService automatically aggregates products from user-owned data
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -754,7 +754,7 @@ impl FarmerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a slice product from a node and slice format
|
/// 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
|
// Get slice format details and default pricing
|
||||||
let (cpu_cores, memory_gb, storage_gb, bandwidth_mbps, default_price) = match slice_format_id {
|
let (cpu_cores, memory_gb, storage_gb, bandwidth_mbps, default_price) = match slice_format_id {
|
||||||
"basic" => (2, 4, 100, 100, 25),
|
"basic" => (2, 4, 100, 100, 25),
|
||||||
@@ -789,8 +789,8 @@ impl FarmerService {
|
|||||||
base_price: price,
|
base_price: price,
|
||||||
base_currency: "USD".to_string(),
|
base_currency: "USD".to_string(),
|
||||||
attributes: std::collections::HashMap::new(),
|
attributes: std::collections::HashMap::new(),
|
||||||
provider_id: farmer_email.to_string(),
|
provider_id: resource_provider_email.to_string(),
|
||||||
provider_name: farmer_name.to_string(),
|
provider_name: resource_provider_name.to_string(),
|
||||||
availability: match node.availability_status {
|
availability: match node.availability_status {
|
||||||
crate::models::user::NodeAvailabilityStatus::Available => crate::models::product::ProductAvailability::Available,
|
crate::models::user::NodeAvailabilityStatus::Available => crate::models::product::ProductAvailability::Available,
|
||||||
crate::models::user::NodeAvailabilityStatus::PartiallyRented => crate::models::product::ProductAvailability::Limited,
|
crate::models::user::NodeAvailabilityStatus::PartiallyRented => crate::models::product::ProductAvailability::Limited,
|
||||||
@@ -880,19 +880,19 @@ impl FarmerService {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get farmer earnings
|
/// Get resource_provider earnings
|
||||||
pub fn get_farmer_earnings(&self, user_email: &str) -> Vec<EarningsRecord> {
|
pub fn get_resource_provider_earnings(&self, user_email: &str) -> Vec<EarningsRecord> {
|
||||||
if let Some(data) = UserPersistence::load_user_data(user_email) {
|
if let Some(data) = UserPersistence::load_user_data(user_email) {
|
||||||
data.farmer_earnings
|
data.resource_provider_earnings
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get farmer statistics
|
/// Get resource_provider statistics
|
||||||
pub fn get_farmer_statistics(&self, user_email: &str) -> FarmerStatistics {
|
pub fn get_resource_provider_statistics(&self, user_email: &str) -> FarmerStatistics {
|
||||||
let nodes = self.get_farmer_nodes(user_email);
|
let nodes = self.get_resource_provider_nodes(user_email);
|
||||||
let earnings = self.get_farmer_earnings(user_email);
|
let earnings = self.get_resource_provider_earnings(user_email);
|
||||||
|
|
||||||
let total_nodes = nodes.len() as i32;
|
let total_nodes = nodes.len() as i32;
|
||||||
let online_nodes = nodes.iter()
|
let online_nodes = nodes.iter()
|
||||||
@@ -990,7 +990,7 @@ impl FarmerService {
|
|||||||
slice_config.bandwidth_mbps <= available_bandwidth)
|
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> {
|
pub fn get_default_slice_formats(&self) -> Vec<DefaultSliceFormat> {
|
||||||
vec![
|
vec![
|
||||||
DefaultSliceFormat {
|
DefaultSliceFormat {
|
||||||
@@ -1039,8 +1039,8 @@ impl FarmerService {
|
|||||||
|
|
||||||
// Load user customizations from persistent data
|
// Load user customizations from persistent data
|
||||||
if let Some(persistent_data) = UserPersistence::load_user_data(user_email) {
|
if let Some(persistent_data) = UserPersistence::load_user_data(user_email) {
|
||||||
if let Some(farmer_settings) = persistent_data.farmer_settings {
|
if let Some(resource_provider_settings) = persistent_data.resource_provider_settings {
|
||||||
if let Some(customizations) = farmer_settings.default_slice_customizations {
|
if let Some(customizations) = resource_provider_settings.default_slice_customizations {
|
||||||
if let Some(custom_format) = customizations.get(format_id) {
|
if let Some(custom_format) = customizations.get(format_id) {
|
||||||
// Apply user customizations
|
// Apply user customizations
|
||||||
if let Some(cpu_cores) = custom_format.get("cpu_cores").and_then(|v| v.as_u64()).map(|v| v as u32) {
|
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> {
|
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);
|
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
||||||
|
|
||||||
// Initialize farmer settings if needed
|
// Initialize resource_provider settings if needed
|
||||||
if persistent_data.farmer_settings.is_none() {
|
if persistent_data.resource_provider_settings.is_none() {
|
||||||
persistent_data.farmer_settings = Some(crate::models::user::FarmerSettings {
|
persistent_data.resource_provider_settings = Some(crate::models::user::FarmerSettings {
|
||||||
auto_accept_reserved_slices: true,
|
auto_accept_reserved_slices: true,
|
||||||
maintenance_window: "02:00-04:00 UTC".to_string(),
|
maintenance_window: "02:00-04:00 UTC".to_string(),
|
||||||
notification_email: None,
|
notification_email: None,
|
||||||
@@ -1096,12 +1096,12 @@ impl FarmerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize default slice customizations if needed
|
// Initialize default slice customizations if needed
|
||||||
if let Some(ref mut farmer_settings) = persistent_data.farmer_settings {
|
if let Some(ref mut resource_provider_settings) = persistent_data.resource_provider_settings {
|
||||||
if farmer_settings.default_slice_customizations.is_none() {
|
if resource_provider_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());
|
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() {
|
if let Some(obj) = customizations.as_object_mut() {
|
||||||
obj.insert(format_id.to_string(), serde_json::to_value(customization).unwrap_or_default());
|
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
|
/// 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> {
|
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
|
// 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())) {
|
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));
|
return Err(format!("Node {} is already registered", grid_node_id));
|
||||||
}
|
}
|
||||||
@@ -1845,8 +1845,8 @@ impl FarmerService {
|
|||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
if slice_rental_enabled || full_node_rental_enabled {
|
if slice_rental_enabled || full_node_rental_enabled {
|
||||||
let farmer_name = persistent_data.name.unwrap_or_else(|| "Unknown Farmer".to_string());
|
let resource_provider_name = persistent_data.name.unwrap_or_else(|| "Unknown ResourceProvider".to_string());
|
||||||
self.auto_generate_marketplace_products(&node, user_email, &farmer_name, None)?;
|
self.auto_generate_marketplace_products(&node, user_email, &resource_provider_name, None)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(node)
|
Ok(node)
|
||||||
@@ -1856,7 +1856,7 @@ impl FarmerService {
|
|||||||
// NODE GROUP MANAGEMENT
|
// 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> {
|
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);
|
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
||||||
|
|
||||||
@@ -1898,7 +1898,7 @@ impl FarmerService {
|
|||||||
Ok(group)
|
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> {
|
pub fn get_node_groups(&self, user_email: &str) -> Vec<NodeGroup> {
|
||||||
// Ensure default groups exist first
|
// Ensure default groups exist first
|
||||||
if let Err(e) = self.ensure_default_node_groups(user_email) {
|
if let Err(e) = self.ensure_default_node_groups(user_email) {
|
||||||
@@ -2165,7 +2165,7 @@ impl FarmerService {
|
|||||||
|
|
||||||
/// Get node by name (for duplicate checking)
|
/// Get node by name (for duplicate checking)
|
||||||
pub fn get_node_by_name(&self, user_email: &str, node_name: &str) -> Option<FarmNode> {
|
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)
|
nodes.into_iter().find(|n| n.name == node_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2278,12 +2278,12 @@ impl FarmerService {
|
|||||||
Ok(())
|
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 {
|
fn create_default_user_data(user_email: &str) -> UserPersistentData {
|
||||||
crate::models::builders::SessionDataBuilder::new_user(user_email)
|
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> {
|
pub fn refresh_all_slice_calculations(&self, user_email: &str) -> Result<(), String> {
|
||||||
let mut persistent_data = UserPersistence::load_user_data(user_email)
|
let mut persistent_data = UserPersistence::load_user_data(user_email)
|
||||||
.ok_or("User data not found")?;
|
.ok_or("User data not found")?;
|
||||||
@@ -2395,7 +2395,7 @@ impl FarmerService {
|
|||||||
Ok(slices)
|
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> {
|
pub fn get_slice_statistics(&self, user_email: &str) -> Result<serde_json::Value, String> {
|
||||||
let persistent_data = UserPersistence::load_user_data(user_email)
|
let persistent_data = UserPersistence::load_user_data(user_email)
|
||||||
.ok_or("User data not found")?;
|
.ok_or("User data not found")?;
|
||||||
@@ -2821,7 +2821,7 @@ impl FarmerService {
|
|||||||
Ok(repaired_count)
|
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> {
|
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)
|
let mut persistent_data = UserPersistence::load_user_data(user_email)
|
||||||
.ok_or("User data not found")?;
|
.ok_or("User data not found")?;
|
||||||
@@ -2971,7 +2971,7 @@ pub struct NodeUpdateData {
|
|||||||
pub marketplace_sla: Option<MarketplaceSLA>,
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct DefaultSliceFormat {
|
pub struct DefaultSliceFormat {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@@ -2984,7 +2984,7 @@ pub struct DefaultSliceFormat {
|
|||||||
pub price_per_hour: rust_decimal::Decimal,
|
pub price_per_hour: rust_decimal::Decimal,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Farmer statistics summary
|
/// ResourceProvider statistics summary
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct FarmerStatistics {
|
pub struct FarmerStatistics {
|
||||||
pub total_nodes: i32,
|
pub total_nodes: i32,
|
@@ -18,7 +18,7 @@ pub struct SliceAssignmentService {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct SliceAssignmentRequest {
|
pub struct SliceAssignmentRequest {
|
||||||
pub user_email: String,
|
pub user_email: String,
|
||||||
pub farmer_email: String,
|
pub resource_provider_email: String,
|
||||||
pub node_id: String,
|
pub node_id: String,
|
||||||
pub combination_id: String,
|
pub combination_id: String,
|
||||||
pub quantity: u32,
|
pub quantity: u32,
|
||||||
@@ -127,7 +127,7 @@ pub struct SecurityConfiguration {
|
|||||||
pub struct SliceAssignment {
|
pub struct SliceAssignment {
|
||||||
pub assignment_id: String,
|
pub assignment_id: String,
|
||||||
pub user_email: String,
|
pub user_email: String,
|
||||||
pub farmer_email: String,
|
pub resource_provider_email: String,
|
||||||
pub node_id: String,
|
pub node_id: String,
|
||||||
pub combination_id: String,
|
pub combination_id: String,
|
||||||
pub slice_allocations: Vec<SliceAllocation>,
|
pub slice_allocations: Vec<SliceAllocation>,
|
||||||
@@ -241,7 +241,7 @@ impl SliceAssignmentService {
|
|||||||
let assignment = SliceAssignment {
|
let assignment = SliceAssignment {
|
||||||
assignment_id,
|
assignment_id,
|
||||||
user_email: request.user_email,
|
user_email: request.user_email,
|
||||||
farmer_email: request.farmer_email,
|
resource_provider_email: request.resource_provider_email,
|
||||||
node_id: request.node_id,
|
node_id: request.node_id,
|
||||||
combination_id: request.combination_id,
|
combination_id: request.combination_id,
|
||||||
slice_allocations,
|
slice_allocations,
|
||||||
@@ -377,7 +377,7 @@ impl SliceAssignmentService {
|
|||||||
"status": "deploying",
|
"status": "deploying",
|
||||||
"deployment_type": "vm",
|
"deployment_type": "vm",
|
||||||
"node_id": assignment.node_id,
|
"node_id": assignment.node_id,
|
||||||
"farmer_email": assignment.farmer_email,
|
"resource_provider_email": assignment.resource_provider_email,
|
||||||
"started_at": Utc::now(),
|
"started_at": Utc::now(),
|
||||||
"estimated_completion": Utc::now() + chrono::Duration::minutes(5)
|
"estimated_completion": Utc::now() + chrono::Duration::minutes(5)
|
||||||
});
|
});
|
||||||
|
@@ -42,7 +42,7 @@ pub struct SliceCombination {
|
|||||||
pub node_location: String,
|
pub node_location: String,
|
||||||
pub node_certification_type: String,
|
pub node_certification_type: String,
|
||||||
pub node_id: String,
|
pub node_id: String,
|
||||||
pub farmer_email: String,
|
pub resource_provider_email: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Track individual slice rentals
|
/// Track individual slice rentals
|
||||||
@@ -70,7 +70,7 @@ pub enum AllocationStatus {
|
|||||||
pub struct SlicePricing {
|
pub struct SlicePricing {
|
||||||
pub base_price_per_hour: Decimal, // Price for 1 base slice per hour
|
pub base_price_per_hour: Decimal, // Price for 1 base slice per hour
|
||||||
pub currency: String,
|
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 {
|
impl Default for SlicePricing {
|
||||||
@@ -157,7 +157,7 @@ impl SliceCalculatorService {
|
|||||||
max_base_slices: u32,
|
max_base_slices: u32,
|
||||||
allocated_slices: u32,
|
allocated_slices: u32,
|
||||||
node: &FarmNode,
|
node: &FarmNode,
|
||||||
farmer_email: &str
|
resource_provider_email: &str
|
||||||
) -> Vec<SliceCombination> {
|
) -> Vec<SliceCombination> {
|
||||||
let available_base_slices = max_base_slices.saturating_sub(allocated_slices);
|
let available_base_slices = max_base_slices.saturating_sub(allocated_slices);
|
||||||
let mut combinations = Vec::new();
|
let mut combinations = Vec::new();
|
||||||
@@ -208,7 +208,7 @@ impl SliceCalculatorService {
|
|||||||
.to_string())
|
.to_string())
|
||||||
.unwrap_or_else(|| "DIY".to_string()),
|
.unwrap_or_else(|| "DIY".to_string()),
|
||||||
node_id: node.id.clone(),
|
node_id: node.id.clone(),
|
||||||
farmer_email: farmer_email.to_string(),
|
resource_provider_email: resource_provider_email.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
combinations.push(combination);
|
combinations.push(combination);
|
||||||
@@ -225,7 +225,7 @@ impl SliceCalculatorService {
|
|||||||
max_base_slices: u32,
|
max_base_slices: u32,
|
||||||
allocated_slices: u32,
|
allocated_slices: u32,
|
||||||
node: &FarmNode,
|
node: &FarmNode,
|
||||||
farmer_email: &str,
|
resource_provider_email: &str,
|
||||||
uptime_percentage: f64,
|
uptime_percentage: f64,
|
||||||
bandwidth_mbps: u32,
|
bandwidth_mbps: u32,
|
||||||
base_price_per_hour: Decimal
|
base_price_per_hour: Decimal
|
||||||
@@ -283,7 +283,7 @@ impl SliceCalculatorService {
|
|||||||
.to_string())
|
.to_string())
|
||||||
.unwrap_or_else(|| "DIY".to_string()),
|
.unwrap_or_else(|| "DIY".to_string()),
|
||||||
node_id: node.id.clone(),
|
node_id: node.id.clone(),
|
||||||
farmer_email: farmer_email.to_string(),
|
resource_provider_email: resource_provider_email.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
combinations.push(combination);
|
combinations.push(combination);
|
||||||
@@ -304,7 +304,7 @@ impl SliceCalculatorService {
|
|||||||
&self,
|
&self,
|
||||||
node: &mut FarmNode,
|
node: &mut FarmNode,
|
||||||
rented_base_slices: u32,
|
rented_base_slices: u32,
|
||||||
farmer_email: &str
|
resource_provider_email: &str
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
// Update allocated count
|
// Update allocated count
|
||||||
node.allocated_base_slices += rented_base_slices as i32;
|
node.allocated_base_slices += rented_base_slices as i32;
|
||||||
@@ -314,7 +314,7 @@ impl SliceCalculatorService {
|
|||||||
node.total_base_slices as u32,
|
node.total_base_slices as u32,
|
||||||
node.allocated_base_slices as u32,
|
node.allocated_base_slices as u32,
|
||||||
node,
|
node,
|
||||||
farmer_email
|
resource_provider_email
|
||||||
);
|
);
|
||||||
node.available_combinations = combinations.iter()
|
node.available_combinations = combinations.iter()
|
||||||
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||||
@@ -328,7 +328,7 @@ impl SliceCalculatorService {
|
|||||||
&self,
|
&self,
|
||||||
node: &mut FarmNode,
|
node: &mut FarmNode,
|
||||||
released_base_slices: u32,
|
released_base_slices: u32,
|
||||||
farmer_email: &str
|
resource_provider_email: &str
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
// Update allocated count
|
// Update allocated count
|
||||||
node.allocated_base_slices = node.allocated_base_slices.saturating_sub(released_base_slices as i32);
|
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.total_base_slices as u32,
|
||||||
node.allocated_base_slices as u32,
|
node.allocated_base_slices as u32,
|
||||||
node,
|
node,
|
||||||
farmer_email
|
resource_provider_email
|
||||||
).iter()
|
).iter()
|
||||||
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||||
.collect();
|
.collect();
|
||||||
@@ -364,7 +364,7 @@ pub struct SliceRental {
|
|||||||
pub rental_id: String,
|
pub rental_id: String,
|
||||||
pub slice_combination_id: String,
|
pub slice_combination_id: String,
|
||||||
pub node_id: String,
|
pub node_id: String,
|
||||||
pub farmer_email: String,
|
pub resource_provider_email: String,
|
||||||
pub slice_allocation: SliceAllocation,
|
pub slice_allocation: SliceAllocation,
|
||||||
pub total_cost: Decimal,
|
pub total_cost: Decimal,
|
||||||
pub payment_status: PaymentStatus,
|
pub payment_status: PaymentStatus,
|
||||||
|
@@ -56,11 +56,11 @@ impl SliceRentalService {
|
|||||||
SliceRentalServiceBuilder::new()
|
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(
|
pub fn rent_slice_combination(
|
||||||
&self,
|
&self,
|
||||||
renter_email: &str,
|
renter_email: &str,
|
||||||
farmer_email: &str,
|
resource_provider_email: &str,
|
||||||
node_id: &str,
|
node_id: &str,
|
||||||
combination_id: &str,
|
combination_id: &str,
|
||||||
quantity: u32,
|
quantity: u32,
|
||||||
@@ -68,9 +68,9 @@ impl SliceRentalService {
|
|||||||
) -> Result<SliceRental, String> {
|
) -> Result<SliceRental, String> {
|
||||||
// Atomic operation with file locking to prevent conflicts
|
// Atomic operation with file locking to prevent conflicts
|
||||||
if self.enable_file_locking {
|
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 {
|
} 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(
|
pub fn rent_slice_combination_with_deployment(
|
||||||
&self,
|
&self,
|
||||||
renter_email: &str,
|
renter_email: &str,
|
||||||
farmer_email: &str,
|
resource_provider_email: &str,
|
||||||
node_id: &str,
|
node_id: &str,
|
||||||
combination_id: &str,
|
combination_id: &str,
|
||||||
quantity: u32,
|
quantity: u32,
|
||||||
@@ -89,7 +89,7 @@ impl SliceRentalService {
|
|||||||
) -> Result<SliceRental, String> {
|
) -> Result<SliceRental, String> {
|
||||||
// First rent the slice combination
|
// First rent the slice combination
|
||||||
let mut rental = self.rent_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
|
// Add deployment metadata to the rental
|
||||||
@@ -133,21 +133,21 @@ impl SliceRentalService {
|
|||||||
fn rent_with_file_lock(
|
fn rent_with_file_lock(
|
||||||
&self,
|
&self,
|
||||||
renter_email: &str,
|
renter_email: &str,
|
||||||
farmer_email: &str,
|
resource_provider_email: &str,
|
||||||
node_id: &str,
|
node_id: &str,
|
||||||
combination_id: &str,
|
combination_id: &str,
|
||||||
quantity: u32,
|
quantity: u32,
|
||||||
rental_duration_hours: u32,
|
rental_duration_hours: u32,
|
||||||
) -> Result<SliceRental, String> {
|
) -> Result<SliceRental, String> {
|
||||||
// Create lock file
|
// 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()
|
let _lock_file = OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(&lock_file_path)
|
.open(&lock_file_path)
|
||||||
.map_err(|e| format!("Failed to create lock file: {}", e))?;
|
.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
|
// Clean up lock file
|
||||||
let _ = std::fs::remove_file(&lock_file_path);
|
let _ = std::fs::remove_file(&lock_file_path);
|
||||||
@@ -159,21 +159,21 @@ impl SliceRentalService {
|
|||||||
fn rent_without_lock(
|
fn rent_without_lock(
|
||||||
&self,
|
&self,
|
||||||
renter_email: &str,
|
renter_email: &str,
|
||||||
farmer_email: &str,
|
resource_provider_email: &str,
|
||||||
node_id: &str,
|
node_id: &str,
|
||||||
combination_id: &str,
|
combination_id: &str,
|
||||||
quantity: u32,
|
quantity: u32,
|
||||||
rental_duration_hours: u32,
|
rental_duration_hours: u32,
|
||||||
) -> Result<SliceRental, String> {
|
) -> Result<SliceRental, String> {
|
||||||
// Load farmer data
|
// Load resource_provider data
|
||||||
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
|
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
|
||||||
.ok_or_else(|| "Farmer not found".to_string())?;
|
.ok_or_else(|| "ResourceProvider not found".to_string())?;
|
||||||
|
|
||||||
// Find the node
|
// 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())?;
|
.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
|
// Find the slice combination
|
||||||
let combination = node.available_combinations.iter()
|
let combination = node.available_combinations.iter()
|
||||||
@@ -226,7 +226,7 @@ impl SliceRentalService {
|
|||||||
self.slice_calculator.update_availability_after_rental(
|
self.slice_calculator.update_availability_after_rental(
|
||||||
node,
|
node,
|
||||||
total_base_slices_needed,
|
total_base_slices_needed,
|
||||||
farmer_email
|
resource_provider_email
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Add allocation to node
|
// Add allocation to node
|
||||||
@@ -237,7 +237,7 @@ impl SliceRentalService {
|
|||||||
rental_id: rental_id.clone(),
|
rental_id: rental_id.clone(),
|
||||||
slice_combination_id: combination_id.to_string(),
|
slice_combination_id: combination_id.to_string(),
|
||||||
node_id: node_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,
|
slice_allocation: allocation,
|
||||||
total_cost,
|
total_cost,
|
||||||
payment_status: PaymentStatus::Paid,
|
payment_status: PaymentStatus::Paid,
|
||||||
@@ -260,12 +260,12 @@ impl SliceRentalService {
|
|||||||
renter_data.wallet_balance_usd -= total_cost;
|
renter_data.wallet_balance_usd -= total_cost;
|
||||||
renter_data.slice_rentals.push(slice_rental.clone());
|
renter_data.slice_rentals.push(slice_rental.clone());
|
||||||
|
|
||||||
// Add earnings to farmer
|
// Add earnings to resource_provider
|
||||||
farmer_data.wallet_balance_usd += total_cost;
|
resource_provider_data.wallet_balance_usd += total_cost;
|
||||||
|
|
||||||
// Save both user data
|
// Save both user data
|
||||||
UserPersistence::save_user_data(&farmer_data)
|
UserPersistence::save_user_data(&resource_provider_data)
|
||||||
.map_err(|e| format!("Failed to save farmer data: {}", e))?;
|
.map_err(|e| format!("Failed to save resource_provider data: {}", e))?;
|
||||||
UserPersistence::save_user_data(&renter_data)
|
UserPersistence::save_user_data(&renter_data)
|
||||||
.map_err(|e| format!("Failed to save renter data: {}", e))?;
|
.map_err(|e| format!("Failed to save renter data: {}", e))?;
|
||||||
|
|
||||||
@@ -273,14 +273,14 @@ impl SliceRentalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Release expired slice rentals
|
/// Release expired slice rentals
|
||||||
pub fn release_expired_rentals(&self, farmer_email: &str) -> Result<u32, String> {
|
pub fn release_expired_rentals(&self, resource_provider_email: &str) -> Result<u32, String> {
|
||||||
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
|
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
|
||||||
.ok_or_else(|| "Farmer not found".to_string())?;
|
.ok_or_else(|| "ResourceProvider not found".to_string())?;
|
||||||
|
|
||||||
let mut released_count = 0;
|
let mut released_count = 0;
|
||||||
let now = Utc::now();
|
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();
|
let mut expired_allocations = Vec::new();
|
||||||
|
|
||||||
// Find expired allocations
|
// Find expired allocations
|
||||||
@@ -314,7 +314,7 @@ impl SliceRentalService {
|
|||||||
self.slice_calculator.update_availability_after_release(
|
self.slice_calculator.update_availability_after_release(
|
||||||
node,
|
node,
|
||||||
base_slices_used,
|
base_slices_used,
|
||||||
farmer_email
|
resource_provider_email
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
released_count += 1;
|
released_count += 1;
|
||||||
@@ -322,20 +322,20 @@ impl SliceRentalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if released_count > 0 {
|
if released_count > 0 {
|
||||||
UserPersistence::save_user_data(&farmer_data)
|
UserPersistence::save_user_data(&resource_provider_data)
|
||||||
.map_err(|e| format!("Failed to save farmer data: {}", e))?;
|
.map_err(|e| format!("Failed to save resource_provider data: {}", e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(released_count)
|
Ok(released_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Get slice rental statistics for a farmer
|
/// Get slice rental statistics for a resource_provider
|
||||||
pub fn get_farmer_slice_statistics(&self, farmer_email: &str) -> SliceRentalStatistics {
|
pub fn get_resource_provider_slice_statistics(&self, resource_provider_email: &str) -> SliceRentalStatistics {
|
||||||
if let Some(farmer_data) = UserPersistence::load_user_data(farmer_email) {
|
if let Some(resource_provider_data) = UserPersistence::load_user_data(resource_provider_email) {
|
||||||
let mut stats = SliceRentalStatistics::default();
|
let mut stats = SliceRentalStatistics::default();
|
||||||
|
|
||||||
for node in &farmer_data.nodes {
|
for node in &resource_provider_data.nodes {
|
||||||
stats.total_nodes += 1;
|
stats.total_nodes += 1;
|
||||||
stats.total_base_slices += node.total_base_slices as u32;
|
stats.total_base_slices += node.total_base_slices as u32;
|
||||||
stats.allocated_base_slices += node.allocated_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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
pub struct SliceRentalStatistics {
|
pub struct SliceRentalStatistics {
|
||||||
pub total_nodes: u32,
|
pub total_nodes: u32,
|
||||||
|
@@ -46,10 +46,10 @@ pub struct UserPersistentData {
|
|||||||
pub deleted: Option<bool>,
|
pub deleted: Option<bool>,
|
||||||
pub deleted_at: Option<String>,
|
pub deleted_at: Option<String>,
|
||||||
pub deletion_reason: Option<String>,
|
pub deletion_reason: Option<String>,
|
||||||
// Farmer-specific data
|
// ResourceProvider-specific data
|
||||||
pub nodes: Vec<crate::models::user::FarmNode>,
|
pub nodes: Vec<crate::models::user::FarmNode>,
|
||||||
pub farmer_earnings: Vec<crate::models::user::EarningsRecord>,
|
pub resource_provider_earnings: Vec<crate::models::user::EarningsRecord>,
|
||||||
pub farmer_settings: Option<crate::models::user::FarmerSettings>,
|
pub resource_provider_settings: Option<crate::models::user::FarmerSettings>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub slice_products: Vec<crate::models::product::Product>,
|
pub slice_products: Vec<crate::models::product::Product>,
|
||||||
// User activity tracking
|
// User activity tracking
|
||||||
@@ -63,10 +63,10 @@ pub struct UserPersistentData {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub active_product_rentals: Vec<ProductRental>,
|
pub active_product_rentals: Vec<ProductRental>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub farmer_rental_earnings: Vec<crate::models::user::FarmerRentalEarning>,
|
pub resource_provider_rental_earnings: Vec<crate::models::user::FarmerRentalEarning>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub node_rentals: Vec<crate::models::user::NodeRental>,
|
pub node_rentals: Vec<crate::models::user::NodeRental>,
|
||||||
// Node groups for farmer organization
|
// Node groups for resource_provider organization
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub node_groups: Vec<crate::models::user::NodeGroup>,
|
pub node_groups: Vec<crate::models::user::NodeGroup>,
|
||||||
// NEW: Slice rental tracking for users
|
// NEW: Slice rental tracking for users
|
||||||
@@ -142,15 +142,15 @@ impl Default for UserPersistentData {
|
|||||||
deleted_at: None,
|
deleted_at: None,
|
||||||
deletion_reason: None,
|
deletion_reason: None,
|
||||||
nodes: Vec::new(),
|
nodes: Vec::new(),
|
||||||
farmer_earnings: Vec::new(),
|
resource_provider_earnings: Vec::new(),
|
||||||
farmer_settings: None,
|
resource_provider_settings: None,
|
||||||
slice_products: Vec::new(),
|
slice_products: Vec::new(),
|
||||||
user_activities: Vec::new(),
|
user_activities: Vec::new(),
|
||||||
user_preferences: None,
|
user_preferences: None,
|
||||||
usage_statistics: None,
|
usage_statistics: None,
|
||||||
orders: Vec::new(),
|
orders: Vec::new(),
|
||||||
active_product_rentals: Vec::new(),
|
active_product_rentals: Vec::new(),
|
||||||
farmer_rental_earnings: Vec::new(),
|
resource_provider_rental_earnings: Vec::new(),
|
||||||
node_rentals: Vec::new(),
|
node_rentals: Vec::new(),
|
||||||
node_groups: Vec::new(),
|
node_groups: Vec::new(),
|
||||||
slice_rentals: Vec::new(),
|
slice_rentals: Vec::new(),
|
||||||
@@ -1306,19 +1306,19 @@ impl UserPersistence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get farmer earnings for a user
|
/// Get resource_provider earnings for a user
|
||||||
pub fn get_farmer_earnings(user_email: &str) -> Vec<crate::models::user::EarningsRecord> {
|
pub fn get_resource_provider_earnings(user_email: &str) -> Vec<crate::models::user::EarningsRecord> {
|
||||||
if let Some(data) = Self::load_user_data(user_email) {
|
if let Some(data) = Self::load_user_data(user_email) {
|
||||||
data.farmer_earnings
|
data.resource_provider_earnings
|
||||||
} else {
|
} else {
|
||||||
Vec::default()
|
Vec::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get farmer settings for a user
|
/// Get resource_provider settings for a user
|
||||||
pub fn get_farmer_settings(user_email: &str) -> Option<crate::models::user::FarmerSettings> {
|
pub fn get_resource_provider_settings(user_email: &str) -> Option<crate::models::user::FarmerSettings> {
|
||||||
if let Some(data) = Self::load_user_data(user_email) {
|
if let Some(data) = Self::load_user_data(user_email) {
|
||||||
data.farmer_settings
|
data.resource_provider_settings
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
// Dashboard Farmer JavaScript
|
// Dashboard ResourceProvider JavaScript
|
||||||
// Handles farmer dashboard functionality including automatic slice management, grid integration, and node management
|
// Handles resource_provider dashboard functionality including automatic slice management, grid integration, and node management
|
||||||
|
|
||||||
if (window.farmerDashboardInitialized) {
|
if (window.resourceProviderDashboardInitialized) {
|
||||||
console.debug('Farmer dashboard already initialized; skipping');
|
console.debug('ResourceProvider dashboard already initialized; skipping');
|
||||||
} else {
|
} else {
|
||||||
window.farmerDashboardInitialized = true;
|
window.resourceProviderDashboardInitialized = true;
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
console.log('🚜 Farmer Dashboard JavaScript loaded - Automatic Slice System');
|
console.log('🚜 ResourceProvider Dashboard JavaScript loaded - Automatic Slice System');
|
||||||
|
|
||||||
// Initialize dashboard
|
// Initialize dashboard
|
||||||
initializeFarmerDashboard();
|
initializeFarmerDashboard();
|
||||||
@@ -762,7 +762,7 @@ function showNodeDetailsModal(node) {
|
|||||||
function loadSliceStatistics() {
|
function loadSliceStatistics() {
|
||||||
console.log('📊 Loading slice statistics');
|
console.log('📊 Loading slice statistics');
|
||||||
|
|
||||||
window.apiJson('/api/dashboard/farmer/slice-statistics')
|
window.apiJson('/api/dashboard/resource_provider/slice-statistics')
|
||||||
.then(data => {
|
.then(data => {
|
||||||
// apiJson returns unwrapped data; support either {statistics: {...}} or {...}
|
// apiJson returns unwrapped data; support either {statistics: {...}} or {...}
|
||||||
const stats = (data && data.statistics) ? data.statistics : (data || {});
|
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() {
|
function initializeFarmerDashboard() {
|
||||||
console.log('🚜 Initializing farmer dashboard');
|
console.log('🚜 Initializing resource_provider dashboard');
|
||||||
|
|
||||||
// Load farmer data
|
// Load resource_provider data
|
||||||
loadFarmerData();
|
loadFarmerData();
|
||||||
|
|
||||||
// Load slice templates
|
// Load slice templates
|
||||||
@@ -2911,12 +2911,12 @@ function resetSliceConfigurationForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load farmer data from API
|
* Load resource_provider data from API
|
||||||
*/
|
*/
|
||||||
async function loadFarmerData() {
|
async function loadFarmerData() {
|
||||||
try {
|
try {
|
||||||
const data = await window.apiJson('/api/dashboard/farmer-data');
|
const data = await window.apiJson('/api/dashboard/resource_provider-data');
|
||||||
console.log('🚜 Loaded farmer data:', data);
|
console.log('🚜 Loaded resource_provider data:', data);
|
||||||
|
|
||||||
// Load node groups as well
|
// Load node groups as well
|
||||||
const groupsResult = await window.apiJson('/api/dashboard/node-groups');
|
const groupsResult = await window.apiJson('/api/dashboard/node-groups');
|
||||||
@@ -2924,8 +2924,8 @@ async function loadFarmerData() {
|
|||||||
data.nodeGroups = nodeGroups;
|
data.nodeGroups = nodeGroups;
|
||||||
console.log('🚜 Node groups loaded:', nodeGroups);
|
console.log('🚜 Node groups loaded:', nodeGroups);
|
||||||
|
|
||||||
// Store farmer data globally for slice status checking
|
// Store resource_provider data globally for slice status checking
|
||||||
window.farmerData = data;
|
window.resourceProviderData = data;
|
||||||
|
|
||||||
// Update dashboard stats
|
// Update dashboard stats
|
||||||
updateDashboardStats(data);
|
updateDashboardStats(data);
|
||||||
@@ -2940,8 +2940,8 @@ async function loadFarmerData() {
|
|||||||
loadSliceTemplates();
|
loadSliceTemplates();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('🚜 Error loading farmer data:', error);
|
console.error('🚜 Error loading resource_provider data:', error);
|
||||||
showNotification('Failed to load farmer 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
|
* Returns 'Active' if at least one node is using this slice format, 'Available' otherwise
|
||||||
*/
|
*/
|
||||||
function getSliceFormatStatus(sliceFormatId) {
|
function getSliceFormatStatus(sliceFormatId) {
|
||||||
// Check if we have farmer data loaded
|
// Check if we have resource_provider data loaded
|
||||||
if (!window.farmerData || !window.farmerData.nodes) {
|
if (!window.resourceProviderData || !window.resourceProviderData.nodes) {
|
||||||
return 'Available'; // Default to Available if no data
|
return 'Available'; // Default to Available if no data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if any node has this slice format in their slice_formats array
|
// 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 &&
|
return node.slice_formats &&
|
||||||
Array.isArray(node.slice_formats) &&
|
Array.isArray(node.slice_formats) &&
|
||||||
node.slice_formats.includes(sliceFormatId);
|
node.slice_formats.includes(sliceFormatId);
|
||||||
@@ -3507,8 +3507,8 @@ function updateNodesTable(nodes) {
|
|||||||
|
|
||||||
// Group info with enhanced display - get actual group name from loaded groups
|
// Group info with enhanced display - get actual group name from loaded groups
|
||||||
let groupInfo = '<span class="badge bg-secondary">Single</span>';
|
let groupInfo = '<span class="badge bg-secondary">Single</span>';
|
||||||
if (node.node_group_id && window.farmerData && window.farmerData.nodeGroups) {
|
if (node.node_group_id && window.resourceProviderData && window.resourceProviderData.nodeGroups) {
|
||||||
const group = window.farmerData.nodeGroups.find(g => g.id === node.node_group_id);
|
const group = window.resourceProviderData.nodeGroups.find(g => g.id === node.node_group_id);
|
||||||
if (group) {
|
if (group) {
|
||||||
groupInfo = `<span class="badge bg-info">${group.name}</span>`;
|
groupInfo = `<span class="badge bg-info">${group.name}</span>`;
|
||||||
}
|
}
|
||||||
@@ -3966,7 +3966,7 @@ async function addGridNodes() {
|
|||||||
// Reset form
|
// Reset form
|
||||||
resetAddNodeForm();
|
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 () => {
|
setTimeout(async () => {
|
||||||
await loadFarmerData();
|
await loadFarmerData();
|
||||||
await loadNodeGroups(); // FARMER FIX: Refresh node groups table after adding new nodes
|
await loadNodeGroups(); // FARMER FIX: Refresh node groups table after adding new nodes
|
||||||
@@ -4155,7 +4155,7 @@ async function confirmNodeDeletion() {
|
|||||||
deleteModal.hide();
|
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(() => {
|
setTimeout(() => {
|
||||||
loadFarmerData();
|
loadFarmerData();
|
||||||
loadNodeGroups(); // FARMER FIX: Refresh node groups table after node deletion
|
loadNodeGroups(); // FARMER FIX: Refresh node groups table after node deletion
|
||||||
@@ -4925,7 +4925,7 @@ async function saveNodeConfiguration() {
|
|||||||
modal.hide();
|
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 () => {
|
setTimeout(async () => {
|
||||||
await loadFarmerData();
|
await loadFarmerData();
|
||||||
await loadNodeGroups(); // FARMER FIX: Refresh node groups table after node configuration changes
|
await loadNodeGroups(); // FARMER FIX: Refresh node groups table after node configuration changes
|
||||||
@@ -5627,7 +5627,7 @@ function createSliceFormatCard(format, type) {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
} else {
|
} 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
|
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>`;
|
pricingDisplay = `<small class="text-muted">${hourlyPrice} ${currency}/hour</small>`;
|
||||||
}
|
}
|
||||||
@@ -5706,15 +5706,15 @@ function getSliceFormatDisplayName(formatId, formatName) {
|
|||||||
return formatName;
|
return formatName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up custom slice products from loaded farmer data
|
// Look up custom slice products from loaded resource_provider data
|
||||||
if (window.farmerData && window.farmerData.slice_products) {
|
if (window.resourceProviderData && window.resourceProviderData.slice_products) {
|
||||||
const sliceProduct = window.farmerData.slice_products.find(product => product.id === formatId);
|
const sliceProduct = window.resourceProviderData.slice_products.find(product => product.id === formatId);
|
||||||
if (sliceProduct && sliceProduct.name) {
|
if (sliceProduct && sliceProduct.name) {
|
||||||
return 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) {
|
if (window.loadedSliceProducts) {
|
||||||
const sliceProduct = window.loadedSliceProducts.find(product => product.id === formatId);
|
const sliceProduct = window.loadedSliceProducts.find(product => product.id === formatId);
|
||||||
if (sliceProduct && sliceProduct.name) {
|
if (sliceProduct && sliceProduct.name) {
|
||||||
@@ -7189,7 +7189,7 @@ function clearValidationError(input) {
|
|||||||
*/
|
*/
|
||||||
async function updateStakingDisplay() {
|
async function updateStakingDisplay() {
|
||||||
try {
|
try {
|
||||||
const data = await window.apiJson('/api/dashboard/farmer-data');
|
const data = await window.apiJson('/api/dashboard/resource_provider-data');
|
||||||
const nodes = data.nodes || [];
|
const nodes = data.nodes || [];
|
||||||
|
|
||||||
// Calculate staking statistics
|
// Calculate staking statistics
|
||||||
@@ -7523,7 +7523,7 @@ function showStakeNodeModal(nodeId) {
|
|||||||
console.log('🛡️ Showing stake modal for node:', nodeId);
|
console.log('🛡️ Showing stake modal for node:', nodeId);
|
||||||
|
|
||||||
// Find the node data
|
// 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) {
|
if (!node) {
|
||||||
showNotification('Node not found', 'error');
|
showNotification('Node not found', 'error');
|
||||||
return;
|
return;
|
||||||
@@ -7657,7 +7657,7 @@ async function stakeOnNode(nodeId, modal) {
|
|||||||
showNotification(`Successfully staked ${stakeAmount} TFP on node`, 'success');
|
showNotification(`Successfully staked ${stakeAmount} TFP on node`, 'success');
|
||||||
modal.hide();
|
modal.hide();
|
||||||
|
|
||||||
// Refresh farmer data to show updated staking
|
// Refresh resource_provider data to show updated staking
|
||||||
await loadFarmerData();
|
await loadFarmerData();
|
||||||
|
|
||||||
// Update wallet balance display
|
// Update wallet balance display
|
||||||
@@ -7683,7 +7683,7 @@ async function unstakeFromNode(nodeId) {
|
|||||||
console.log('🛡️ Unstaking TFP from node:', nodeId);
|
console.log('🛡️ Unstaking TFP from node:', nodeId);
|
||||||
|
|
||||||
// Find the node data
|
// 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) {
|
if (!node || !node.staking_options || !node.staking_options.staking_enabled) {
|
||||||
showNotification('Node is not currently staked', 'error');
|
showNotification('Node is not currently staked', 'error');
|
||||||
return;
|
return;
|
||||||
@@ -7712,7 +7712,7 @@ async function unstakeFromNode(nodeId) {
|
|||||||
const returnedAmount = result?.returned_amount || stakedAmount;
|
const returnedAmount = result?.returned_amount || stakedAmount;
|
||||||
showNotification(`Successfully unstaked ${returnedAmount} TFP from node`, 'success');
|
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();
|
await loadFarmerData();
|
||||||
|
|
||||||
// Update wallet balance display
|
// Update wallet balance display
|
||||||
@@ -7731,7 +7731,7 @@ function showUpdateStakeModal(nodeId) {
|
|||||||
console.log('🛡️ Showing update stake modal for node:', nodeId);
|
console.log('🛡️ Showing update stake modal for node:', nodeId);
|
||||||
|
|
||||||
// Find the node data
|
// 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) {
|
if (!node || !node.staking_options || !node.staking_options.staking_enabled) {
|
||||||
showNotification('Node is not currently staked', 'error');
|
showNotification('Node is not currently staked', 'error');
|
||||||
return;
|
return;
|
||||||
@@ -7847,7 +7847,7 @@ async function updateNodeStaking(nodeId, modal) {
|
|||||||
showNotification(`Successfully updated staking to ${newStakeAmount} TFP`, 'success');
|
showNotification(`Successfully updated staking to ${newStakeAmount} TFP`, 'success');
|
||||||
modal.hide();
|
modal.hide();
|
||||||
|
|
||||||
// Refresh farmer data to show updated staking
|
// Refresh resource_provider data to show updated staking
|
||||||
await loadFarmerData();
|
await loadFarmerData();
|
||||||
|
|
||||||
// Update wallet balance display
|
// Update wallet balance display
|
@@ -31,7 +31,7 @@ class DemoWorkflow {
|
|||||||
action: () => this.demoAppDeployment()
|
action: () => this.demoAppDeployment()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Farmer: Node Management",
|
title: "ResourceProvider: Node Management",
|
||||||
description: "Manage your farming nodes and monitor capacity.",
|
description: "Manage your farming nodes and monitor capacity.",
|
||||||
action: () => this.demoNodeManagement()
|
action: () => this.demoNodeManagement()
|
||||||
},
|
},
|
||||||
@@ -265,7 +265,7 @@ class DemoWorkflow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
demoNodeManagement() {
|
demoNodeManagement() {
|
||||||
showNotification('Demo: Simulating farmer node management...', 'info');
|
showNotification('Demo: Simulating resource_provider node management...', 'info');
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Simulate node status change
|
// Simulate node status change
|
||||||
|
@@ -431,7 +431,7 @@ class MarketplaceIntegration {
|
|||||||
|
|
||||||
if (!sessionStorage.getItem('marketplaceSlices')) {
|
if (!sessionStorage.getItem('marketplaceSlices')) {
|
||||||
// Get real users from user database
|
// 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 = [
|
const mockSlices = [
|
||||||
{
|
{
|
||||||
|
@@ -12,11 +12,11 @@ class UserDatabase {
|
|||||||
const mockUsers = [
|
const mockUsers = [
|
||||||
{
|
{
|
||||||
id: 'user-001',
|
id: 'user-001',
|
||||||
username: 'sara_farmer',
|
username: 'sara_resource_provider',
|
||||||
display_name: 'Sara Nicks',
|
display_name: 'Sara Nicks',
|
||||||
email: 'user1@example.com',
|
email: 'user1@example.com',
|
||||||
password: 'password',
|
password: 'password',
|
||||||
role: 'farmer',
|
role: 'resource_provider',
|
||||||
location: 'Amsterdam, Netherlands',
|
location: 'Amsterdam, Netherlands',
|
||||||
joined_date: '2024-01-15',
|
joined_date: '2024-01-15',
|
||||||
reputation: 4.8,
|
reputation: 4.8,
|
||||||
@@ -84,7 +84,7 @@ class UserDatabase {
|
|||||||
display_name: 'Jordan Mitchell',
|
display_name: 'Jordan Mitchell',
|
||||||
email: 'user5@example.com',
|
email: 'user5@example.com',
|
||||||
password: 'password',
|
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',
|
location: 'Toronto, Canada',
|
||||||
joined_date: new Date().toISOString().split('T')[0],
|
joined_date: new Date().toISOString().split('T')[0],
|
||||||
reputation: 5.0,
|
reputation: 5.0,
|
||||||
|
@@ -14,7 +14,7 @@ impl DataValidator {
|
|||||||
|
|
||||||
if let Value::Object(ref mut obj) = value {
|
if let Value::Object(ref mut obj) = value {
|
||||||
Self::repair_user_activities(obj)?;
|
Self::repair_user_activities(obj)?;
|
||||||
Self::repair_farmer_settings(obj)?;
|
Self::repair_resource_provider_settings(obj)?;
|
||||||
Self::ensure_required_fields(obj)?;
|
Self::ensure_required_fields(obj)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,20 +47,20 @@ impl DataValidator {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Repairs farmer settings to include all required fields
|
/// Repairs resource_provider settings to include all required fields
|
||||||
fn repair_farmer_settings(obj: &mut Map<String, Value>) -> Result<(), String> {
|
fn repair_resource_provider_settings(obj: &mut Map<String, Value>) -> Result<(), String> {
|
||||||
if let Some(Value::Object(ref mut farmer_settings)) = obj.get_mut("farmer_settings") {
|
if let Some(Value::Object(ref mut resource_provider_settings)) = obj.get_mut("resource_provider_settings") {
|
||||||
// Ensure minimum_deployment_duration exists
|
// Ensure minimum_deployment_duration exists
|
||||||
if !farmer_settings.contains_key("minimum_deployment_duration") {
|
if !resource_provider_settings.contains_key("minimum_deployment_duration") {
|
||||||
farmer_settings.insert(
|
resource_provider_settings.insert(
|
||||||
"minimum_deployment_duration".to_string(),
|
"minimum_deployment_duration".to_string(),
|
||||||
Value::Number(serde_json::Number::from(24))
|
Value::Number(serde_json::Number::from(24))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure preferred_regions exists
|
// Ensure preferred_regions exists
|
||||||
if !farmer_settings.contains_key("preferred_regions") {
|
if !resource_provider_settings.contains_key("preferred_regions") {
|
||||||
farmer_settings.insert(
|
resource_provider_settings.insert(
|
||||||
"preferred_regions".to_string(),
|
"preferred_regions".to_string(),
|
||||||
Value::Array(vec![
|
Value::Array(vec![
|
||||||
Value::String("NA".to_string()),
|
Value::String("NA".to_string()),
|
||||||
@@ -83,7 +83,7 @@ impl DataValidator {
|
|||||||
("apps", Value::Array(vec![])),
|
("apps", Value::Array(vec![])),
|
||||||
("app_deployments", Value::Array(vec![])),
|
("app_deployments", Value::Array(vec![])),
|
||||||
("nodes", Value::Array(vec![])),
|
("nodes", Value::Array(vec![])),
|
||||||
("farmer_earnings", Value::Array(vec![])),
|
("resource_provider_earnings", Value::Array(vec![])),
|
||||||
("user_activities", Value::Array(vec![])),
|
("user_activities", Value::Array(vec![])),
|
||||||
("pool_positions", Value::Object(Map::new())),
|
("pool_positions", Value::Object(Map::new())),
|
||||||
];
|
];
|
||||||
|
@@ -78,7 +78,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<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
|
<i class="bi bi-hdd-rack me-2"></i> Add a Mycelium Node
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -117,11 +117,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-lg-3 mb-4">
|
<div class="col-md-6 col-lg-3 mb-4">
|
||||||
<div class="dashboard-card">
|
<div class="dashboard-card">
|
||||||
<span class="badge bg-success badge-role">FARMER</span>
|
<span class="badge bg-success badge-role">RESOURCE PROVIDER</span>
|
||||||
<h4>Farmer Dashboard</h4>
|
<h4>Resource Provider Dashboard</h4>
|
||||||
<p>Manage your nodes, create slices, set pricing, and track earnings.</p>
|
<p>Manage your nodes, create slices, set pricing, and track earnings.</p>
|
||||||
<div class="d-grid">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -28,9 +28,9 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<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>
|
<i class="bi bi-hdd-rack me-1"></i>
|
||||||
Farmer
|
Resource Provider
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
{% extends "dashboard/layout.html" %}
|
{% extends "dashboard/layout.html" %}
|
||||||
|
|
||||||
{% block title %}ThreeFold Dashboard - Farmer{% endblock %}
|
{% block title %}ThreeFold Dashboard - Resource Provider{% endblock %}
|
||||||
|
|
||||||
{% block dashboard_content %}
|
{% block dashboard_content %}
|
||||||
<div class="my-4">
|
<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>
|
<p class="lead">Manage your nodes, configure slices, and monitor earnings</p>
|
||||||
|
|
||||||
<!-- Status Summary -->
|
<!-- Status Summary -->
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
<div class="stats-card success">
|
<div class="stats-card success">
|
||||||
<h5 class="card-title">Active Nodes</h5>
|
<h5 class="card-title">Active Nodes</h5>
|
||||||
<div class="d-flex justify-content-between align-items-end">
|
<div class="d-flex justify-content-between align-items-end">
|
||||||
<h2 class="mb-0" id="active-nodes-count">{{ farmer_stats.online_nodes }}</h2>
|
<h2 class="mb-0" id="active-nodes-count">{{ resource provider_stats.online_nodes }}</h2>
|
||||||
<small class="text-muted">of {{ farmer_stats.total_nodes }} total</small>
|
<small class="text-muted">of {{ resource provider_stats.total_nodes }} total</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
<div class="stats-card primary">
|
<div class="stats-card primary">
|
||||||
<h5 class="card-title">Allocated Slices</h5>
|
<h5 class="card-title">Allocated Slices</h5>
|
||||||
<div class="d-flex justify-content-between align-items-end">
|
<div class="d-flex justify-content-between align-items-end">
|
||||||
<h2 class="mb-0" id="active-slices-count">{{ farmer_stats.allocated_base_slices }}</h2>
|
<h2 class="mb-0" id="active-slices-count">{{ resource provider_stats.allocated_base_slices }}</h2>
|
||||||
<small class="text-muted">of {{ farmer_stats.total_base_slices }} total</small>
|
<small class="text-muted">of {{ resource provider_stats.total_base_slices }} total</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
<div class="stats-card warning">
|
<div class="stats-card warning">
|
||||||
<h5 class="card-title">Monthly Earnings</h5>
|
<h5 class="card-title">Monthly Earnings</h5>
|
||||||
<div class="d-flex justify-content-between align-items-end">
|
<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>
|
<small class="text-muted">$/month</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -187,7 +187,7 @@
|
|||||||
<div class="stats-card primary">
|
<div class="stats-card primary">
|
||||||
<h6 class="card-title">Total Base Slices</h6>
|
<h6 class="card-title">Total Base Slices</h6>
|
||||||
<div class="d-flex justify-content-between align-items-end">
|
<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>
|
<small class="text-muted">Available</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -196,7 +196,7 @@
|
|||||||
<div class="stats-card success">
|
<div class="stats-card success">
|
||||||
<h6 class="card-title">Allocated Slices</h6>
|
<h6 class="card-title">Allocated Slices</h6>
|
||||||
<div class="d-flex justify-content-between align-items-end">
|
<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>
|
<small class="text-muted">Rented</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -205,7 +205,7 @@
|
|||||||
<div class="stats-card info">
|
<div class="stats-card info">
|
||||||
<h6 class="card-title">Available Slices</h6>
|
<h6 class="card-title">Available Slices</h6>
|
||||||
<div class="d-flex justify-content-between align-items-end">
|
<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>
|
<small class="text-muted">For Rent</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
<div class="stats-card warning">
|
<div class="stats-card warning">
|
||||||
<h6 class="card-title">Utilization</h6>
|
<h6 class="card-title">Utilization</h6>
|
||||||
<div class="d-flex justify-content-between align-items-end">
|
<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>
|
<small class="text-muted">Capacity</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -238,8 +238,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="node-slices-table">
|
<tbody id="node-slices-table">
|
||||||
{% if farmer_nodes %}
|
{% if resource provider_nodes %}
|
||||||
{% for node in farmer_nodes %}
|
{% for node in resource provider_nodes %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
@@ -396,8 +396,8 @@
|
|||||||
{{ super() }}
|
{{ super() }}
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||||
|
|
||||||
<!-- Load farmer dashboard JavaScript -->
|
<!-- Load resource provider dashboard JavaScript -->
|
||||||
<script src="/static/js/dashboard-farmer.js"></script>
|
<script src="/static/js/dashboard-resource_provider.js"></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Ensure charts have consistent sizes */
|
/* Ensure charts have consistent sizes */
|
@@ -55,7 +55,7 @@
|
|||||||
<div class="display-4 mb-3 text-success">
|
<div class="display-4 mb-3 text-success">
|
||||||
<i class="bi bi-hdd-rack"></i>
|
<i class="bi bi-hdd-rack"></i>
|
||||||
</div>
|
</div>
|
||||||
<h5>As a Farmer</h5>
|
<h5>As a Resource Provider</h5>
|
||||||
<p>Manage nodes, configure slices, set pricing</p>
|
<p>Manage nodes, configure slices, set pricing</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -341,7 +341,7 @@
|
|||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title"><i class="bi bi-people me-2 text-success"></i>Community Building</h5>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -78,7 +78,7 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<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>
|
<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>
|
<a href="/docs" class="btn btn-outline-primary">Learn More</a>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block title %}Farmers Terms and Conditions - Project Mycelium{% endblock %}
|
{% block title %}Resource Providers Terms and Conditions - Project Mycelium{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container my-5">
|
<div class="container my-5">
|
||||||
@@ -9,25 +9,25 @@
|
|||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item"><a href="/terms">Terms and Conditions</a></li>
|
<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>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="d-flex align-items-center mb-4">
|
<div class="d-flex align-items-center mb-4">
|
||||||
<i class="bi bi-hdd-rack fs-1 me-3 text-primary"></i>
|
<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>
|
</div>
|
||||||
<p class="lead mb-4">Last updated: May 22, 2025</p>
|
<p class="lead mb-4">Last updated: May 22, 2025</p>
|
||||||
|
|
||||||
<div class="alert alert-info">
|
<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>
|
</div>
|
||||||
|
|
||||||
<h2>1. Definition of a Farmer</h2>
|
<h2>1. Definition of a Resource Provider</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>
|
<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>
|
<h2>2. Resource Provider Responsibilities</h2>
|
||||||
<p>As a Farmer on the Project Mycelium, you agree to:</p>
|
<p>As a Resource Provider on the Project Mycelium, you agree to:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Maintain your connected hardware in good working condition with adequate internet connectivity</li>
|
<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>
|
<li>Ensure your hardware meets the minimum technical requirements specified in the Farming documentation</li>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>3. Reputation System and Staking</h2>
|
<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>
|
<ul>
|
||||||
<li>Your reputation score is calculated based on multiple factors including uptime, staked Credits, and performance metrics</li>
|
<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>
|
<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>
|
<h2>4. Rewards and Credits</h2>
|
||||||
<p>Compensation for resource contribution is governed by the following principles:</p>
|
<p>Compensation for resource contribution is governed by the following principles:</p>
|
||||||
<ul>
|
<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>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>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>
|
</ul>
|
||||||
|
|
||||||
<h2>5. Hardware and Capacity</h2>
|
<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>
|
<li>Slashing penalties may include reputation reduction, temporary suspension, or in severe cases, permanent removal from the marketplace</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>7. Termination of Farmer Status</h2>
|
<h2>7. Termination of Resource Provider Status</h2>
|
||||||
<p>You may cease being a Farmer by:</p>
|
<p>You may cease being a Resource Provider by:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Disconnecting your hardware from the Mycelium Grid</li>
|
<li>Disconnecting your hardware from the Mycelium Grid</li>
|
||||||
<li>Providing notice through your dashboard at least 30 days prior to complete disconnection</li>
|
<li>Providing notice through your dashboard at least 30 days prior to complete disconnection</li>
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>8. Liability Limitation</h2>
|
<h2>8. Liability Limitation</h2>
|
||||||
<p>As a Farmer, you acknowledge that:</p>
|
<p>As a Resource Provider, you acknowledge that:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>ThreeFold is not responsible for any damage to your hardware resulting from normal operation</li>
|
<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>
|
<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">
|
<div class="alert alert-warning mt-5">
|
||||||
<h5 class="alert-heading">Important Note</h5>
|
<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>
|
||||||
|
|
||||||
<div class="text-center mt-5 mb-3">
|
<div class="text-center mt-5 mb-3">
|
@@ -18,9 +18,9 @@
|
|||||||
<div class="card h-100 shadow-sm">
|
<div class="card h-100 shadow-sm">
|
||||||
<div class="card-body text-center">
|
<div class="card-body text-center">
|
||||||
<i class="bi bi-hdd-rack fs-1 mb-3 text-primary"></i>
|
<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>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -129,8 +129,8 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="provider-name">
|
<div class="provider-name">
|
||||||
{% if product_data.product.attributes.farmer_email %}
|
{% if product_data.product.attributes.resource provider_email %}
|
||||||
{{ product_data.product.attributes.farmer_email.value | truncate(length=15) }}
|
{{ product_data.product.attributes.resource provider_email.value | truncate(length=15) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if product_data.product.provider %}{{ product_data.product.provider }}{% else %}Unknown{% endif %}
|
{% if product_data.product.provider %}{{ product_data.product.provider }}{% else %}Unknown{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
<h5 class="alert-heading">What are Mycelium Nodes?</h5>
|
<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>
|
<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>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<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="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h5>1. Purchase Your Mycelium Node</h5>
|
<h5>1. Purchase Your Mycelium Node</h5>
|
||||||
@@ -322,7 +322,7 @@
|
|||||||
|
|
||||||
<div class="alert alert-info mt-3">
|
<div class="alert alert-info mt-3">
|
||||||
<i class="bi bi-info-circle me-2"></i>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
<strong>Node:</strong> {{ slice.node_id }}
|
<strong>Node:</strong> {{ slice.node_id }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<strong>Farmer:</strong> {{ slice.farmer_email }}
|
<strong>Resource Provider:</strong> {{ slice.resource provider_email }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<strong>Specifications:</strong>
|
<strong>Specifications:</strong>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form id="sliceRentalForm" method="POST" action="/marketplace/slice/rent">
|
<form id="sliceRentalForm" method="POST" action="/marketplace/slice/rent">
|
||||||
<!-- Hidden fields -->
|
<!-- 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="node_id" value="{{ node_id }}">
|
||||||
<input type="hidden" name="combination_id" value="{{ combination_id }}">
|
<input type="hidden" name="combination_id" value="{{ combination_id }}">
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user