mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-05-30 11:50:38 +00:00
feat: embed dashboard into GreptimeDB binary (#1239)
* feat: embed dashboard into GreptimeDB binary * fix: resolve PR comments
This commit is contained in:
@@ -6,6 +6,7 @@ license.workspace = true
|
||||
|
||||
[features]
|
||||
mem-prof = ["dep:common-mem-prof"]
|
||||
dashboard = []
|
||||
|
||||
[dependencies]
|
||||
aide = { version = "0.9", features = ["axum"] }
|
||||
@@ -39,6 +40,7 @@ humantime-serde = "1.1"
|
||||
hyper = { version = "0.14", features = ["full"] }
|
||||
influxdb_line_protocol = { git = "https://github.com/evenyag/influxdb_iox", branch = "feat/line-protocol" }
|
||||
metrics = "0.20"
|
||||
mime_guess = "2.0"
|
||||
num_cpus = "1.13"
|
||||
once_cell = "1.16"
|
||||
openmetrics-parser = "0.4"
|
||||
@@ -54,6 +56,7 @@ rand.workspace = true
|
||||
regex = "1.6"
|
||||
rustls = "0.20"
|
||||
rustls-pemfile = "1.0"
|
||||
rust-embed = { version = "6.6", features = ["debug-embed"] }
|
||||
schemars = "0.8"
|
||||
serde.workspace = true
|
||||
serde_json = "1.0"
|
||||
|
||||
54
src/servers/build.rs
Normal file
54
src/servers/build.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2023 Greptime Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
fn main() {
|
||||
#[cfg(feature = "dashboard")]
|
||||
fetch_dashboard_assets();
|
||||
}
|
||||
|
||||
#[cfg(feature = "dashboard")]
|
||||
fn fetch_dashboard_assets() {
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
macro_rules! p {
|
||||
($($tokens: tt)*) => {
|
||||
println!("cargo:warning={}", format!($($tokens)*))
|
||||
}
|
||||
}
|
||||
|
||||
let output = Command::new("./fetch-dashboard-assets.sh")
|
||||
.current_dir("../../scripts")
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.and_then(|p| p.wait_with_output());
|
||||
match output {
|
||||
Ok(output) => {
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
.lines()
|
||||
.for_each(|x| p!("{}", x));
|
||||
|
||||
assert!(output.status.success());
|
||||
}
|
||||
Err(e) => {
|
||||
let e = format!(
|
||||
r#"
|
||||
Failed to fetch dashboard assets: {}.
|
||||
You can manually execute './scripts/fetch-dashboard-assets.sh' to see why,
|
||||
or it's a network error, just try again or enable/disable some proxy."#,
|
||||
e
|
||||
);
|
||||
panic!("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/servers/dashboard/VERSION
Normal file
1
src/servers/dashboard/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
v0.0.1-test
|
||||
@@ -18,7 +18,7 @@ use std::string::FromUtf8Error;
|
||||
|
||||
use axum::http::StatusCode as HttpStatusCode;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use axum::Json;
|
||||
use axum::{http, Json};
|
||||
use base64::DecodeError;
|
||||
use catalog;
|
||||
use common_error::prelude::*;
|
||||
@@ -275,6 +275,12 @@ pub enum Error {
|
||||
source: tonic_reflection::server::Error,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to build HTTP response, source: {source}"))]
|
||||
BuildHttpResponse {
|
||||
source: http::Error,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -294,7 +300,8 @@ impl ErrorExt for Error {
|
||||
| TcpBind { .. }
|
||||
| CatalogError { .. }
|
||||
| GrpcReflectionService { .. }
|
||||
| BuildingContext { .. } => StatusCode::Internal,
|
||||
| BuildingContext { .. }
|
||||
| BuildHttpResponse { .. } => StatusCode::Internal,
|
||||
|
||||
InsertScript { source, .. }
|
||||
| ExecuteScript { source, .. }
|
||||
|
||||
@@ -20,6 +20,8 @@ pub mod prometheus;
|
||||
pub mod script;
|
||||
|
||||
mod admin;
|
||||
#[cfg(feature = "dashboard")]
|
||||
mod dashboard;
|
||||
#[cfg(feature = "mem-prof")]
|
||||
pub mod mem_prof;
|
||||
|
||||
@@ -477,6 +479,11 @@ impl HttpServer {
|
||||
routing::get(handler::health).post(handler::health),
|
||||
);
|
||||
|
||||
#[cfg(feature = "dashboard")]
|
||||
{
|
||||
router = router.nest("/dashboard", dashboard::dashboard());
|
||||
}
|
||||
|
||||
router
|
||||
// middlewares
|
||||
.layer(
|
||||
|
||||
56
src/servers/src/http/dashboard.rs
Normal file
56
src/servers/src/http/dashboard.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2023 Greptime Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use axum::body::{boxed, Full};
|
||||
use axum::http::{header, StatusCode, Uri};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use axum::routing::Router;
|
||||
use common_telemetry::debug;
|
||||
use rust_embed::RustEmbed;
|
||||
use snafu::ResultExt;
|
||||
|
||||
use crate::error::{BuildHttpResponseSnafu, Result};
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "dashboard/"]
|
||||
pub struct Assets;
|
||||
|
||||
pub(crate) fn dashboard() -> Router {
|
||||
Router::new().fallback(static_handler)
|
||||
}
|
||||
|
||||
#[axum_macros::debug_handler]
|
||||
async fn static_handler(uri: Uri) -> Result<impl IntoResponse> {
|
||||
debug!("[dashboard] requesting: {}", uri.path());
|
||||
|
||||
let mut path = uri.path().trim_start_matches('/');
|
||||
if path.is_empty() {
|
||||
path = "index.html";
|
||||
}
|
||||
|
||||
match Assets::get(path) {
|
||||
Some(content) => {
|
||||
let body = boxed(Full::from(content.data));
|
||||
let mime = mime_guess::from_path(path).first_or_octet_stream();
|
||||
|
||||
Response::builder()
|
||||
.header(header::CONTENT_TYPE, mime.as_ref())
|
||||
.body(body)
|
||||
}
|
||||
None => Response::builder()
|
||||
.status(StatusCode::NOT_FOUND)
|
||||
.body(boxed(Full::from("404"))),
|
||||
}
|
||||
.context(BuildHttpResponseSnafu)
|
||||
}
|
||||
Reference in New Issue
Block a user