diff --git a/visualizer/Cargo.lock b/visualizer/Cargo.lock index e19297a9a..b165174eb 100644 --- a/visualizer/Cargo.lock +++ b/visualizer/Cargo.lock @@ -273,6 +273,46 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "amplify" +version = "3.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba2ec14f4fb838e9ddace42fa5944bb1ee4dff8477494ba48c5f874e16caf27a" +dependencies = [ + "amplify_derive", + "amplify_num", + "wasm-bindgen", +] + +[[package]] +name = "amplify_derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c3de270e75f27a4468a7c344070109046656e85cb522141f7d40ab4b83803ac" +dependencies = [ + "amplify_syn", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "amplify_num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27d3d00d3d115395a7a8a4dc045feb7aa82b641e485f7e15f4e67ac16f4f56d" + +[[package]] +name = "amplify_syn" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da24db1445cc7bc3842fa072c2d51fe5b25b812b6a572d65842a4c72e87221ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -326,17 +366,6 @@ dependencies = [ "syn", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -409,6 +438,27 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blockscout-service-launcher" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fc9022734a46409fd0e33659b7e48eff5bc1235a087f6d1f6fb7a4fbcb02d8" +dependencies = [ + "actix-web", + "actix-web-prom", + "anyhow", + "futures", + "opentelemetry", + "opentelemetry-jaeger", + "prometheus", + "serde", + "tokio", + "tonic", + "tracing", + "tracing-opentelemetry", + "tracing-subscriber", +] + [[package]] name = "brotli" version = "3.3.4" @@ -736,19 +786,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "env_logger" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "fastrand" version = "1.8.0" @@ -988,12 +1025,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "0.14.20" @@ -1336,9 +1367,9 @@ checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" [[package]] name = "opentelemetry" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d6c3d7288a106c0a363e4b0e8d308058d56902adefb16f4936f417ffef086e" +checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f" dependencies = [ "opentelemetry_api", "opentelemetry_sdk", @@ -1346,9 +1377,9 @@ dependencies = [ [[package]] name = "opentelemetry-jaeger" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e785d273968748578931e4dc3b4f5ec86b26e09d9e0d66b55adda7fce742f7a" +checksum = "08e028dc9f4f304e9320ce38c80e7cf74067415b1ad5a8750a38bae54a4d450d" dependencies = [ "async-trait", "futures", @@ -1363,34 +1394,34 @@ dependencies = [ [[package]] name = "opentelemetry-semantic-conventions" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b02e0230abb0ab6636d18e2ba8fa02903ea63772281340ccac18e0af3ec9eeb" +checksum = "24e33428e6bf08c6f7fcea4ddb8e358fab0fe48ab877a87c70c6ebe20f673ce5" dependencies = [ "opentelemetry", ] [[package]] name = "opentelemetry_api" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c24f96e21e7acc813c7a8394ee94978929db2bcc46cf6b5014fc612bf7760c22" +checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2" dependencies = [ "fnv", "futures-channel", "futures-util", "indexmap", - "js-sys", "once_cell", "pin-project-lite", "thiserror", + "urlencoding", ] [[package]] name = "opentelemetry_sdk" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca41c4933371b61c2a2f214bf16931499af4ec90543604ec828f7a625c09113" +checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" dependencies = [ "async-trait", "crossbeam-channel", @@ -1410,9 +1441,9 @@ dependencies = [ [[package]] name = "ordered-float" -version = "1.1.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" dependencies = [ "num-traits", ] @@ -2002,9 +2033,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.102" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -2080,9 +2111,9 @@ dependencies = [ [[package]] name = "thrift" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09678c4cdbb4eed72e18b7c2af1329c69825ed16fcbac62d083fc3e2b0590ff0" +checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09" dependencies = [ "byteorder", "integer-encoding", @@ -2353,9 +2384,9 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21ebb87a95ea13271332df069020513ab70bdb5637ca42d6e492dc3bbbad48de" +checksum = "00a39dcf9bfc1742fa4d6215253b33a6e474be78275884c216fc2a06267b3600" dependencies = [ "once_cell", "opentelemetry", @@ -2365,6 +2396,16 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.16" @@ -2375,12 +2416,15 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", + "tracing-serde", ] [[package]] @@ -2445,6 +2489,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "valuable" version = "0.1.0" @@ -2462,7 +2512,6 @@ name = "visualizer" version = "0.1.0" dependencies = [ "anyhow", - "bytes", "futures", "lazy_static", "prometheus", @@ -2474,29 +2523,37 @@ dependencies = [ ] [[package]] -name = "visualizer-server" +name = "visualizer-proto" version = "0.1.0" dependencies = [ "actix-prost", "actix-prost-build", "actix-prost-macros", "actix-web", - "actix-web-prom", + "prost", + "prost-build", + "serde", + "serde_with", + "tonic", + "tonic-build", +] + +[[package]] +name = "visualizer-server" +version = "0.1.0" +dependencies = [ + "actix-prost-build", + "actix-web", + "amplify", "anyhow", "assert-str", "async-trait", + "blockscout-service-launcher", "bytes", "config", - "env_logger", - "futures", "lazy_static", - "opentelemetry", - "opentelemetry-jaeger", "pretty_assertions", - "prometheus", - "prost", "prost-build", - "prost-types", "regex", "serde", "serde_json", @@ -2505,9 +2562,8 @@ dependencies = [ "tonic", "tonic-build", "tracing", - "tracing-opentelemetry", - "tracing-subscriber", "visualizer", + "visualizer-proto", "walkdir", ] diff --git a/visualizer/Cargo.toml b/visualizer/Cargo.toml index 6d54599b2..665829b63 100644 --- a/visualizer/Cargo.toml +++ b/visualizer/Cargo.toml @@ -2,5 +2,6 @@ resolver = "2" members = [ "visualizer", - "visualizer-server" + "visualizer-server", + "visualizer-proto" ] diff --git a/visualizer/visualizer-proto/Cargo.toml b/visualizer/visualizer-proto/Cargo.toml new file mode 100644 index 000000000..7baf7ca45 --- /dev/null +++ b/visualizer/visualizer-proto/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "visualizer-proto" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +actix-web = "4" +actix-prost = { git = "https://github.com/blockscout/actix-prost" } +actix-prost-macros = { git = "https://github.com/blockscout/actix-prost" } +prost = "0.11" +serde = { version = "1", features = ["derive"] } +serde_with = { version = "2.0", features = ["hex", "base64"] } +tonic = "0.8" + +[build-dependencies] +actix-prost-build = { git = "https://github.com/blockscout/actix-prost" } +tonic-build = "0.8" +prost-build = "0.11" \ No newline at end of file diff --git a/visualizer/visualizer-server/build.rs b/visualizer/visualizer-proto/build.rs similarity index 100% rename from visualizer/visualizer-server/build.rs rename to visualizer/visualizer-proto/build.rs diff --git a/visualizer/visualizer-server/proto/api_config_http.yaml b/visualizer/visualizer-proto/proto/api_config_http.yaml similarity index 100% rename from visualizer/visualizer-server/proto/api_config_http.yaml rename to visualizer/visualizer-proto/proto/api_config_http.yaml diff --git a/visualizer/visualizer-server/proto/health.proto b/visualizer/visualizer-proto/proto/health.proto similarity index 100% rename from visualizer/visualizer-server/proto/health.proto rename to visualizer/visualizer-proto/proto/health.proto diff --git a/visualizer/visualizer-server/proto/visualizer.proto b/visualizer/visualizer-proto/proto/visualizer.proto similarity index 100% rename from visualizer/visualizer-server/proto/visualizer.proto rename to visualizer/visualizer-proto/proto/visualizer.proto diff --git a/visualizer/visualizer-proto/src/lib.rs b/visualizer/visualizer-proto/src/lib.rs new file mode 100644 index 000000000..f076f2b5a --- /dev/null +++ b/visualizer/visualizer-proto/src/lib.rs @@ -0,0 +1,15 @@ +#![allow(clippy::derive_partial_eq_without_eq)] + +pub mod blockscout { + pub mod visualizer { + pub mod v1 { + include!(concat!(env!("OUT_DIR"), "/blockscout.visualizer.v1.rs")); + } + } +} + +pub mod google { + pub mod protobuf { + include!(concat!(env!("OUT_DIR"), "/google.protobuf.rs")); + } +} diff --git a/visualizer/visualizer-server/swagger/visualizer.swagger.yaml b/visualizer/visualizer-proto/swagger/visualizer.swagger.yaml similarity index 98% rename from visualizer/visualizer-server/swagger/visualizer.swagger.yaml rename to visualizer/visualizer-proto/swagger/visualizer.swagger.yaml index 91b4f5da5..2820cfc07 100644 --- a/visualizer/visualizer-server/swagger/visualizer.swagger.yaml +++ b/visualizer/visualizer-proto/swagger/visualizer.swagger.yaml @@ -81,6 +81,7 @@ definitions: - NOT_SERVING - SERVICE_UNKNOWN default: UNKNOWN + description: ' - SERVICE_UNKNOWN: Used only by the Watch method.' protobufAny: type: object properties: @@ -93,12 +94,12 @@ definitions: code: type: integer format: int32 + message: + type: string details: type: array items: $ref: '#/definitions/protobufAny' - message: - type: string v1HealthCheckResponse: type: object properties: @@ -107,12 +108,12 @@ definitions: v1VisualizeContractsRequest: type: object properties: - outputMask: - type: string sources: type: object additionalProperties: type: string + outputMask: + type: string v1VisualizeResponse: type: object properties: @@ -129,13 +130,13 @@ definitions: v1VisualizeStorageRequest: type: object properties: - contractName: - type: string - fileName: - type: string - outputMask: - type: string sources: type: object additionalProperties: type: string + fileName: + type: string + contractName: + type: string + outputMask: + type: string diff --git a/visualizer/visualizer-server/Cargo.toml b/visualizer/visualizer-server/Cargo.toml index 073104542..7270b2482 100644 --- a/visualizer/visualizer-server/Cargo.toml +++ b/visualizer/visualizer-server/Cargo.toml @@ -10,32 +10,22 @@ doctest = false [dependencies] visualizer = { path = "../visualizer" } +visualizer-proto = { path = "../visualizer-proto" } -# we're not released yet -actix-prost = { git = "https://github.com/blockscout/actix-prost" } -actix-prost-macros = { git = "https://github.com/blockscout/actix-prost" } actix-web = "4" -actix-web-prom = "0.6" +amplify = { version = "3.13.0", features = ["derive"] } anyhow = "1.0" async-trait = "0.1" +blockscout-service-launcher = { version = "0.8.0" } bytes = "1.2" config = "0.13" -env_logger = "0.9" -futures = "0.3" lazy_static = "1.3" -opentelemetry = {version = "0.18", features = ["rt-tokio"]} -opentelemetry-jaeger = { version = "0.17", features = ["rt-tokio"] } -prometheus = "0.13" -prost = "0.11" -prost-types = "0.11" regex = "1.7" serde = { version = "1", features = ["derive"] } serde_with = { version = "2.0", features = ["hex", "base64"] } tokio = "1.21" tonic = "0.8" tracing = "0.1" -tracing-opentelemetry = "0.18" -tracing-subscriber = {version = "0.3", features = ["env-filter"]} [dev-dependencies] pretty_assertions = "1.3" diff --git a/visualizer/visualizer-server/config/base.toml b/visualizer/visualizer-server/config/base.toml index 47e461b86..81203dbe1 100644 --- a/visualizer/visualizer-server/config/base.toml +++ b/visualizer/visualizer-server/config/base.toml @@ -3,5 +3,5 @@ enabled = true addr = "0.0.0.0:8050" [server.grpc] -enabled = true +enabled = false addr = "0.0.0.0:8051" diff --git a/visualizer/visualizer-server/src/lib.rs b/visualizer/visualizer-server/src/lib.rs index f178596c3..b5bac1f94 100644 --- a/visualizer/visualizer-server/src/lib.rs +++ b/visualizer/visualizer-server/src/lib.rs @@ -1,12 +1,9 @@ -pub mod run; - -mod health; -mod metrics; mod proto; +mod server; +mod services; mod settings; -mod solidity; -mod tracer; +mod types; -pub use health::HealthService; +pub use server::run; +pub use services::SolidityVisualizerService; pub use settings::Settings; -pub use solidity::{route_solidity_visualizer, SolidityVisualizerService}; diff --git a/visualizer/visualizer-server/src/main.rs b/visualizer/visualizer-server/src/main.rs index 5a2c7b9db..bf7b65465 100644 --- a/visualizer/visualizer-server/src/main.rs +++ b/visualizer/visualizer-server/src/main.rs @@ -3,5 +3,5 @@ use visualizer_server::Settings; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { let settings = Settings::new().expect("failed to read config"); - visualizer_server::run::sol2uml(settings).await + visualizer_server::run(settings).await } diff --git a/visualizer/visualizer-server/src/metrics.rs b/visualizer/visualizer-server/src/metrics.rs deleted file mode 100644 index 6473197e8..000000000 --- a/visualizer/visualizer-server/src/metrics.rs +++ /dev/null @@ -1,42 +0,0 @@ -use actix_web::{dev::Server, App, HttpServer}; -use actix_web_prom::{PrometheusMetrics, PrometheusMetricsBuilder}; -use std::net::SocketAddr; - -#[derive(Clone)] -pub struct Metrics { - metrics_middleware: PrometheusMetrics, - visualizer_middleware: PrometheusMetrics, -} - -impl Metrics { - pub fn new(endpoint: String) -> Self { - let regustry = prometheus::default_registry(); - let metrics_middleware = PrometheusMetricsBuilder::new("visualizer_metrics") - .registry(regustry.clone()) - .endpoint(&endpoint) - .build() - .unwrap(); - let visualizer_middleware = PrometheusMetricsBuilder::new("visualizer") - .registry(regustry.clone()) - .build() - .unwrap(); - - Self { - metrics_middleware, - visualizer_middleware, - } - } - - pub fn middleware(&self) -> &PrometheusMetrics { - &self.visualizer_middleware - } - - pub fn run_server(&self, addr: SocketAddr) -> Server { - tracing::info!(addr = ?addr, "starting metris server"); - let metrics_middleware = self.metrics_middleware.clone(); - HttpServer::new(move || App::new().wrap(metrics_middleware.clone())) - .bind(addr) - .unwrap() - .run() - } -} diff --git a/visualizer/visualizer-server/src/proto.rs b/visualizer/visualizer-server/src/proto.rs index f076f2b5a..67cf66a92 100644 --- a/visualizer/visualizer-server/src/proto.rs +++ b/visualizer/visualizer-server/src/proto.rs @@ -1,15 +1,8 @@ -#![allow(clippy::derive_partial_eq_without_eq)] - -pub mod blockscout { - pub mod visualizer { - pub mod v1 { - include!(concat!(env!("OUT_DIR"), "/blockscout.visualizer.v1.rs")); - } - } -} - -pub mod google { - pub mod protobuf { - include!(concat!(env!("OUT_DIR"), "/google.protobuf.rs")); - } -} +pub use visualizer_proto::{ + blockscout::visualizer::v1::{ + health_actix, health_check_response, health_server, solidity_visualizer_actix, + solidity_visualizer_server, HealthCheckRequest, HealthCheckResponse, + VisualizeContractsRequest, VisualizeResponse, VisualizeStorageRequest, + }, + google::protobuf::FieldMask, +}; diff --git a/visualizer/visualizer-server/src/run.rs b/visualizer/visualizer-server/src/run.rs deleted file mode 100644 index d7e26758e..000000000 --- a/visualizer/visualizer-server/src/run.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::{ - health::HealthService, - metrics::Metrics, - proto::blockscout::visualizer::v1::{ - health_actix::route_health, health_server::HealthServer, - solidity_visualizer_server::SolidityVisualizerServer, - }, - solidity::{route_solidity_visualizer, SolidityVisualizerService}, - tracer::init_logs, - Settings, -}; -use actix_web::{dev::Server, App, HttpServer}; -use actix_web_prom::PrometheusMetrics; -use std::{net::SocketAddr, sync::Arc}; - -pub fn http_server( - visualizer: Arc, - health: Arc, - metrics: PrometheusMetrics, - addr: SocketAddr, -) -> Server { - tracing::info!("starting http server on addr {}", addr); - let server = HttpServer::new(move || { - App::new() - .wrap(metrics.clone()) - .configure(|config| route_solidity_visualizer(config, visualizer.clone())) - .configure(|config| route_health(config, health.clone())) - }) - .bind(addr) - .unwrap_or_else(|_| panic!("failed to bind server")); - - server.run() -} - -pub async fn grpc_server( - visualizer: Arc, - health: Arc, - addr: SocketAddr, -) -> Result<(), anyhow::Error> { - tracing::info!("starting grpc server on addr {}", addr); - let server = tonic::transport::Server::builder() - .add_service(SolidityVisualizerServer::from_arc(visualizer)) - .add_service(HealthServer::from_arc(health)); - - server.serve(addr).await?; - Ok(()) -} - -pub async fn sol2uml(settings: Settings) -> Result<(), anyhow::Error> { - init_logs(settings.jaeger); - - let visualizer = Arc::new(SolidityVisualizerService::default()); - let health = Arc::new(HealthService::default()); - let metrics = Metrics::new(settings.metrics.route); - let mut futures = vec![]; - - if settings.server.http.enabled { - let http_server = { - let http_server_future = http_server( - visualizer.clone(), - health.clone(), - metrics.middleware().clone(), - settings.server.http.addr, - ); - tokio::spawn(async move { http_server_future.await.map_err(anyhow::Error::msg) }) - }; - futures.push(http_server) - } - - if settings.server.grpc.enabled { - let grpc_server = { - let service = visualizer.clone(); - tokio::spawn( - async move { grpc_server(service, health, settings.server.grpc.addr).await }, - ) - }; - futures.push(grpc_server) - } - - if settings.metrics.enabled { - futures.push(tokio::spawn(async move { - metrics.run_server(settings.metrics.addr).await?; - Ok(()) - })) - } - - let (res, _, others) = futures::future::select_all(futures).await; - for future in others.into_iter() { - future.abort() - } - res? -} diff --git a/visualizer/visualizer-server/src/server.rs b/visualizer/visualizer-server/src/server.rs new file mode 100644 index 000000000..7a54d3812 --- /dev/null +++ b/visualizer/visualizer-server/src/server.rs @@ -0,0 +1,52 @@ +use crate::{ + proto::{health_server::HealthServer, solidity_visualizer_server::SolidityVisualizerServer}, + services::{HealthService, SolidityVisualizerService}, + settings::Settings, +}; +use blockscout_service_launcher::{launcher, launcher::LaunchSettings, tracing}; +use std::sync::Arc; +use visualizer_proto::blockscout::visualizer::v1::{ + health_actix::route_health, solidity_visualizer_actix::route_solidity_visualizer, +}; + +const SERVICE_NAME: &str = "visualizer"; + +#[derive(Clone)] +struct Router { + visualizer: Arc, + health: Arc, +} + +impl Router { + pub fn grpc_router(&self) -> tonic::transport::server::Router { + tonic::transport::Server::builder() + .add_service(SolidityVisualizerServer::from_arc(self.visualizer.clone())) + .add_service(HealthServer::from_arc(self.health.clone())) + } +} + +impl launcher::HttpRouter for Router { + fn register_routes(&self, service_config: &mut actix_web::web::ServiceConfig) { + service_config.configure(|config| route_health(config, self.health.clone())); + service_config + .configure(|config| route_solidity_visualizer(config, self.visualizer.clone())); + } +} + +pub async fn run(settings: Settings) -> Result<(), anyhow::Error> { + tracing::init_logs(SERVICE_NAME, &settings.tracing, &settings.jaeger)?; + + let visualizer = Arc::new(SolidityVisualizerService::default()); + let health = Arc::new(HealthService::default()); + + let router = Router { visualizer, health }; + let grpc_router = router.grpc_router(); + let http_router = router; + + let launch_settings = LaunchSettings { + service_name: SERVICE_NAME.to_owned(), + server: settings.server, + metrics: settings.metrics, + }; + launcher::launch(&launch_settings, http_router, grpc_router).await +} diff --git a/visualizer/visualizer-server/src/health.rs b/visualizer/visualizer-server/src/services/health.rs similarity index 78% rename from visualizer/visualizer-server/src/health.rs rename to visualizer/visualizer-server/src/services/health.rs index 560274b45..ea79b4363 100644 --- a/visualizer/visualizer-server/src/health.rs +++ b/visualizer/visualizer-server/src/services/health.rs @@ -1,9 +1,7 @@ -use crate::proto::blockscout::visualizer::v1::{ +use crate::proto::{ health_check_response, health_server::Health, HealthCheckRequest, HealthCheckResponse, }; -pub use crate::proto::blockscout::visualizer::v1::health_actix::route_health; - #[derive(Default)] pub struct HealthService {} @@ -14,7 +12,7 @@ impl Health for HealthService { _request: tonic::Request, ) -> Result, tonic::Status> { Ok(tonic::Response::new(HealthCheckResponse { - status: health_check_response::ServingStatus::Serving as i32, + status: health_check_response::ServingStatus::Serving.into(), })) } } diff --git a/visualizer/visualizer-server/src/services/mod.rs b/visualizer/visualizer-server/src/services/mod.rs new file mode 100644 index 000000000..4b1ad8e5d --- /dev/null +++ b/visualizer/visualizer-server/src/services/mod.rs @@ -0,0 +1,5 @@ +mod health; +mod solidity_visualizer; + +pub use health::HealthService; +pub use solidity_visualizer::SolidityVisualizerService; diff --git a/visualizer/visualizer-server/src/solidity/server.rs b/visualizer/visualizer-server/src/services/solidity_visualizer.rs similarity index 63% rename from visualizer/visualizer-server/src/solidity/server.rs rename to visualizer/visualizer-server/src/services/solidity_visualizer.rs index 7c347a467..300c0158e 100644 --- a/visualizer/visualizer-server/src/solidity/server.rs +++ b/visualizer/visualizer-server/src/services/solidity_visualizer.rs @@ -1,23 +1,28 @@ -use crate::proto::blockscout::visualizer::v1::{ - solidity_visualizer_server::SolidityVisualizer, VisualizeContractsRequest, VisualizeResponse, - VisualizeStorageRequest, +use crate::{ + proto::{ + solidity_visualizer_server::SolidityVisualizer, VisualizeContractsRequest, + VisualizeResponse, VisualizeStorageRequest, + }, + types::{ + VisualizeContractsRequestWrapper, VisualizeResponseWrapper, VisualizeStorageRequestWrapper, + }, }; +use async_trait::async_trait; #[derive(Default)] pub struct SolidityVisualizerService {} -#[async_trait::async_trait] +#[async_trait] impl SolidityVisualizer for SolidityVisualizerService { #[tracing::instrument(skip(self, request), level = "info")] async fn visualize_contracts( &self, request: tonic::Request, ) -> Result, tonic::Status> { - let request = visualizer::VisualizeContractsRequest::try_from(request.into_inner()) - .map_err(|e| tonic::Status::invalid_argument(e.to_string()))?; - let result = visualizer::visualize_contracts(request).await; + let request: VisualizeContractsRequestWrapper = request.into_inner().into(); + let result = visualizer::visualize_contracts(request.try_into()?).await; result - .map(|response| tonic::Response::new(response.into())) + .map(|response| tonic::Response::new(VisualizeResponseWrapper::from(response).into())) .map_err(|error| match error { visualizer::VisualizeContractsError::Internal(e) => { tonic::Status::internal(e.to_string()) @@ -33,11 +38,10 @@ impl SolidityVisualizer for SolidityVisualizerService { &self, request: tonic::Request, ) -> Result, tonic::Status> { - let request = visualizer::VisualizeStorageRequest::try_from(request.into_inner()) - .map_err(|e| tonic::Status::invalid_argument(e.to_string()))?; - let result = visualizer::visualize_storage(request).await; + let request: VisualizeStorageRequestWrapper = request.into_inner().into(); + let result = visualizer::visualize_storage(request.try_into()?).await; result - .map(|response| tonic::Response::new(response.into())) + .map(|response| tonic::Response::new(VisualizeResponseWrapper::from(response).into())) .map_err(|error| match error { visualizer::VisualizeStorageError::Internal(e) => { tonic::Status::internal(e.to_string()) diff --git a/visualizer/visualizer-server/src/settings.rs b/visualizer/visualizer-server/src/settings.rs index b335771f0..15ae00365 100644 --- a/visualizer/visualizer-server/src/settings.rs +++ b/visualizer/visualizer-server/src/settings.rs @@ -1,6 +1,9 @@ +use blockscout_service_launcher::{ + launcher::{MetricsSettings, ServerSettings}, + tracing::{JaegerSettings, TracingSettings}, +}; use config::{Config, File}; use serde::{de, Deserialize}; -use std::{net::SocketAddr, str::FromStr}; /// Wrapper under [`serde::de::IgnoredAny`] which implements /// [`PartialEq`] and [`Eq`] for fields to be ignored. @@ -22,6 +25,7 @@ pub struct Settings { pub server: ServerSettings, pub metrics: MetricsSettings, pub jaeger: JaegerSettings, + pub tracing: TracingSettings, // Is required as we deny unknown fields, but allow users provide // path to config through PREFIX__CONFIG env variable. If removed, @@ -30,79 +34,6 @@ pub struct Settings { config_path: IgnoredAny, } -#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq)] -#[serde(default, deny_unknown_fields)] -pub struct ServerSettings { - pub http: HttpServerSettings, - pub grpc: GrpcServerSettings, -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(default, deny_unknown_fields)] -pub struct HttpServerSettings { - pub enabled: bool, - pub addr: SocketAddr, -} - -impl Default for HttpServerSettings { - fn default() -> Self { - Self { - enabled: true, - addr: SocketAddr::from_str("0.0.0.0:8050").expect("valid addr"), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(default, deny_unknown_fields)] -pub struct GrpcServerSettings { - pub enabled: bool, - pub addr: SocketAddr, -} - -impl Default for GrpcServerSettings { - fn default() -> Self { - Self { - enabled: true, - addr: SocketAddr::from_str("0.0.0.0:8051").expect("valid addr"), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(default, deny_unknown_fields)] -pub struct MetricsSettings { - pub enabled: bool, - pub addr: SocketAddr, - pub route: String, -} - -impl Default for MetricsSettings { - fn default() -> Self { - Self { - enabled: false, - addr: SocketAddr::from_str("0.0.0.0:6060").expect("should be valid url"), - route: "/metrics".to_string(), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(default, deny_unknown_fields)] -pub struct JaegerSettings { - pub enabled: bool, - pub agent_endpoint: String, -} - -impl Default for JaegerSettings { - fn default() -> Self { - Self { - enabled: false, - agent_endpoint: "localhost:6831".to_string(), - } - } -} - impl Settings { pub fn new() -> anyhow::Result { let config_path = std::env::var("VISUALIZER__CONFIG"); diff --git a/visualizer/visualizer-server/src/solidity/mod.rs b/visualizer/visualizer-server/src/solidity/mod.rs deleted file mode 100644 index 7a81541f9..000000000 --- a/visualizer/visualizer-server/src/solidity/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod server; -mod types; - -pub use crate::proto::blockscout::visualizer::v1::solidity_visualizer_actix::route_solidity_visualizer; -pub use server::SolidityVisualizerService; diff --git a/visualizer/visualizer-server/src/tracer.rs b/visualizer/visualizer-server/src/tracer.rs deleted file mode 100644 index 70dbdb70e..000000000 --- a/visualizer/visualizer-server/src/tracer.rs +++ /dev/null @@ -1,44 +0,0 @@ -use opentelemetry::{ - global::{self}, - sdk::{self, propagation::TraceContextPropagator}, - trace::TraceError, -}; -use tracing_subscriber::{filter::LevelFilter, layer::SubscriberExt, prelude::*}; - -use crate::settings::JaegerSettings; - -pub fn init_logs(jaeger_settings: JaegerSettings) { - let stdout = tracing_subscriber::fmt::layer().with_filter( - tracing_subscriber::EnvFilter::builder() - .with_default_directive(LevelFilter::INFO.into()) - .from_env_lossy(), - ); - let registry = tracing_subscriber::registry() - // output logs (tracing) to stdout with log level taken from env (default is INFO) - .with(stdout); - if jaeger_settings.enabled { - let tracer = - init_jaeger_tracer(&jaeger_settings.agent_endpoint).expect("failed to init tracer"); - registry - // output traces to jaeger with default log level (default is DEBUG) - .with( - tracing_opentelemetry::layer() - .with_tracer(tracer) - .with_filter(LevelFilter::DEBUG), - ) - .try_init() - } else { - registry.try_init() - } - .expect("failed to register tracer with registry"); -} - -pub fn init_jaeger_tracer(endpoint: &str) -> Result { - global::set_text_map_propagator(TraceContextPropagator::new()); - - opentelemetry_jaeger::new_agent_pipeline() - .with_service_name("visualizer") - .with_endpoint(endpoint) - .with_auto_split_batch(true) - .install_batch(opentelemetry::runtime::Tokio) -} diff --git a/visualizer/visualizer-server/src/types/mod.rs b/visualizer/visualizer-server/src/types/mod.rs new file mode 100644 index 000000000..2f7fe22aa --- /dev/null +++ b/visualizer/visualizer-server/src/types/mod.rs @@ -0,0 +1,8 @@ +mod util; +mod visualize_contracts; +mod visualize_response; +mod visualize_storage; + +pub use visualize_contracts::VisualizeContractsRequestWrapper; +pub use visualize_response::VisualizeResponseWrapper; +pub use visualize_storage::VisualizeStorageRequestWrapper; diff --git a/visualizer/visualizer-server/src/solidity/types.rs b/visualizer/visualizer-server/src/types/util.rs similarity index 78% rename from visualizer/visualizer-server/src/solidity/types.rs rename to visualizer/visualizer-server/src/types/util.rs index 17e5157fc..71ef80e28 100644 --- a/visualizer/visualizer-server/src/solidity/types.rs +++ b/visualizer/visualizer-server/src/types/util.rs @@ -1,10 +1,4 @@ -use crate::proto::{ - blockscout::visualizer::v1::{ - VisualizeContractsRequest, VisualizeResponse, VisualizeStorageRequest, - }, - google::protobuf::FieldMask, -}; -use bytes::Bytes; +use crate::proto::FieldMask; use lazy_static::lazy_static; use regex::{Regex, RegexBuilder}; use std::{ @@ -22,14 +16,14 @@ lazy_static! { static ref REGEX_NO_DOTS: Regex = Regex::new(r"(^|/)[.]+($|/)").unwrap(); } -fn sources(sources: HashMap) -> BTreeMap { +pub fn sources(sources: HashMap) -> BTreeMap { sources .into_iter() .map(|(path, content)| (PathBuf::from(path), content)) .collect() } -fn output_mask(field_mask: Option) -> Result { +pub fn output_mask(field_mask: Option) -> Result { let mut output_mask: OutputMask = field_mask .map(|mask| { mask.paths @@ -39,14 +33,14 @@ fn output_mask(field_mask: Option) -> Result) -> BTreeMap { +pub fn fix_sources_paths(sources: BTreeMap) -> BTreeMap { sources .into_iter() .map(|(path, content)| { @@ -65,44 +59,12 @@ fn fix_sources_paths(sources: BTreeMap) -> BTreeMap String { +pub fn sanitize_path(path: &str) -> String { let path = REGEX_ONLY_CHARS.replace_all(path, "_"); let path = REGEX_NO_DOTS.replace_all(path.as_ref(), "_"); path.to_string() } -impl TryFrom for visualizer::VisualizeContractsRequest { - type Error = anyhow::Error; - - fn try_from(request: VisualizeContractsRequest) -> Result { - Ok(Self { - sources: fix_sources_paths(sources(request.sources)), - output_mask: output_mask(request.output_mask)?, - }) - } -} - -impl TryFrom for visualizer::VisualizeStorageRequest { - type Error = anyhow::Error; - - fn try_from(request: VisualizeStorageRequest) -> Result { - Ok(Self { - sources: fix_sources_paths(sources(request.sources)), - file_path: PathBuf::from(request.file_name), - contract_name: request.contract_name, - output_mask: output_mask(request.output_mask)?, - }) - } -} - -impl From for VisualizeResponse { - fn from(response: visualizer::Response) -> Self { - Self { - png: response.png.map(Bytes::from), - svg: response.svg.map(Bytes::from), - } - } -} #[cfg(test)] mod tests { use super::*; diff --git a/visualizer/visualizer-server/src/types/visualize_contracts.rs b/visualizer/visualizer-server/src/types/visualize_contracts.rs new file mode 100644 index 000000000..cec69c595 --- /dev/null +++ b/visualizer/visualizer-server/src/types/visualize_contracts.rs @@ -0,0 +1,19 @@ +use super::util::{fix_sources_paths, output_mask, sources}; +use crate::proto; +use amplify::{From, Wrapper}; + +#[derive(Wrapper, From, Clone, Debug, PartialEq)] +pub struct VisualizeContractsRequestWrapper(proto::VisualizeContractsRequest); + +impl TryFrom for visualizer::VisualizeContractsRequest { + type Error = tonic::Status; + + fn try_from(request: VisualizeContractsRequestWrapper) -> Result { + let request = request.0; + Ok(Self { + sources: fix_sources_paths(sources(request.sources)), + output_mask: output_mask(request.output_mask) + .map_err(|e| tonic::Status::invalid_argument(e.to_string()))?, + }) + } +} diff --git a/visualizer/visualizer-server/src/types/visualize_response.rs b/visualizer/visualizer-server/src/types/visualize_response.rs new file mode 100644 index 000000000..7c360352c --- /dev/null +++ b/visualizer/visualizer-server/src/types/visualize_response.rs @@ -0,0 +1,15 @@ +use crate::proto; +use amplify::{From, Wrapper}; +use bytes::Bytes; + +#[derive(Wrapper, From, Clone, Debug, PartialEq)] +pub struct VisualizeResponseWrapper(proto::VisualizeResponse); + +impl From for VisualizeResponseWrapper { + fn from(response: visualizer::Response) -> Self { + Self(proto::VisualizeResponse { + png: response.png.map(Bytes::from), + svg: response.svg.map(Bytes::from), + }) + } +} diff --git a/visualizer/visualizer-server/src/types/visualize_storage.rs b/visualizer/visualizer-server/src/types/visualize_storage.rs new file mode 100644 index 000000000..f3b7b1cfa --- /dev/null +++ b/visualizer/visualizer-server/src/types/visualize_storage.rs @@ -0,0 +1,22 @@ +use super::util::{fix_sources_paths, output_mask, sources}; +use crate::proto; +use amplify::{From, Wrapper}; +use std::path::PathBuf; + +#[derive(Wrapper, From, Clone, Debug, PartialEq)] +pub struct VisualizeStorageRequestWrapper(proto::VisualizeStorageRequest); + +impl TryFrom for visualizer::VisualizeStorageRequest { + type Error = tonic::Status; + + fn try_from(request: VisualizeStorageRequestWrapper) -> Result { + let request = request.0; + Ok(Self { + sources: fix_sources_paths(sources(request.sources)), + file_path: PathBuf::from(request.file_name), + contract_name: request.contract_name, + output_mask: output_mask(request.output_mask) + .map_err(|e| tonic::Status::invalid_argument(e.to_string()))?, + }) + } +} diff --git a/visualizer/visualizer-server/tests/solidity.rs b/visualizer/visualizer-server/tests/solidity.rs index 4e3296af4..20a63ebe8 100644 --- a/visualizer/visualizer-server/tests/solidity.rs +++ b/visualizer/visualizer-server/tests/solidity.rs @@ -8,7 +8,8 @@ use bytes::Bytes; use serde::Deserialize; use serde_json::json; use serde_with::serde_as; -use visualizer_server::{route_solidity_visualizer, SolidityVisualizerService}; +use visualizer_proto::blockscout::visualizer::v1::solidity_visualizer_actix::route_solidity_visualizer; +use visualizer_server::SolidityVisualizerService; use std::{collections::BTreeMap, fs, path::PathBuf, str::from_utf8, sync::Arc}; use walkdir::WalkDir; diff --git a/visualizer/visualizer/Cargo.toml b/visualizer/visualizer/Cargo.toml index 6478ab1a9..fcc3d2348 100644 --- a/visualizer/visualizer/Cargo.toml +++ b/visualizer/visualizer/Cargo.toml @@ -6,7 +6,6 @@ repository = "https://github.com/blockscout/blockscout-rs/sol_to_uml" [dependencies] anyhow = "1.0" -bytes = "1.2" futures = "0.3" lazy_static = "1.3" prometheus = "0.13"