From d39b24a8a295107fe92898572c15ef00b938cc7d Mon Sep 17 00:00:00 2001 From: thuan2172001 <thuan2172001@gmail.com> Date: Wed, 13 Mar 2024 22:22:38 +0700 Subject: [PATCH] fix: docker flow --- .github/workflows/ci.yaml | 2 - .github/workflows/docker.yml | 17 +++++ Cargo.lock | 73 +++++++++---------- Cargo.toml | 2 +- Dockerfile | 1 + src/adapter/Cargo.toml | 8 +- src/adapter/src/repositories/grpc/config.rs | 6 ++ src/adapter/src/repositories/grpc/mod.rs | 2 + .../repositories/grpc/models}/gpt_answer.rs | 17 ++--- .../src/repositories/grpc/models/mod.rs | 1 + src/adapter/src/repositories/mod.rs | 1 + .../repositories/postgres/models/question.rs | 32 +++++--- .../src/repositories/postgres/question_db.rs | 14 ++-- src/grpc/Cargo.toml | 16 +--- src/grpc/build.rs | 2 +- src/grpc/src/grpc_server/mod.rs | 1 - src/grpc/src/interfaces/gpt_answer.rs | 3 + src/grpc/src/interfaces/mod.rs | 1 + src/grpc/src/lib.rs | 3 +- src/grpc_server/Cargo.toml | 66 +++++++++++++++++ src/grpc_server/build.rs | 57 +++++++++++++++ src/grpc_server/config/00-default.toml | 5 ++ .../src/controllers}/gpt_answer.rs | 21 +++--- .../src/controllers}/mod.rs | 0 src/grpc_server/src/lib.rs | 2 + src/grpc_server/src/main.rs | 62 ++++++++++++++++ src/grpc_server/src/options.rs | 34 +++++++++ src/public/Cargo.toml | 2 +- src/public/src/controllers/question.rs | 27 ++++--- src/public/src/main.rs | 6 +- 30 files changed, 370 insertions(+), 114 deletions(-) create mode 100644 .github/workflows/docker.yml create mode 100644 src/adapter/src/repositories/grpc/config.rs create mode 100644 src/adapter/src/repositories/grpc/mod.rs rename src/{grpc/src/grpc_client => adapter/src/repositories/grpc/models}/gpt_answer.rs (65%) create mode 100644 src/adapter/src/repositories/grpc/models/mod.rs delete mode 100644 src/grpc/src/grpc_server/mod.rs create mode 100644 src/grpc/src/interfaces/gpt_answer.rs create mode 100644 src/grpc/src/interfaces/mod.rs create mode 100644 src/grpc_server/Cargo.toml create mode 100644 src/grpc_server/build.rs create mode 100644 src/grpc_server/config/00-default.toml rename src/{grpc/src/grpc_server => grpc_server/src/controllers}/gpt_answer.rs (62%) rename src/{grpc/src/grpc_client => grpc_server/src/controllers}/mod.rs (100%) create mode 100644 src/grpc_server/src/lib.rs create mode 100644 src/grpc_server/src/main.rs create mode 100644 src/grpc_server/src/options.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8760d68..2ab124b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -65,7 +65,6 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' needs: [cargo-check, fmt-check, test-and-coverage] - # needs: [fmt-check] steps: - name: Check out from Git uses: actions/checkout@v4 @@ -103,7 +102,6 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' needs: [cargo-check, fmt-check, test-and-coverage] - # needs: [fmt-check] steps: - name: Check out from Git uses: actions/checkout@v4 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..1b3580b --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,17 @@ +name: Docker build + +on: + pull_request: + branches: + - main + +jobs: + build-docker-image: + runs-on: ubuntu-latest + steps: + - name: Check out from Git + uses: actions/checkout@v4 + + - name: Build docker image + run: | + docker build . diff --git a/Cargo.lock b/Cargo.lock index 5db657a..5c7640e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,10 +11,12 @@ dependencies = [ "deadpool-diesel", "diesel", "diesel_migrations", + "grpc_interface", "rust_core", "serde", "testcontainers-modules", "tokio", + "tonic", ] [[package]] @@ -104,9 +106,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "async-stream" @@ -147,15 +149,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "autotools" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8da1805e028a172334c3b680f93e71126f2327622faef2ec3d893c0a4ad77" -dependencies = [ - "cc", -] - [[package]] name = "axum" version = "0.6.20" @@ -337,7 +330,7 @@ dependencies = [ "deadpool-diesel", "diesel", "diesel_migrations", - "grpc_client", + "grpc_interface", "openssl", "opentelemetry", "rand", @@ -391,7 +384,7 @@ dependencies = [ "rust-ini", "serde", "serde_json", - "toml 0.8.10", + "toml 0.8.11", "yaml-rust", ] @@ -828,16 +821,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] -name = "grpc_client" +name = "grpc_interface" version = "0.0.1" dependencies = [ - "once_cell", "prost", - "prost-build", - "protobuf-src", + "tonic", + "tonic-build", +] + +[[package]] +name = "grpc_server" +version = "0.0.1" +dependencies = [ + "clap", + "common", + "grpc_interface", + "opentelemetry", + "prost", + "readonly", "rust_core", + "serde", + "serde_json", + "tokio", "tonic", "tonic-build", + "tracing", ] [[package]] @@ -1584,9 +1592,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1645,15 +1653,6 @@ dependencies = [ "prost", ] -[[package]] -name = "protobuf-src" -version = "1.1.0+21.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7ac8852baeb3cc6fb83b93646fb93c0ffe5d14bf138c945ceb4b9948ee0e3c1" -dependencies = [ - "autotools", -] - [[package]] name = "quote" version = "1.0.35" @@ -2072,18 +2071,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", @@ -2246,14 +2245,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +checksum = "af06656561d28735e9c1cd63dfd57132c8155426aa6af24f36a00a351f88c48e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.6", + "toml_edit 0.22.7", ] [[package]] @@ -2280,9 +2279,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.6" +version = "0.22.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +checksum = "18769cd1cec395d70860ceb4d932812a0b4d06b1a4bb336745a4d21b9496e992" dependencies = [ "indexmap 2.2.5", "serde", diff --git a/Cargo.toml b/Cargo.toml index 49a5ae3..25646c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["src/public"] +members = ["src/public", "src/grpc_server"] resolver = "2" diff --git a/Dockerfile b/Dockerfile index aa0966e..7baa79a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,7 @@ FROM clux/muslrust:stable AS chef USER root RUN cargo install cargo-chef + WORKDIR /app FROM clux/muslrust:stable AS bunyan diff --git a/src/adapter/Cargo.toml b/src/adapter/Cargo.toml index 021a25f..d04f690 100644 --- a/src/adapter/Cargo.toml +++ b/src/adapter/Cargo.toml @@ -42,4 +42,10 @@ version = "1.36.0" features = ["full"] [dependencies.anyhow] -version = "1.0.80" \ No newline at end of file +version = "1.0.80" + +[dependencies.tonic] +version = "0.11.0" + +[dependencies.grpc_interface] +path = "../grpc" diff --git a/src/adapter/src/repositories/grpc/config.rs b/src/adapter/src/repositories/grpc/config.rs new file mode 100644 index 0000000..2bba061 --- /dev/null +++ b/src/adapter/src/repositories/grpc/config.rs @@ -0,0 +1,6 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +pub struct ClientConfig { + pub url: String, +} diff --git a/src/adapter/src/repositories/grpc/mod.rs b/src/adapter/src/repositories/grpc/mod.rs new file mode 100644 index 0000000..c00f297 --- /dev/null +++ b/src/adapter/src/repositories/grpc/mod.rs @@ -0,0 +1,2 @@ +pub mod models; +pub mod config; \ No newline at end of file diff --git a/src/grpc/src/grpc_client/gpt_answer.rs b/src/adapter/src/repositories/grpc/models/gpt_answer.rs similarity index 65% rename from src/grpc/src/grpc_client/gpt_answer.rs rename to src/adapter/src/repositories/grpc/models/gpt_answer.rs index b07a665..4e42922 100644 --- a/src/grpc/src/grpc_client/gpt_answer.rs +++ b/src/adapter/src/repositories/grpc/models/gpt_answer.rs @@ -1,11 +1,9 @@ use rust_core::common::errors::CoreError; use tonic::transport::Channel; -use gpt_answer::gpt_answer_service_client::GptAnswerServiceClient; - -mod gpt_answer { - tonic::include_proto!("gpt_answer"); -} +use grpc_interface::interfaces::gpt_answer::gpt_answer::{ + gpt_answer_service_client::GptAnswerServiceClient, GetAnswerPayload, +}; pub struct GptAnswerGrpcClient { client: GptAnswerServiceClient<Channel>, @@ -17,10 +15,9 @@ impl GptAnswerGrpcClient { Self { client } } - pub async fn get_instance() -> Result<Self, CoreError> { - let uri = "http://0.0.0.0:50051"; + pub async fn get_instance(uri: &'static str) -> Result<Self, CoreError> { let channel = Channel::from_static(uri).connect().await.map_err(|err| { - println!("Error connecting to GPT: {:?}", err); + eprintln!("Error connecting to GPT: {:?}", err); CoreError::InternalError })?; @@ -29,12 +26,12 @@ impl GptAnswerGrpcClient { } pub async fn get_answer(&mut self, question: &str) -> Result<String, CoreError> { - let request = tonic::Request::new(gpt_answer::GetAnswerPayload { + let request = tonic::Request::new(GetAnswerPayload { question: question.to_string(), }); let response = self.client.get_answer(request).await.map_err(|err| { - println!("Error getting answer from GPT: {:?}", err); + eprintln!("Error getting answer from GPT: {:?}", err); CoreError::InternalError })?; diff --git a/src/adapter/src/repositories/grpc/models/mod.rs b/src/adapter/src/repositories/grpc/models/mod.rs new file mode 100644 index 0000000..21cbc95 --- /dev/null +++ b/src/adapter/src/repositories/grpc/models/mod.rs @@ -0,0 +1 @@ +pub mod gpt_answer; \ No newline at end of file diff --git a/src/adapter/src/repositories/mod.rs b/src/adapter/src/repositories/mod.rs index 812478a..8976b0a 100644 --- a/src/adapter/src/repositories/mod.rs +++ b/src/adapter/src/repositories/mod.rs @@ -1,3 +1,4 @@ pub mod in_memory; pub mod postgres; pub mod repository_test; +pub mod grpc; \ No newline at end of file diff --git a/src/adapter/src/repositories/postgres/models/question.rs b/src/adapter/src/repositories/postgres/models/question.rs index 2b3a234..93e804c 100644 --- a/src/adapter/src/repositories/postgres/models/question.rs +++ b/src/adapter/src/repositories/postgres/models/question.rs @@ -1,8 +1,10 @@ -use std::time::SystemTime; +use std::{ + io::{Error, ErrorKind}, + time::SystemTime, +}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; -use rust_core::common::errors::CoreError; -use rust_core::entities::question::QuestionEntity; +use rust_core::entities::question::{QuestionEntity, QuestionId}; use serde::Serialize; #[derive(Debug, Queryable, Serialize, Selectable, Insertable, AsChangeset, Identifiable)] @@ -20,23 +22,33 @@ pub struct QuestionModel { pub created_on: SystemTime, } -impl QuestionModel { - pub fn from(entity: QuestionEntity) -> Result<Self, CoreError> { +impl TryFrom<QuestionEntity> for QuestionModel { + type Error = Error; + + fn try_from(entity: QuestionEntity) -> Result<QuestionModel, Self::Error> { + let id = entity + .id + .0 + .parse() + .map_err(|_| Error::new(ErrorKind::InvalidInput, "Invalid ID"))?; + Ok(QuestionModel { - id: entity.id.to_string().parse()?, + id, title: entity.title, content: entity.content, tags: entity.tags.map(|v| v.into_iter().map(Some).collect()), created_on: SystemTime::now(), }) } +} - pub fn to_entity(self) -> Result<QuestionEntity, CoreError> { - Ok(QuestionEntity { - id: self.id.to_string().parse()?, +impl Into<QuestionEntity> for QuestionModel { + fn into(self) -> QuestionEntity { + QuestionEntity { + id: QuestionId(self.id.to_string()), title: self.title, content: self.content, tags: self.tags.map(|v| v.into_iter().flatten().collect()), - }) + } } } diff --git a/src/adapter/src/repositories/postgres/question_db.rs b/src/adapter/src/repositories/postgres/question_db.rs index 6099855..9b3b40d 100644 --- a/src/adapter/src/repositories/postgres/question_db.rs +++ b/src/adapter/src/repositories/postgres/question_db.rs @@ -37,7 +37,8 @@ impl QuestionPort for QuestionDBRepository { .await .unwrap() .interact(move |conn| { - let question = QuestionModel::from(question).unwrap(); + let question = + QuestionModel::try_from(question).map_err(|_| CoreError::InternalError)?; let response = insert_into(questions) .values(&question) .get_result::<QuestionModel>(conn) @@ -46,7 +47,7 @@ impl QuestionPort for QuestionDBRepository { _ => CoreError::InternalError, }) .unwrap(); - Ok(response.to_entity().unwrap()) + Ok(response.into()) }) .await .unwrap() @@ -58,7 +59,8 @@ impl QuestionPort for QuestionDBRepository { .await .unwrap() .interact(move |conn| { - let question = QuestionModel::from(question)?; + let question = + QuestionModel::try_from(question).map_err(|_| CoreError::InternalError)?; let response = update(questions.filter(id.eq(question.id))) .set(&question) .get_result::<QuestionModel>(conn) @@ -66,7 +68,7 @@ impl QuestionPort for QuestionDBRepository { diesel::result::Error::NotFound => CoreError::NotFound, _ => CoreError::InternalError, })? - .to_entity()?; + .into(); Ok(response) }) @@ -109,7 +111,7 @@ impl QuestionPort for QuestionDBRepository { diesel::result::Error::NotFound => CoreError::NotFound, _ => CoreError::InternalError, })? - .to_entity()?; + .into(); Ok(response) }) @@ -136,7 +138,7 @@ impl QuestionPort for QuestionDBRepository { Ok(question_list .into_iter() - .map(|l| l.to_entity().unwrap()) + .map(|l| l.into()) .collect::<Vec<_>>()) }) .await diff --git a/src/grpc/Cargo.toml b/src/grpc/Cargo.toml index f5aa19b..5f16274 100644 --- a/src/grpc/Cargo.toml +++ b/src/grpc/Cargo.toml @@ -4,7 +4,7 @@ test = [] example = [] [package] -name = "grpc_client" +name = "grpc_interface" edition = "2021" version = "0.0.1" autobins = true @@ -15,28 +15,16 @@ autobenches = true [dependencies.tonic] version = "0.11.0" -[dependencies.once_cell] -version = "1.8.0" - [dependencies.prost] version = "0.12.3" -[dependencies.prost-build] -version = "0.12.3" - -[dependencies.protobuf-src] -version = "1.1.0" - -[dependencies.rust_core] -path = "../core" - [build-dependencies] tonic-build = "0.11.0" [lib] path = "src/lib.rs" -name = "grpc_client" +name = "grpc_interface" test = true doctest = true bench = true diff --git a/src/grpc/build.rs b/src/grpc/build.rs index 44d03b1..a019efa 100644 --- a/src/grpc/build.rs +++ b/src/grpc/build.rs @@ -1,4 +1,4 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { - tonic_build::compile_protos("proto/gpt_answer.proto")?; + tonic_build::compile_protos("proto/")?; Ok(()) } diff --git a/src/grpc/src/grpc_server/mod.rs b/src/grpc/src/grpc_server/mod.rs deleted file mode 100644 index bec2060..0000000 --- a/src/grpc/src/grpc_server/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod gpt_answer; diff --git a/src/grpc/src/interfaces/gpt_answer.rs b/src/grpc/src/interfaces/gpt_answer.rs new file mode 100644 index 0000000..ef738af --- /dev/null +++ b/src/grpc/src/interfaces/gpt_answer.rs @@ -0,0 +1,3 @@ +pub mod gpt_answer { + tonic::include_proto!("gpt_answer"); +} diff --git a/src/grpc/src/interfaces/mod.rs b/src/grpc/src/interfaces/mod.rs new file mode 100644 index 0000000..21cbc95 --- /dev/null +++ b/src/grpc/src/interfaces/mod.rs @@ -0,0 +1 @@ +pub mod gpt_answer; \ No newline at end of file diff --git a/src/grpc/src/lib.rs b/src/grpc/src/lib.rs index acb46d2..7f397c5 100644 --- a/src/grpc/src/lib.rs +++ b/src/grpc/src/lib.rs @@ -1,2 +1 @@ -pub mod grpc_client; -pub mod grpc_server; +pub mod interfaces; \ No newline at end of file diff --git a/src/grpc_server/Cargo.toml b/src/grpc_server/Cargo.toml new file mode 100644 index 0000000..d6a048b --- /dev/null +++ b/src/grpc_server/Cargo.toml @@ -0,0 +1,66 @@ +bin = [] +bench = [] +test = [] +example = [] + +[package] +name = "grpc_server" +edition = "2021" +version = "0.0.1" +autobins = true +autoexamples = true +autotests = true +autobenches = true + +[dependencies.tonic] +version = "0.11.0" + +[dependencies.prost] +version = "0.12.3" + +[dependencies.rust_core] +path = "../core" + +[dependencies.serde] +version = "1.0" +features = ["derive"] + +[dependencies.clap] +version = "4.4.7" +features = ["derive"] + +[dependencies.tokio] +version = "1.36.0" +features = ["full"] + +[dependencies.opentelemetry] +version = "0.22.0" + +[dependencies] +serde_json = "1.0" +readonly = "0.2.12" +tracing = "0.1" + +[dependencies.common] +path = "../common" + +[dependencies.grpc_interface] +path = "../grpc" + +[build-dependencies] +tonic-build = "0.11.0" + + +[lib] +path = "src/lib.rs" +name = "grpc_server" +test = true +doctest = true +bench = true +doc = true +plugin = false +proc-macro = false +harness = true +edition = "2021" +required-features = [] +crate-type = ["rlib"] diff --git a/src/grpc_server/build.rs b/src/grpc_server/build.rs new file mode 100644 index 0000000..3c01894 --- /dev/null +++ b/src/grpc_server/build.rs @@ -0,0 +1,57 @@ +use std::{borrow::Cow, env, process::Command}; + +/// Generate the `cargo:` key output +pub fn generate_cargo_keys() { + let output = Command::new("git") + .args(["rev-parse", "--short", "HEAD"]) + .output(); + + let commit = match output { + Ok(o) if o.status.success() => { + let sha = String::from_utf8_lossy(&o.stdout).trim().to_owned(); + Cow::from(sha) + } + Ok(o) => { + println!("cargo:warning=Git command failed with status: {}", o.status); + Cow::from("unknown") + } + Err(err) => { + println!("cargo:warning=Failed to execute git command: {}", err); + Cow::from("unknown") + } + }; + + println!("cargo:rustc-env=APP_VERSION={}", get_version(&commit)) +} + +fn get_platform() -> String { + let env_dash = if env::var("CARGO_CFG_TARGET_ENV").unwrap().is_empty() { + "" + } else { + "-" + }; + + format!( + "{}-{}{}{}", + env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + env::var("CARGO_CFG_TARGET_OS").unwrap(), + env_dash, + env::var("CARGO_CFG_TARGET_ENV").unwrap_or(String::from("")), + ) +} + +fn get_version(impl_commit: &str) -> String { + let commit_dash = if impl_commit.is_empty() { "" } else { "-" }; + + format!( + "{}{}{}-{}", + std::env::var("CARGO_PKG_VERSION").unwrap_or_default(), + commit_dash, + impl_commit, + get_platform(), + ) +} + +pub fn main() { + generate_cargo_keys(); +} diff --git a/src/grpc_server/config/00-default.toml b/src/grpc_server/config/00-default.toml new file mode 100644 index 0000000..1f4048f --- /dev/null +++ b/src/grpc_server/config/00-default.toml @@ -0,0 +1,5 @@ +service_name = "rust-grpc-server" +exporter_endpoint = "http://localhost:7281" + +[servers.gpt_answer_service] +url = "0.0.0.0:50051" \ No newline at end of file diff --git a/src/grpc/src/grpc_server/gpt_answer.rs b/src/grpc_server/src/controllers/gpt_answer.rs similarity index 62% rename from src/grpc/src/grpc_server/gpt_answer.rs rename to src/grpc_server/src/controllers/gpt_answer.rs index 61f9c61..7aae3d4 100644 --- a/src/grpc/src/grpc_server/gpt_answer.rs +++ b/src/grpc_server/src/controllers/gpt_answer.rs @@ -1,10 +1,11 @@ -use gpt_answer::gpt_answer_service_server::{GptAnswerService, GptAnswerServiceServer}; -use gpt_answer::{GetAnswerPayload, GetAnswerResponse}; +use grpc_interface::interfaces::gpt_answer::gpt_answer::gpt_answer_service_server::{ + GptAnswerService, GptAnswerServiceServer, +}; +use grpc_interface::interfaces::gpt_answer::gpt_answer::{GetAnswerPayload, GetAnswerResponse}; +use rust_core::common::errors::CoreError; use tonic::{transport::Server, Request, Response, Status}; -mod gpt_answer { - tonic::include_proto!("gpt_answer"); -} +use crate::options::Options; #[derive(Debug, Default)] pub struct GptAnswerServer; @@ -24,9 +25,11 @@ impl GptAnswerService for GptAnswerServer { } } -pub async fn init_gpt_answer_server() { - let result = "0.0.0.0:50051".parse().map_err(|err| { - println!("Error: {:?}", err); +pub async fn init_gpt_answer_server(options: Options) { + let gpt_answer_config = options.servers.gpt_answer_service.clone().unwrap(); + let result = gpt_answer_config.url.parse().map_err(|err| { + eprintln!("Error: {:?}", err); + CoreError::InternalError }); if result.is_ok() { @@ -44,6 +47,6 @@ pub async fn init_gpt_answer_server() { println!("GPT Answer server started at {}", addr); } else { - println!("GPT Answer server failed to start"); + eprintln!("GPT Answer server failed to start"); } } diff --git a/src/grpc/src/grpc_client/mod.rs b/src/grpc_server/src/controllers/mod.rs similarity index 100% rename from src/grpc/src/grpc_client/mod.rs rename to src/grpc_server/src/controllers/mod.rs diff --git a/src/grpc_server/src/lib.rs b/src/grpc_server/src/lib.rs new file mode 100644 index 0000000..889f08d --- /dev/null +++ b/src/grpc_server/src/lib.rs @@ -0,0 +1,2 @@ +pub mod controllers; +pub mod options; \ No newline at end of file diff --git a/src/grpc_server/src/main.rs b/src/grpc_server/src/main.rs new file mode 100644 index 0000000..201752b --- /dev/null +++ b/src/grpc_server/src/main.rs @@ -0,0 +1,62 @@ +use clap::{Parser, Subcommand}; +use grpc_server::{controllers, options}; +use opentelemetry::global; + +use common::loggers::telemetry::init_telemetry; +use common::options::parse_options; +use controllers::gpt_answer::init_gpt_answer_server; +use options::Options; + +#[tokio::main] +async fn main() { + let args = Args::parse(); + if args.version { + println!(env!("APP_VERSION")); + return; + } + + let options: Options = match parse_options(args.config_path) { + Ok(options) => options, + Err(err) => { + eprintln!("Failed to load config: {}", err); + return; + } + }; + + if let Some(Commands::Config) = args.command { + println!("{:#?}", options); + return; + } + + init_telemetry( + options.service_name.as_str(), + options.exporter_endpoint.as_str(), + options.log.level.as_str(), + ); + + let gpt_answer_server = tokio::spawn(init_gpt_answer_server(options)); + + tokio::try_join!(gpt_answer_server).expect("Failed to run servers"); + + global::shutdown_tracer_provider(); +} + +/// Simple REST server. +#[derive(Parser, Debug)] +#[command(about, long_about = None)] +struct Args { + #[command(subcommand)] + command: Option<Commands>, + /// Config file + #[arg(short, long, default_value = "config/00-default.toml")] + config_path: Vec<String>, + /// Print version + #[clap(short, long)] + version: bool, +} + +#[derive(Subcommand, Clone, Debug)] +enum Commands { + /// Print config + Config, +} diff --git a/src/grpc_server/src/options.rs b/src/grpc_server/src/options.rs new file mode 100644 index 0000000..3b3aa81 --- /dev/null +++ b/src/grpc_server/src/options.rs @@ -0,0 +1,34 @@ +use serde::Deserialize; +use common::options::{default_log, Log}; + +/// Configuration options for the application. +/// +/// This struct represents the configuration options for the application, including server settings, +/// database configuration, endpoint for the exporter, service name, and logging configuration. +#[readonly::make] +#[derive(Deserialize, Debug)] +pub struct Options { + /// Configuration for the servers. + pub servers: Servers, + /// The endpoint for the exporter. + pub exporter_endpoint: String, + /// The name of the service. + pub service_name: String, + /// Configuration for logging, including log level. + #[serde(default = "default_log")] + pub log: Log, +} + +/// Represents servers configuration options. +#[derive(Deserialize, Debug)] +pub struct Servers { + /// Configuration for using in-memory database. + pub gpt_answer_service: Option<ServiceServer>, +} + +/// Represents service server configuration. +#[derive(Debug, Deserialize, Clone)] +pub struct ServiceServer { + /// URL for the server. + pub url: String, +} diff --git a/src/public/Cargo.toml b/src/public/Cargo.toml index 1c4b180..74b8a55 100644 --- a/src/public/Cargo.toml +++ b/src/public/Cargo.toml @@ -103,7 +103,7 @@ version = "1.0.57" [dependencies.anyhow] version = "1.0.80" -[dependencies.grpc_client] +[dependencies.grpc_interface] path = "../grpc" [lib] diff --git a/src/public/src/controllers/question.rs b/src/public/src/controllers/question.rs index 1f83d49..5a459c5 100644 --- a/src/public/src/controllers/question.rs +++ b/src/public/src/controllers/question.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; +use adapter::repositories::grpc::models::gpt_answer::GptAnswerGrpcClient; use tracing::instrument; use warp::http::StatusCode; use warp::reject::Rejection; @@ -11,8 +12,6 @@ use rust_core::entities::question::{QuestionEntity, QuestionId}; use rust_core::entities::question_filter::QuestionFilter; use rust_core::ports::question::QuestionPort; -use grpc_client::grpc_client::gpt_answer::GptAnswerGrpcClient; - use crate::errors::WarpError; /// Handler for retrieving questions based on query parameters. @@ -25,12 +24,12 @@ pub async fn get_questions( question_port: Arc<dyn QuestionPort + Send + Sync>, query: HashMap<String, String>, ) -> Result<impl Reply, Rejection> { - let question_filter = QuestionFilter::from_query(&query).map_err(|err| WarpError::from(err))?; + let question_filter = QuestionFilter::from_query(&query).map_err(WarpError::from)?; let questions = question_port .list(&question_filter) .await - .map_err(|err| WarpError::from(err))?; + .map_err(WarpError::from)?; Ok(warp::reply::json(&questions)) } @@ -45,12 +44,12 @@ pub async fn get_question( question_port: Arc<dyn QuestionPort + Send + Sync>, id: String, ) -> Result<impl Reply, Rejection> { - let question_id = QuestionId::from_str(id.as_str()).map_err(|err| WarpError::from(err))?; + let question_id = QuestionId::from_str(id.as_str()).map_err(WarpError::from)?; let question = question_port .get(&question_id) .await - .map_err(|err| WarpError::from(err))?; + .map_err(WarpError::from)?; Ok(warp::reply::json(&question)) } @@ -68,7 +67,7 @@ pub async fn add_question( question_port .add(question) .await - .map_err(|err| WarpError::from(err))?; + .map_err(WarpError::from)?; Ok(warp::reply::with_status("Question added", StatusCode::OK)) } @@ -83,12 +82,12 @@ pub async fn delete_question( question_port: Arc<dyn QuestionPort + Send + Sync>, id: String, ) -> Result<impl Reply, Rejection> { - let question_id = QuestionId::from_str(id.as_str()).map_err(|err| WarpError::from(err))?; + let question_id = QuestionId::from_str(id.as_str()).map_err(WarpError::from)?; question_port .delete(&question_id) .await - .map_err(|err| WarpError::from(err))?; + .map_err(WarpError::from)?; Ok(warp::reply::with_status("Question deleted", StatusCode::OK)) } @@ -105,13 +104,13 @@ pub async fn update_question( id: String, mut question: QuestionEntity, ) -> Result<impl Reply, Rejection> { - let question_id = QuestionId::from_str(id.as_str()).map_err(|err| WarpError::from(err))?; + let question_id = QuestionId::from_str(id.as_str()).map_err(WarpError::from)?; question.id = question_id; question_port .update(question) .await - .map_err(|err| WarpError::from(err))?; + .map_err(WarpError::from)?; Ok(warp::reply::with_status("Question updated", StatusCode::OK)) } @@ -141,15 +140,15 @@ pub async fn get_question_answer_controller( let question = question_port .get(&QuestionId::from_str(id.as_str()).unwrap()) .await - .map_err(|err| WarpError::from(err))?; + .map_err(WarpError::from)?; - let client = GptAnswerGrpcClient::get_instance().await; + let client = GptAnswerGrpcClient::get_instance("0.0.0.0:50051").await; let answer = client .unwrap() .get_answer(&question.content) .await - .map_err(|err| WarpError::from(err))?; + .map_err(WarpError::from)?; Ok(warp::reply::with_status(answer, StatusCode::OK)) } diff --git a/src/public/src/main.rs b/src/public/src/main.rs index 50487ee..009a655 100644 --- a/src/public/src/main.rs +++ b/src/public/src/main.rs @@ -1,4 +1,3 @@ -#[rustfmt::skip] #[cfg_attr(debug_assertions, allow(dead_code, unused_imports))] use openssl; #[rustfmt::skip] @@ -23,8 +22,6 @@ use common::loggers::telemetry::init_telemetry; use common::options::parse_options; use rust_core::ports::question::QuestionPort; -use grpc_client::grpc_server::gpt_answer::init_gpt_answer_server; - #[tokio::main] async fn main() { let args = Args::parse(); @@ -52,9 +49,8 @@ async fn main() { options.log.level.as_str(), ); - let grpc_server = tokio::spawn(init_gpt_answer_server()); let warp_server = tokio::spawn(run_warp_server(options)); - tokio::try_join!(grpc_server, warp_server).expect("Failed to run servers"); + tokio::try_join!(warp_server).expect("Failed to run servers"); global::shutdown_tracer_provider(); }