Compare commits
7 Commits
workflows
...
1eeca606ec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1eeca606ec | ||
|
|
6ce8850ddb | ||
|
|
a9a08d2ef8 | ||
|
|
bbde3c1b60 | ||
|
|
e2d364722b | ||
|
|
da0ab29b2a | ||
| a1996adc45 |
16
.github/workflows/test.yaml
vendored
16
.github/workflows/test.yaml
vendored
@@ -45,11 +45,16 @@ jobs:
|
|||||||
- name: Restore frontend build cache
|
- name: Restore frontend build cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: apps/nxmesh-frontend/build
|
path: apps/nxmesh-frontend/dist
|
||||||
key: frontend-build-${{ runner.os }}-run-${{ github.run_id }}
|
key: frontend-build-${{ runner.os }}-run-${{ github.run_id }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
frontend-build-${{ runner.os }}-
|
frontend-build-${{ runner.os }}-
|
||||||
|
|
||||||
|
- name: Add dummy fonrtend build artifact to prevent build failure
|
||||||
|
run: |
|
||||||
|
mkdir -p apps/nxmesh-frontend/dist
|
||||||
|
touch apps/nxmesh-frontend/dist/dummy
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --all-features
|
run: cargo test --all-features
|
||||||
|
|
||||||
@@ -74,11 +79,16 @@ jobs:
|
|||||||
- name: Restore frontend build cache
|
- name: Restore frontend build cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: apps/nxmesh-frontend/build
|
path: apps/nxmesh-frontend/dist
|
||||||
key: frontend-build-${{ runner.os }}-run-${{ github.run_id }}
|
key: frontend-build-${{ runner.os }}-run-${{ github.run_id }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
frontend-build-${{ runner.os }}-
|
frontend-build-${{ runner.os }}-
|
||||||
|
|
||||||
|
- name: Add dummy fonrtend build artifact to prevent build failure
|
||||||
|
run: |
|
||||||
|
mkdir -p apps/nxmesh-frontend/dist
|
||||||
|
touch apps/nxmesh-frontend/dist/dummy
|
||||||
|
|
||||||
- name: Run clippy
|
- name: Run clippy
|
||||||
run: cargo clippy --all-features
|
run: cargo clippy --all-features
|
||||||
|
|
||||||
@@ -147,7 +157,7 @@ jobs:
|
|||||||
- name: Cache frontend build
|
- name: Cache frontend build
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: apps/nxmesh-frontend/build
|
path: apps/nxmesh-frontend/dist
|
||||||
key: frontend-build-${{ runner.os }}-run-${{ github.run_id }}
|
key: frontend-build-${{ runner.os }}-run-${{ github.run_id }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
frontend-build-${{ runner.os }}-
|
frontend-build-${{ runner.os }}-
|
||||||
|
|||||||
76
Cargo.lock
generated
76
Cargo.lock
generated
@@ -538,6 +538,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
|
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum-core",
|
"axum-core",
|
||||||
|
"axum-macros",
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
@@ -586,6 +587,17 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-macros"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
@@ -2477,12 +2489,14 @@ dependencies = [
|
|||||||
"handlebars",
|
"handlebars",
|
||||||
"hex",
|
"hex",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
|
"mime_guess",
|
||||||
"mockall",
|
"mockall",
|
||||||
"nxmesh-core",
|
"nxmesh-core",
|
||||||
"nxmesh-migration",
|
"nxmesh-migration",
|
||||||
"nxmesh-proto",
|
"nxmesh-proto",
|
||||||
"rand 0.10.0",
|
"rand 0.10.0",
|
||||||
"rcgen",
|
"rcgen",
|
||||||
|
"rust-embed",
|
||||||
"sea-orm",
|
"sea-orm",
|
||||||
"sea-orm-migration",
|
"sea-orm-migration",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -3338,6 +3352,40 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-embed"
|
||||||
|
version = "8.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27"
|
||||||
|
dependencies = [
|
||||||
|
"rust-embed-impl",
|
||||||
|
"rust-embed-utils",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-embed-impl"
|
||||||
|
version = "8.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rust-embed-utils",
|
||||||
|
"syn 2.0.117",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-embed-utils"
|
||||||
|
version = "8.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1"
|
||||||
|
dependencies = [
|
||||||
|
"sha2",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-ini"
|
name = "rust-ini"
|
||||||
version = "0.21.3"
|
version = "0.21.3"
|
||||||
@@ -3454,6 +3502,15 @@ version = "1.0.23"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "same-file"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schannel"
|
name = "schannel"
|
||||||
version = "0.1.28"
|
version = "0.1.28"
|
||||||
@@ -4876,6 +4933,16 @@ version = "0.9.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "walkdir"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||||
|
dependencies = [
|
||||||
|
"same-file",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "want"
|
name = "want"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@@ -5046,6 +5113,15 @@ dependencies = [
|
|||||||
"wasite",
|
"wasite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.62.2"
|
version = "0.62.2"
|
||||||
|
|||||||
@@ -84,7 +84,12 @@ time = "0.3"
|
|||||||
|
|
||||||
# Cert handling
|
# Cert handling
|
||||||
zip = { workspace = true }
|
zip = { workspace = true }
|
||||||
|
rust-embed = { version = "8.11.0", features = [] }
|
||||||
|
mime_guess = "2.0.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio-test.workspace = true
|
tokio-test.workspace = true
|
||||||
mockall.workspace = true
|
mockall.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
dev-tools = ["axum/macros"]
|
||||||
|
|||||||
1
apps/nxmesh-master/frontend-dist
Symbolic link
1
apps/nxmesh-master/frontend-dist
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../nxmesh-frontend/dist/
|
||||||
@@ -6,6 +6,7 @@ use nxmesh_proto::{
|
|||||||
};
|
};
|
||||||
use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter};
|
use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter};
|
||||||
use tonic::transport::Server;
|
use tonic::transport::Server;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{db::entities::public_key_revocations, service::agent::AgentServerService};
|
use crate::{db::entities::public_key_revocations, service::agent::AgentServerService};
|
||||||
|
|
||||||
@@ -69,7 +70,14 @@ impl AgentConnectorTrait for SshAgentConnector {
|
|||||||
.layer(ssh_interceptor)
|
.layer(ssh_interceptor)
|
||||||
.add_service(agent_server_service);
|
.add_service(agent_server_service);
|
||||||
|
|
||||||
router.serve(addr).await?;
|
info!("SSH Agent gRPC server is listening on {}", addr);
|
||||||
|
router
|
||||||
|
.serve(addr)
|
||||||
|
.await
|
||||||
|
.inspect(|_| info!("SSH Agent gRPC server stopped gracefully."))
|
||||||
|
.inspect_err(|e| {
|
||||||
|
tracing::error!("SSH Agent gRPC server failed: {}", e);
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ mod cli;
|
|||||||
mod config;
|
mod config;
|
||||||
mod connector;
|
mod connector;
|
||||||
mod db;
|
mod db;
|
||||||
|
mod routes;
|
||||||
mod service;
|
mod service;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
|||||||
69
apps/nxmesh-master/src/routes/frontend/mod.rs
Normal file
69
apps/nxmesh-master/src/routes/frontend/mod.rs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
use axum::{Router, response::IntoResponse};
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
// In development, build the frontend from the source directory, the soft link will handle the path resolution
|
||||||
|
// In deployment, pre-build the frontend and replace the frontend-dist folder with the built assets, the rust-embed will handle the embedding and path resolution
|
||||||
|
#[derive(rust_embed::Embed)]
|
||||||
|
#[folder = "./frontend-dist/"]
|
||||||
|
struct FrontendAssets;
|
||||||
|
|
||||||
|
const INDEX_HTML: &str = "index.html";
|
||||||
|
|
||||||
|
pub async fn get_router() -> Router {
|
||||||
|
Router::new()
|
||||||
|
.route(
|
||||||
|
"/",
|
||||||
|
axum::routing::get(get_fallback_handler)
|
||||||
|
.head(get_fallback_handler)
|
||||||
|
.options(get_fallback_handler),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{*path}",
|
||||||
|
axum::routing::get(get_file_handler)
|
||||||
|
.head(get_file_handler)
|
||||||
|
.options(get_file_handler),
|
||||||
|
)
|
||||||
|
//
|
||||||
|
.fallback(get_fallback_handler().await)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_fallback_handler() -> Result<axum::response::Html<Vec<u8>>, axum::http::StatusCode>
|
||||||
|
{
|
||||||
|
let index_html = get_index_html();
|
||||||
|
match index_html {
|
||||||
|
Some(html) => Ok(axum::response::Html(html)),
|
||||||
|
None => Err(axum::http::StatusCode::NOT_FOUND),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_index_html() -> Option<Vec<u8>> {
|
||||||
|
FrontendAssets::get(INDEX_HTML).map(|asset| asset.data.as_ref().to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_file_handler(
|
||||||
|
axum::extract::Path(path): axum::extract::Path<String>,
|
||||||
|
) -> Result<axum::response::Response, axum::http::StatusCode> {
|
||||||
|
let file_path = if path.is_empty() {
|
||||||
|
INDEX_HTML.to_string()
|
||||||
|
} else {
|
||||||
|
path
|
||||||
|
};
|
||||||
|
|
||||||
|
match FrontendAssets::get(&file_path) {
|
||||||
|
Some(asset) => {
|
||||||
|
let content_type = mime_guess::from_path(&file_path).first_or_octet_stream();
|
||||||
|
let response = axum::response::Response::builder()
|
||||||
|
.header(axum::http::header::CONTENT_TYPE, content_type.as_ref())
|
||||||
|
.body(asset.data.into_owned().into())
|
||||||
|
.map_err(|e| {
|
||||||
|
error!("Failed to build response for {}: {}", file_path, e);
|
||||||
|
axum::http::StatusCode::INTERNAL_SERVER_ERROR
|
||||||
|
})?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
// return index.html for any file not found to support client-side routing in the frontend
|
||||||
|
None => get_fallback_handler()
|
||||||
|
.await
|
||||||
|
.map(|html| html.into_response()),
|
||||||
|
}
|
||||||
|
}
|
||||||
9
apps/nxmesh-master/src/routes/mod.rs
Normal file
9
apps/nxmesh-master/src/routes/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
use axum::Router;
|
||||||
|
|
||||||
|
mod frontend;
|
||||||
|
|
||||||
|
pub async fn get_root_router() -> Router {
|
||||||
|
Router::new()
|
||||||
|
.merge(frontend::get_router().await)
|
||||||
|
.fallback(frontend::get_fallback_handler().await)
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
use std::sync::Arc;
|
use std::{net::ToSocketAddrs, sync::Arc};
|
||||||
|
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{connector::agent::AgentConnectorTrait, service::certificate::CertificateService};
|
use crate::{connector::agent::AgentConnectorTrait, service::certificate::CertificateService};
|
||||||
|
|
||||||
@@ -26,15 +28,38 @@ pub async fn start_master_server(
|
|||||||
println!("Certificate generated and stored successfully.");
|
println!("Certificate generated and stored successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize agent connector
|
let ssh_connector = crate::connector::agent::ssh::SshAgentConnector::new(settings.clone())?;
|
||||||
let mut agent_connector = crate::connector::agent::AgentConnector::new(Box::new(
|
let cert_service_for_agent = cert_service.clone();
|
||||||
crate::connector::agent::ssh::SshAgentConnector::new(settings.clone())?,
|
let settings_for_agent = settings.clone();
|
||||||
));
|
let connection_for_agent = db_connection.clone();
|
||||||
|
|
||||||
// Start the agent server
|
tokio::spawn(async move {
|
||||||
agent_connector
|
let mut connector = ssh_connector;
|
||||||
.start_server(&settings, cert_service, db_connection)
|
tracing::info!("Starting agent server...");
|
||||||
.await?;
|
if let Err(e) = connector
|
||||||
|
.start_server(
|
||||||
|
&settings_for_agent,
|
||||||
|
cert_service_for_agent,
|
||||||
|
connection_for_agent,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
tracing::error!("Agent server failed: {}", e);
|
||||||
|
} else {
|
||||||
|
tracing::info!("Agent server stopped.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let axum_router = crate::routes::get_root_router().await;
|
||||||
|
|
||||||
|
// Start the HTTP server
|
||||||
|
let addr = format!("{}:{}", settings.server.bind_address, settings.server.port)
|
||||||
|
.to_socket_addrs()?
|
||||||
|
.next()
|
||||||
|
.ok_or("Invalid bind address")?;
|
||||||
|
let listener = tokio::net::TcpListener::bind(addr).await?;
|
||||||
|
info!("Web/API server is listening on {}", addr);
|
||||||
|
axum::serve(listener, axum_router).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user