features: app engine #1

Merged
ghe0 merged 11 commits from app_engine into main 2025-05-15 01:39:06 +00:00
7 changed files with 100 additions and 4 deletions
Showing only changes of commit 7807e14167 - Show all commits

1
Cargo.lock generated

@ -3796,6 +3796,7 @@ dependencies = [
"ed25519-dalek",
"env_logger",
"futures",
"hex",
"hyper-util",
"itertools 0.14.0",
"log",

@ -22,6 +22,7 @@ env_logger = "0.11.8"
thiserror = "2.0.12"
nanoid = "0.4.0"
dotenv = "0.15.0"
hex = "0.4.3"
[profile.release]
lto = true

@ -17,7 +17,11 @@ async fn main() {
if dotenv::from_filename("/etc/detee/brain/config.ini").is_err() {
dotenv().ok();
}
env_logger::builder().filter_level(log::LevelFilter::Debug).init();
env_logger::builder()
.filter_level(log::LevelFilter::Trace)
.filter_module("tungstenite", log::LevelFilter::Debug)
.filter_module("tokio_tungstenite", log::LevelFilter::Debug)
.init();
let db_url = std::env::var("DB_URL").expect("the environment variable DB_URL is not set");
let db_user = std::env::var("DB_USER").expect("the environment variable DB_USER is not set");

@ -32,6 +32,7 @@ pub const DELETED_VM: &str = "deleted_vm";
pub const VM_CONTRACT: &str = "vm_contract";
pub const ACTIVE_APP: &str = "active_app";
pub const APP_NODE: &str = "app_node";
pub const ID_ALPHABET: [char; 62] = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',

@ -1,7 +1,8 @@
use crate::constants::{ACCOUNT, ACTIVE_APP};
use crate::constants::{ACCOUNT, ACTIVE_APP, APP_NODE};
use crate::db::general::Report;
use super::Error;
use crate::db;
use crate::old_brain;
use serde::{Deserialize, Serialize};
use surrealdb::engine::remote::ws::Client;
@ -25,6 +26,14 @@ pub struct AppNode {
pub offline_minutes: u64,
}
impl AppNode {
pub async fn register(self, db: &Surreal<Client>) -> Result<AppNode, Error> {
db::Account::get_or_create(db, &self.operator.key().to_string()).await?;
let app_node: Option<AppNode> = db.upsert(self.id.clone()).content(self).await?;
app_node.ok_or(Error::FailedToCreateDBEntry)
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct AppNodeWithReports {
pub id: RecordId,
@ -88,6 +97,17 @@ pub struct ActiveAppWithNode {
}
impl ActiveAppWithNode {
pub async fn list_by_node(db: &Surreal<Client>, node_pubkey: &str) -> Result<Vec<Self>, Error> {
let mut query_result = db
.query(format!(
"select * from {ACTIVE_APP} where out = {APP_NODE}:{node_pubkey} fetch out;"
))
.await?;
let contract: Vec<Self> = query_result.take(0)?;
Ok(contract)
}
pub async fn get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
let contract: Option<Self> =
db.query(format!("select * from {ACTIVE_APP}:{uuid} fetch out;")).await?.take(0)?;

@ -1,3 +1,5 @@
use crate::constants::{ACCOUNT, APP_NODE};
use crate::db::prelude as db;
use crate::grpc::{check_sig_from_parts, check_sig_from_req};
use detee_shared::app_proto::brain_app_cli_server::BrainAppCli;
use detee_shared::app_proto::brain_app_daemon_server::BrainAppDaemon;
@ -10,9 +12,12 @@ use log::info;
use std::pin::Pin;
use std::sync::Arc;
use surrealdb::engine::remote::ws::Client;
use surrealdb::RecordId;
use surrealdb::Surreal;
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;
use tokio_stream::{Stream, StreamExt};
use tonic::{Status, Streaming};
use tonic::{Response, Status, Streaming};
pub struct AppDaemonServer {
pub db: Arc<Surreal<Client>>,
@ -37,7 +42,36 @@ impl BrainAppDaemon for AppDaemonServer {
let req = check_sig_from_req(req)?;
info!("Starting app_node registration process for {:?}", req);
todo!()
let app_node = db::AppNode {
id: RecordId::from((APP_NODE, req.node_pubkey.clone())),
operator: RecordId::from((ACCOUNT, req.operator_wallet)),
country: req.country,
region: req.region,
city: req.city,
ip: req.main_ip,
price: req.price,
avail_mem_mb: 0,
avail_vcpus: 0,
avail_storage_gbs: 0,
avail_ports: 0,
max_ports_per_app: 0,
offline_minutes: 0,
};
app_node.register(&self.db).await?;
info!("Sending existing contracts to {}", req.node_pubkey);
let contracts = db::ActiveAppWithNode::list_by_node(&self.db, &req.node_pubkey).await?;
let (tx, rx) = mpsc::channel(6);
tokio::spawn(async move {
for contract in contracts {
let _ = tx.send(Ok(contract.into())).await;
}
});
let resp_stream = ReceiverStream::new(rx);
Ok(Response::new(Box::pin(resp_stream)))
}
async fn brain_messages(

@ -250,3 +250,38 @@ impl From<VmNodeResources> for db::VmNodeResources {
}
}
}
impl From<db::ActiveAppWithNode> for AppContract {
fn from(value: db::ActiveAppWithNode) -> Self {
let public_package_mr_enclave =
Some(hex::decode(value.mr_enclave.clone()).unwrap_or_default());
AppContract {
uuid: value.id.key().to_string(),
package_url: value.package_url,
admin_pubkey: value.admin.key().to_string(),
node_pubkey: value.app_node.id.key().to_string(),
public_ipv4: value.host_ipv4,
resource: Some(AppResource {
memory_mb: value.memory_mb as u32,
disk_mb: value.disk_size_gb as u32,
vcpu: value.vcpus as u32,
ports: value.mapped_ports.iter().map(|(_, g)| *g as u32).collect(),
}),
mapped_ports: value
.mapped_ports
.iter()
.map(|(h, g)| MappedPort { host_port: *h as u32, guest_port: *g as u32 })
.collect(),
created_at: value.created_at.to_rfc3339(),
updated_at: value.created_at.to_rfc3339(),
nano_per_minute: value.price_per_unit,
locked_nano: value.locked_nano,
collected_at: value.collected_at.to_rfc3339(),
hratls_pubkey: value.mr_enclave,
public_package_mr_enclave,
app_name: value.app_name,
}
}
}