From b871d407598f61acb71b0af67659777e700fc824 Mon Sep 17 00:00:00 2001 From: filipriec Date: Sat, 15 Feb 2025 22:57:40 +0100 Subject: [PATCH] not working, basic structure with grpc --- .gitignore | 1 + Cargo.lock | 232 ++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 8 +- build.rs | 4 + proto/api.proto | 15 +++ src/client/mod.rs | 22 +---- src/db.rs | 52 +++++++++++ src/lib.rs | 3 + src/main.rs | 52 +++++------ src/server/mod.rs | 43 ++------- 10 files changed, 352 insertions(+), 80 deletions(-) create mode 100644 build.rs create mode 100644 src/db.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..fedaa2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +.env diff --git a/Cargo.lock b/Cargo.lock index 86c2511..62ca546 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,6 +246,15 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +[[package]] +name = "cc" +version = "1.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -313,6 +322,22 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -484,6 +509,21 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1079,11 +1119,14 @@ name = "multieko2" version = "0.1.0" dependencies = [ "clap", + "dotenvy", "prost", "sqlx", "tokio", "tonic", "tonic-build", + "tracing", + "tracing-subscriber", ] [[package]] @@ -1092,6 +1135,33 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "native-tls" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -1154,6 +1224,56 @@ version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +[[package]] +name = "openssl" +version = "0.10.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking" version = "2.2.1" @@ -1475,12 +1595,44 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.217" @@ -1547,6 +1699,21 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1646,6 +1813,7 @@ dependencies = [ "indexmap 2.7.1", "log", "memchr", + "native-tls", "once_cell", "percent-encoding", "serde", @@ -1891,6 +2059,16 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -2089,6 +2267,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -2159,6 +2363,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" @@ -2211,6 +2421,28 @@ dependencies = [ "wasite", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index f07b184..82648c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,14 @@ edition = "2021" [dependencies] clap = { version = "4.5.29", features = ["derive"] } +dotenvy = "0.15.7" prost = "0.13.5" -sqlx = { version = "0.8.3", features = ["postgres", "runtime-tokio"] } +sqlx = { version = "0.8.3", features = ["postgres", "runtime-tokio", "runtime-tokio-native-tls"] } tokio = { version = "1.43.0", features = ["full", "macros"] } tonic = "0.12.3" tonic-build = "0.12.3" +tracing = "0.1.41" +tracing-subscriber = "0.3.19" + +[build-dependencies] +tonic-build = "0.12" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..1f5f767 --- /dev/null +++ b/build.rs @@ -0,0 +1,4 @@ +// build.rs +fn main() { + tonic_build::compile_protos("proto/api.proto").unwrap(); +} diff --git a/proto/api.proto b/proto/api.proto index e69de29..efb516a 100644 --- a/proto/api.proto +++ b/proto/api.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package my_service; + +service MyService { + rpc MyMethod (MyRequest) returns (MyResponse); +} + +message MyRequest { + int32 id = 1; +} + +message MyResponse { + string message = 1; +} diff --git a/src/client/mod.rs b/src/client/mod.rs index 45e319d..9699c22 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,21 +1,7 @@ -use multieko2::accounting_client::AccountingClient; -use multieko2::{CreateAccountRequest, GetAccountRequest}; - -pub async fn run_client(server_url: String) -> Result<(), Box> { - let mut client = AccountingClient::connect(server_url).await?; - - // Create an account - let create_response = client - .create_account(CreateAccountRequest { name: "John Doe".into() }) - .await?; - println!("Created account with ID: {}", create_response.into_inner().id); - - // Get an account - let get_response = client - .get_account(GetAccountRequest { id: "1".into() }) - .await?; - let account = get_response.into_inner(); - println!("Account ID: {}, Name: {}", account.id, account.name); +use crate::proto::api::accounting_client::AccountingClient; +pub async fn run_client() -> Result<(), Box> { + let mut client = AccountingClient::connect("http://[::1]:50051").await?; + // Client implementation Ok(()) } diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..4840945 --- /dev/null +++ b/src/db.rs @@ -0,0 +1,52 @@ +// src/db.rs +use sqlx::postgres::{PgPool, PgPoolOptions}; +use std::time::Duration; +use tracing::info; + +#[derive(Debug)] +pub struct DatabaseConfig { + pub username: String, + pub password: String, + pub host: String, + pub port: u16, + pub database_name: String, + pub max_connections: u32, +} + +impl DatabaseConfig { + pub fn from_env() -> Self { + Self { + username: std::env::var("RUST_DB_USER").expect("RUST_DB_USER must be set"), + password: std::env::var("RUST_DB_PASSWORD").expect("RUST_DB_PASSWORD must be set"), + host: std::env::var("RUST_DB_HOST").expect("RUST_DB_HOST must be set"), + port: std::env::var("RUST_DB_PORT") + .expect("RUST_DB_PORT must be set") + .parse() + .expect("RUST_DB_PORT must be a valid port number"), + database_name: std::env::var("RUST_DB_NAME").expect("RUST_DB_NAME must be set"), + max_connections: 5, + } + } + + pub fn connection_string(&self) -> String { + format!( + "postgres://{}:{}@{}:{}/{}", + self.username, self.password, self.host, self.port, self.database_name + ) + } +} + +pub async fn create_pool(config: &DatabaseConfig) -> Result { + let conn_str = config.connection_string(); + info!("Connecting to database: {}", conn_str); + PgPoolOptions::new() + .max_connections(config.max_connections) + .acquire_timeout(Duration::from_secs(3)) + .connect(&conn_str) + .await +} + +pub async fn check_connection(pool: &PgPool) -> Result<(), sqlx::Error> { + sqlx::query("SELECT 1").execute(pool).await?; + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index e69de29..e878331 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -0,0 +1,3 @@ +// src/lib.rs +pub mod db; +pub mod server; diff --git a/src/main.rs b/src/main.rs index ee200bb..6a2324b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,35 +1,33 @@ -use clap::{Parser, Subcommand}; +// src/main.rs +use tonic::transport::Server; use sqlx::PgPool; - -#[derive(Parser)] -struct Cli { - #[clap(subcommand)] - command: Commands, -} - -#[derive(Subcommand)] -enum Commands { - Standalone, - Server, - Client { server_url: String }, -} +use crate::db; +use crate::server; #[tokio::main] async fn main() -> Result<(), Box> { - let args = Cli::parse(); + // Load .env file + dotenvy::dotenv().ok(); - match args.command { - Commands::Standalone => { - standalone::run().await?; - } - Commands::Server => { - let db_pool = PgPool::connect("postgres://user:password@localhost/multieko2").await?; - server::run_server(db_pool).await?; - } - Commands::Client { server_url } => { - client::run_client(server_url).await?; - } + // Initialize database + let db_config = db::DatabaseConfig::from_env(); + let db_pool = db::create_pool(&db_config) + .await + .expect("Failed to create database pool"); + + + // Check database connection + db::check_connection(&db_pool) + .await + .expect("Failed to connect to database"); + + // Choose mode based on command line arguments + let args: Vec = env::args().collect(); + match args.get(1).map(|s| s.as_str()) { + Some("server") => server::run_server(db_pool).await?, + Some("client") => client::run_client().await?, + Some("standalone") => standalone::run().await?, + _ => println!("Usage: [server|client|standalone]"), } - Ok(()) } diff --git a/src/server/mod.rs b/src/server/mod.rs index eb4d142..9039731 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,52 +1,27 @@ use tonic::{Request, Response, Status}; -use sqlx::PgPool; -use multieko2::accounting_server::{Accounting, AccountingServer}; -use multieko2::{CreateAccountRequest, CreateAccountResponse, GetAccountRequest, GetAccountResponse}; +use crate::{db, proto::api::*}; -pub struct MyAccountingService { - db_pool: PgPool, +pub struct AccountingService { + db_pool: sqlx::PgPool, } #[tonic::async_trait] -impl Accounting for MyAccountingService { +impl accounting_server::Accounting for AccountingService { async fn create_account( &self, request: Request, ) -> Result, Status> { - let name = request.into_inner().name; - let account = sqlx::query!("INSERT INTO accounts (name) VALUES ($1) RETURNING id", name) - .fetch_one(&self.db_pool) - .await - .map_err(|e| Status::internal(e.to_string()))?; - - Ok(Response::new(CreateAccountResponse { id: account.id.to_string() })) - } - - async fn get_account( - &self, - request: Request, - ) -> Result, Status> { - let id = request.into_inner().id; - let account = sqlx::query!("SELECT id, name FROM accounts WHERE id = $1", id) - .fetch_one(&self.db_pool) - .await - .map_err(|e| Status::internal(e.to_string()))?; - - Ok(Response::new(GetAccountResponse { - id: account.id.to_string(), - name: account.name, - })) + // Database implementation } } -pub async fn run_server(db_pool: PgPool) -> Result<(), Box> { +pub async fn run_server(pool: sqlx::PgPool) -> Result<(), Box> { let addr = "[::1]:50051".parse()?; - let service = MyAccountingService { db_pool }; - tonic::transport::Server::builder() - .add_service(AccountingServer::new(service)) + .add_service(accounting_server::AccountingServer::new( + AccountingService { db_pool: pool } + )) .serve(addr) .await?; - Ok(()) }