use crate::constants::{ACCOUNT, ID_ALPHABET, NEW_VM_REQ, VM_NODE}; use crate::db::prelude as db; use detee_shared::app_proto::AppNodeListResp; use detee_shared::general_proto::{AccountBalance, ListOperatorsResp}; use detee_shared::vm_proto::*; use nanoid::nanoid; use surrealdb::RecordId; impl From for AccountBalance { fn from(account: db::Account) -> Self { AccountBalance { balance: account.balance, tmp_locked: account.tmp_locked } } } impl From for db::NewVmReq { fn from(new_vm_req: NewVmReq) -> Self { Self { id: RecordId::from((NEW_VM_REQ, nanoid!(40, &ID_ALPHABET))), admin: RecordId::from((ACCOUNT, new_vm_req.admin_pubkey)), vm_node: RecordId::from((VM_NODE, new_vm_req.node_pubkey)), hostname: new_vm_req.hostname, extra_ports: new_vm_req.extra_ports, public_ipv4: new_vm_req.public_ipv4, public_ipv6: new_vm_req.public_ipv6, disk_size_gb: new_vm_req.disk_size_gb, vcpus: new_vm_req.vcpus, memory_mb: new_vm_req.memory_mb, kernel_url: new_vm_req.kernel_url, kernel_sha: new_vm_req.kernel_sha, dtrfs_url: new_vm_req.dtrfs_url, dtrfs_sha: new_vm_req.dtrfs_sha, price_per_unit: new_vm_req.price_per_unit, locked_nano: new_vm_req.locked_nano, created_at: surrealdb::sql::Datetime::default(), error: String::new(), } } } impl From for NewVmReq { fn from(new_vm_req: db::NewVmReq) -> Self { Self { uuid: new_vm_req.id.key().to_string(), hostname: new_vm_req.hostname, admin_pubkey: new_vm_req.admin.key().to_string(), node_pubkey: new_vm_req.vm_node.key().to_string(), extra_ports: new_vm_req.extra_ports, public_ipv4: new_vm_req.public_ipv4, public_ipv6: new_vm_req.public_ipv6, disk_size_gb: new_vm_req.disk_size_gb, vcpus: new_vm_req.vcpus, memory_mb: new_vm_req.memory_mb, kernel_url: new_vm_req.kernel_url, kernel_sha: new_vm_req.kernel_sha, dtrfs_url: new_vm_req.dtrfs_url, dtrfs_sha: new_vm_req.dtrfs_sha, price_per_unit: new_vm_req.price_per_unit, locked_nano: new_vm_req.locked_nano, } } } impl From for NewVmResp { fn from(resp: db::NewVmResp) -> Self { match resp { // TODO: This will require a small architecture change to pass MeasurementArgs from // Daemon to CLI db::NewVmResp::Args(uuid, args) => { NewVmResp { uuid, error: String::new(), args: Some(args) } } db::NewVmResp::Error(uuid, error) => NewVmResp { uuid, error, args: None }, } } } impl From for UpdateVmReq { fn from(update_vm_req: db::UpdateVmReq) -> Self { Self { uuid: update_vm_req.id.key().to_string(), // daemon does not care about VM hostname hostname: String::new(), admin_pubkey: update_vm_req.admin.key().to_string(), disk_size_gb: update_vm_req.disk_size_gb, vcpus: update_vm_req.vcpus, memory_mb: update_vm_req.memory_mb, kernel_url: update_vm_req.kernel_url, kernel_sha: update_vm_req.kernel_sha, dtrfs_url: update_vm_req.dtrfs_url, dtrfs_sha: update_vm_req.dtrfs_sha, } } } impl From for DeleteVmReq { fn from(delete_vm_req: db::DeletedVm) -> Self { Self { uuid: delete_vm_req.id.key().to_string(), admin_pubkey: delete_vm_req.admin.key().to_string(), } } } impl From for BrainVmMessage { fn from(notification: db::VmDaemonMsg) -> Self { match notification { db::VmDaemonMsg::Create(new_vm_req) => { BrainVmMessage { msg: Some(brain_vm_message::Msg::NewVmReq(new_vm_req.into())) } } db::VmDaemonMsg::Update(update_vm_req) => BrainVmMessage { msg: Some(brain_vm_message::Msg::UpdateVmReq(update_vm_req.into())), }, db::VmDaemonMsg::Delete(deleted_vm) => { BrainVmMessage { msg: Some(brain_vm_message::Msg::DeleteVm(deleted_vm.into())) } } } } } impl From for VmContract { fn from(db_c: db::ActiveVmWithNode) -> Self { let mut exposed_ports = Vec::new(); for port in db_c.mapped_ports.iter() { exposed_ports.push(port.0); } VmContract { uuid: db_c.id.key().to_string(), hostname: db_c.hostname.clone(), admin_pubkey: db_c.admin.key().to_string(), node_pubkey: db_c.vm_node.id.key().to_string(), node_ip: db_c.vm_node.ip.clone(), location: format!( "{}, {}, {}", db_c.vm_node.city, db_c.vm_node.region, db_c.vm_node.country ), memory_mb: db_c.memory_mb, vcpus: db_c.vcpus, disk_size_gb: db_c.disk_size_gb, mapped_ports: db_c .mapped_ports .iter() .map(|(h, g)| MappedPort { host_port: *h, guest_port: *g }) .collect(), vm_public_ipv6: db_c.public_ipv6.clone(), vm_public_ipv4: db_c.public_ipv4.clone(), locked_nano: db_c.locked_nano, dtrfs_sha: db_c.dtrfs_sha.clone(), kernel_sha: db_c.kernel_sha.clone(), nano_per_minute: db_c.price_per_minute(), created_at: db_c.created_at.to_rfc3339(), // TODO: remove updated_at from the proto // This will get moved to VM history (users will be able to // query old contracts, which also shows updates of existing contracts). updated_at: db_c.created_at.to_rfc3339(), collected_at: db_c.collected_at.to_rfc3339(), } } } impl From for tonic::Status { fn from(e: db::Error) -> Self { Self::internal(format!("Internal error: {e}")) } } impl From for ListOperatorsResp { fn from(db_o: db::Operator) -> Self { ListOperatorsResp { pubkey: db_o.account.key().to_string(), escrow: db_o.escrow, email: db_o.email, app_nodes: db_o.app_nodes, vm_nodes: db_o.vm_nodes, reports: db_o.reports, } } } impl From for VmNodeListResp { fn from(vm_node: db::VmNodeWithReports) -> Self { Self { operator: vm_node.operator.key().to_string(), node_pubkey: vm_node.id.key().to_string(), country: vm_node.country, region: vm_node.region, city: vm_node.city, ip: vm_node.ip, reports: vm_node.reports.iter().map(|n| n.reason.clone()).collect(), price: vm_node.price, } } } impl From for AppNodeListResp { fn from(app_node: db::AppNodeWithReports) -> Self { Self { operator: app_node.operator.key().to_string(), node_pubkey: app_node.id.key().to_string(), country: app_node.country, region: app_node.region, city: app_node.city, ip: app_node.ip, reports: app_node.reports.iter().map(|n| n.reason.clone()).collect(), price: app_node.price, } } } impl From for db::VmNodeResources { fn from(res: VmNodeResources) -> Self { Self { avail_mem_mb: res.avail_memory_mb, avail_vcpus: res.avail_vcpus, avail_storage_gbs: res.avail_storage_gb, avail_ipv4: res.avail_ipv4, avail_ipv6: res.avail_ipv6, avail_ports: res.avail_ports, max_ports_per_vm: res.max_ports_per_vm, } } }