From 298cd26d3de6936f4e4444808fcdebf5d16eaecd Mon Sep 17 00:00:00 2001 From: mateuszpiorowski Date: Sat, 13 Jan 2024 16:15:54 +0100 Subject: [PATCH] update --- client/src/hooks.server.js | 32 +- docker-compose.app.yml | 3 +- proto/src/main.rs | 6 + service-auth/Cargo.lock | 222 ++- service-auth/Cargo.toml | 4 + service-auth/src/auth_oauth.rs | 7 +- service-auth/src/auth_service.rs | 26 +- service-auth/src/lib.rs | 2 + service-auth/src/main.rs | 1 + service-auth/src/proto.rs | 2289 +++++++++++++++++++++++++++++ service-notes/Cargo.lock | 15 +- service-notes/Cargo.toml | 26 +- service-notes/src/note_service.rs | 8 +- service-users/Cargo.lock | 26 + service-users/Cargo.toml | 2 +- 15 files changed, 2595 insertions(+), 74 deletions(-) create mode 100644 service-auth/src/proto.rs diff --git a/client/src/hooks.server.js b/client/src/hooks.server.js index ab039eb5..d93c43f2 100644 --- a/client/src/hooks.server.js +++ b/client/src/hooks.server.js @@ -3,7 +3,6 @@ import { grpcSafe } from "$lib/safe"; import { usersService } from "$lib/server/grpc"; import { logger, perf } from "$lib/server/logger"; import { createMetadata } from "$lib/server/metadata"; -import { Metadata } from "@grpc/grpc-js"; import { redirect } from "@sveltejs/kit"; /** @type {import('@sveltejs/kit').Handle} */ @@ -35,39 +34,30 @@ export async function handle({ event, resolve }) { /** * Check if the user is coming from the oauth flow - * If so, send the token to the backend to create a user + * If so, set a temporary cookie with the token + * On the next request, the new token will be used */ - const oauth_token = event.url.searchParams.get("oauth_token"); - if (oauth_token) { - const metadata = new Metadata(); - metadata.add("x-authorization", `bearer ${oauth_token}`); - /** @type {import("$lib/safe").Safe} */ - const token = await new Promise((res) => { - usersService.CreateUser({}, metadata, grpcSafe(res)); - }); - if (token.error) { - throw redirect(302, "/auth?error=1"); - } - event.cookies.set("token", token.data.id, { + let token = event.url.searchParams.get("token"); + if (token) { + event.cookies.set("token", token, { domain: COOKIE_DOMAIN, path: "/", - // 10 seconds, it's just to create the user and redirect to the dashboard - // after that the token will be refreshed with 7 days max age + // 10 seconds, it should be enough to be read by the backend on the next request maxAge: 10, }); throw redirect(302, "/dashboard"); } - if (event.url.pathname === "/") { - throw redirect(302, "/dashboard"); - } - - const token = event.cookies.get("token") ?? ""; + token = event.cookies.get("token") ?? ""; if (!token) { logger.info("No token"); throw redirect(302, "/auth"); } + if (event.url.pathname === "/") { + throw redirect(302, "/dashboard"); + } + const metadata = createMetadata(token); /** @type {import("$lib/safe").Safe} */ const auth = await new Promise((res) => { diff --git a/docker-compose.app.yml b/docker-compose.app.yml index c089bdec..beeb6b55 100644 --- a/docker-compose.app.yml +++ b/docker-compose.app.yml @@ -33,8 +33,9 @@ services: PORT: 443 RUST_LOG: info DATABASE_URL: postgresql://?host=db-users&user=postgres&password=12345&dbname=users - AUTH_URL: http://127.0.0.1:8090 CLIENT_URL: http://127.0.0.1:3000 + AUTH_URL: http://127.0.0.1:8090 + USERS_URL: http://service-users:443 GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID} GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET} GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID} diff --git a/proto/src/main.rs b/proto/src/main.rs index d977d5f8..bae64069 100644 --- a/proto/src/main.rs +++ b/proto/src/main.rs @@ -17,4 +17,10 @@ fn main() { .out_dir("../service-utils/src/") .compile(&["./main.proto"], &["./"]) .expect("Failed to compile utils protos"); + + tonic_build::configure() + .type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]") + .out_dir("../service-auth/src/") + .compile(&["./main.proto"], &["./"]) + .expect("Failed to compile utils protos"); } diff --git a/service-auth/Cargo.lock b/service-auth/Cargo.lock index 7644d9ff..96814a72 100644 --- a/service-auth/Cargo.lock +++ b/service-auth/Cargo.lock @@ -53,6 +53,28 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.40", +] + [[package]] name = "async-trait" version = "0.1.74" @@ -61,7 +83,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -76,6 +98,34 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core 0.3.4", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.11", + "http-body 0.4.6", + "hyper 0.14.27", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "axum" version = "0.7.2" @@ -83,7 +133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.4.1", "bytes", "futures-util", "http 1.0.0", @@ -109,6 +159,23 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 0.2.11", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-core" version = "0.4.1" @@ -314,6 +381,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -431,7 +504,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -504,7 +577,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -523,13 +596,19 @@ dependencies = [ "futures-sink", "futures-util", "http 1.0.0", - "indexmap", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.3" @@ -676,6 +755,18 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper 0.14.27", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -742,6 +833,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.1.0" @@ -749,7 +850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -758,6 +859,15 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.10" @@ -1004,7 +1114,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -1104,7 +1214,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -1178,6 +1288,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "quote" version = "1.0.33" @@ -1421,13 +1554,14 @@ name = "rusve-auth" version = "0.1.0" dependencies = [ "anyhow", - "axum", + "axum 0.7.2", "deadpool-postgres", "futures-core", "futures-util", "http 1.0.0", "jsonwebtoken", "oauth2", + "prost", "reqwest", "rustls", "rustls-native-certs", @@ -1438,6 +1572,7 @@ dependencies = [ "tokio-postgres", "tokio-postgres-rustls", "tokio-stream", + "tonic", "tower", "tower-http", "tracing", @@ -1516,7 +1651,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -1654,6 +1789,17 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.40" @@ -1722,7 +1868,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -1796,6 +1942,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.2.0" @@ -1804,7 +1960,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -1892,6 +2048,38 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" +dependencies = [ + "async-stream", + "async-trait", + "axum 0.6.20", + "base64 0.21.5", + "bytes", + "futures-core", + "futures-util", + "h2 0.3.22", + "http 0.2.11", + "http-body 0.4.6", + "hyper 0.14.27", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "rustls-native-certs", + "rustls-pemfile", + "tokio", + "tokio-rustls", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower" version = "0.4.13" @@ -1900,9 +2088,13 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", + "indexmap 1.9.3", "pin-project", "pin-project-lite", + "rand", + "slab", "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -1956,7 +2148,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -2119,7 +2311,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.40", "wasm-bindgen-shared", ] @@ -2153,7 +2345,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/service-auth/Cargo.toml b/service-auth/Cargo.toml index ec78f000..badcf3e7 100644 --- a/service-auth/Cargo.toml +++ b/service-auth/Cargo.toml @@ -29,6 +29,10 @@ rustls = "0.21.5" rustls-native-certs = "0.6.3" deadpool-postgres = "0.10.5" +# gRPC +prost = "0.11.9" +tonic = { version = "0.9.2", features = ["tls", "tls-roots"] } + # Http axum = "0.7.2" tower = "0.4.13" diff --git a/service-auth/src/auth_oauth.rs b/service-auth/src/auth_oauth.rs index ad701b75..78ca3fe7 100644 --- a/service-auth/src/auth_oauth.rs +++ b/service-auth/src/auth_oauth.rs @@ -2,6 +2,7 @@ use anyhow::Result; use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl}; use rusve_auth::Env; use serde::{Deserialize, Serialize}; +use tonic::metadata::{Ascii, MetadataValue}; pub enum OAuthProvider { Google, @@ -22,7 +23,7 @@ pub trait OAuth { Self: Sized; fn build_oauth_client(&self) -> BasicClient; async fn get_user_info(&self, token: &str) -> Result; - fn generate_jwt(&self, user: OAuthUser) -> Result; + fn generate_jwt(&self, user: OAuthUser) -> Result>; } pub struct OAuthConfig { @@ -140,12 +141,12 @@ impl OAuth for OAuthConfig { } } - fn generate_jwt(&self, user: OAuthUser) -> Result { + fn generate_jwt(&self, user: OAuthUser) -> Result> { let token = jsonwebtoken::encode( &jsonwebtoken::Header::new(jsonwebtoken::Algorithm::HS256), &user, &jsonwebtoken::EncodingKey::from_secret(self.jwt_secret.as_bytes()), )?; - Ok(token) + Ok(format!("bearer {}", token).parse()?) } } diff --git a/service-auth/src/auth_service.rs b/service-auth/src/auth_service.rs index 463a43fe..57714c75 100644 --- a/service-auth/src/auth_service.rs +++ b/service-auth/src/auth_service.rs @@ -1,5 +1,6 @@ use crate::{ auth_oauth::{OAuth, OAuthConfig}, + proto::users_service_client::UsersServiceClient, AppState, }; use anyhow::Result; @@ -130,17 +131,34 @@ pub async fn oauth_callback( /* * This is where you implement you own logic to create or update a user in your database. - * Here we are creating the jwt token with the user data and sending it to the client. - * The client will act as a gateway to the other services and use it to create a new user. + * Here we are calling the users service to create a new user. + * It returns an id token that we can use to authenticate the user. */ let jwt_token = oauth_config.generate_jwt(user_profile).map_err(|err| { tracing::error!("Failed to generate JWT: {:?}", err); Redirect::to(&format!("{}/auth?error=2", state.env.client_url)) })?; + let client = UsersServiceClient::connect(state.env.users_url.to_owned()) + .await + .map_err(|err| { + tracing::error!("Failed to connect to users service: {:?}", err); + Redirect::to(&format!("{}/auth?error=2", state.env.client_url)) + }); + let mut request = tonic::Request::new(crate::proto::Empty {}); + let metadata = request.metadata_mut(); + metadata.insert("x-authorization", jwt_token); + let token = client? + .create_user(request) + .await + .map_err(|err| { + tracing::error!("Failed to create user: {:?}", err); + Redirect::to(&format!("{}/auth?error=2", state.env.client_url)) + })? + .into_inner(); tracing::info!("User authenticated"); Ok(Redirect::to(&format!( - "{}/?oauth_token={}", - state.env.client_url, jwt_token + "{}/?token={}", + state.env.client_url, token.id ))) } diff --git a/service-auth/src/lib.rs b/service-auth/src/lib.rs index 4d8cc716..4ff41419 100644 --- a/service-auth/src/lib.rs +++ b/service-auth/src/lib.rs @@ -12,6 +12,7 @@ pub struct Env { pub database_url: String, pub auth_url: String, pub client_url: String, + pub users_url: String, pub google_client_id: String, pub google_client_secret: String, pub github_client_id: String, @@ -26,6 +27,7 @@ pub fn init_envs() -> Result { database_url: std::env::var("DATABASE_URL").context("DATABASE_URL is not set")?, auth_url: std::env::var("AUTH_URL").context("AUTH_URL is not set")?, client_url: std::env::var("CLIENT_URL").context("CLIENT_URL is not set")?, + users_url: std::env::var("USERS_URL").context("USERS_URL is not set")?, google_client_id: std::env::var("GOOGLE_CLIENT_ID") .context("GOOGLE_CLIENT_ID is not set")?, google_client_secret: std::env::var("GOOGLE_CLIENT_SECRET") diff --git a/service-auth/src/main.rs b/service-auth/src/main.rs index 8c4ba7ed..d0efe9ed 100644 --- a/service-auth/src/main.rs +++ b/service-auth/src/main.rs @@ -1,3 +1,4 @@ +mod proto; mod auth_db; mod auth_oauth; mod auth_service; diff --git a/service-auth/src/proto.rs b/service-auth/src/proto.rs new file mode 100644 index 00000000..7cda080b --- /dev/null +++ b/service-auth/src/proto.rs @@ -0,0 +1,2289 @@ +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct User { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub created: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub updated: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub deleted: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub email: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub sub: ::prost::alloc::string::String, + #[prost(enumeration = "UserRole", tag = "7")] + pub role: i32, + #[prost(string, tag = "8")] + pub avatar: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub subscription_id: ::prost::alloc::string::String, + #[prost(string, tag = "10")] + pub subscription_end: ::prost::alloc::string::String, + #[prost(string, tag = "11")] + pub subscription_check: ::prost::alloc::string::String, + #[prost(bool, tag = "12")] + pub subscription_active: bool, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum UserRole { + RoleUnset = 0, + User = 1, + Admin = 2, +} +impl UserRole { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + UserRole::RoleUnset => "ROLE_UNSET", + UserRole::User => "USER", + UserRole::Admin => "ADMIN", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ROLE_UNSET" => Some(Self::RoleUnset), + "USER" => Some(Self::User), + "ADMIN" => Some(Self::Admin), + _ => None, + } + } +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Profile { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub created: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub updated: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub deleted: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub user_id: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub name: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub about: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub avatar_id: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub avatar_url: ::prost::alloc::string::String, + #[prost(string, tag = "10")] + pub cover_id: ::prost::alloc::string::String, + #[prost(string, tag = "11")] + pub cover_url: ::prost::alloc::string::String, + #[prost(string, tag = "12")] + pub resume_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Note { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub created: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub updated: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub deleted: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub user_id: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub title: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub content: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct File { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub created: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub updated: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub deleted: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub target_id: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub file_name: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub file_size: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub file_type: ::prost::alloc::string::String, + #[prost(enumeration = "FileTarget", tag = "9")] + pub file_target: i32, + #[prost(bytes = "vec", tag = "10")] + pub file_buffer: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Email { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub created: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub updated: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub deleted: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub target_id: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub email_to: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub email_from: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub email_from_name: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub email_subject: ::prost::alloc::string::String, + #[prost(string, tag = "10")] + pub email_body: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum FileTarget { + FileUnset = 0, + Document = 1, + Avatar = 2, +} +impl FileTarget { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + FileTarget::FileUnset => "FILE_UNSET", + FileTarget::Document => "DOCUMENT", + FileTarget::Avatar => "AVATAR", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "FILE_UNSET" => Some(Self::FileUnset), + "DOCUMENT" => Some(Self::Document), + "AVATAR" => Some(Self::Avatar), + _ => None, + } + } +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Empty {} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Id { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Page { + #[prost(int64, tag = "1")] + pub offset: i64, + #[prost(int64, tag = "2")] + pub limit: i64, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Count { + #[prost(int64, tag = "1")] + pub count: i64, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AuthResponse { + #[prost(string, tag = "1")] + pub token: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub user: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StripeUrlResponse { + #[prost(string, tag = "1")] + pub url: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NoteResponse { + #[prost(message, optional, tag = "1")] + pub note: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub profile: ::core::option::Option, +} +/// Generated client implementations. +pub mod users_service_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct UsersServiceClient { + inner: tonic::client::Grpc, + } + impl UsersServiceClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl UsersServiceClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> UsersServiceClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + UsersServiceClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn create_user( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UsersService/CreateUser", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UsersService", "CreateUser")); + self.inner.unary(req, path, codec).await + } + pub async fn auth( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/proto.UsersService/Auth"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("proto.UsersService", "Auth")); + self.inner.unary(req, path, codec).await + } + pub async fn get_profile_by_user_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UsersService/GetProfileByUserId", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UsersService", "GetProfileByUserId")); + self.inner.unary(req, path, codec).await + } + pub async fn create_profile( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UsersService/CreateProfile", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UsersService", "CreateProfile")); + self.inner.unary(req, path, codec).await + } + pub async fn create_stripe_checkout( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UsersService/CreateStripeCheckout", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UsersService", "CreateStripeCheckout")); + self.inner.unary(req, path, codec).await + } + pub async fn create_stripe_portal( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UsersService/CreateStripePortal", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UsersService", "CreateStripePortal")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated client implementations. +pub mod notes_service_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct NotesServiceClient { + inner: tonic::client::Grpc, + } + impl NotesServiceClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl NotesServiceClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> NotesServiceClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + NotesServiceClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn count_notes_by_user_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.NotesService/CountNotesByUserId", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.NotesService", "CountNotesByUserId")); + self.inner.unary(req, path, codec).await + } + pub async fn get_notes_by_user_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.NotesService/GetNotesByUserId", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.NotesService", "GetNotesByUserId")); + self.inner.server_streaming(req, path, codec).await + } + pub async fn get_note_by_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.NotesService/GetNoteById", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.NotesService", "GetNoteById")); + self.inner.unary(req, path, codec).await + } + pub async fn create_note( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.NotesService/CreateNote", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.NotesService", "CreateNote")); + self.inner.unary(req, path, codec).await + } + pub async fn delete_note_by_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.NotesService/DeleteNoteById", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.NotesService", "DeleteNoteById")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated client implementations. +pub mod utils_service_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct UtilsServiceClient { + inner: tonic::client::Grpc, + } + impl UtilsServiceClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl UtilsServiceClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> UtilsServiceClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + UtilsServiceClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn count_emails_by_target_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UtilsService/CountEmailsByTargetId", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UtilsService", "CountEmailsByTargetId")); + self.inner.unary(req, path, codec).await + } + pub async fn get_emails_by_target_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UtilsService/GetEmailsByTargetId", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UtilsService", "GetEmailsByTargetId")); + self.inner.server_streaming(req, path, codec).await + } + pub async fn send_email( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UtilsService/SendEmail", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UtilsService", "SendEmail")); + self.inner.unary(req, path, codec).await + } + pub async fn count_files_by_target_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UtilsService/CountFilesByTargetId", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UtilsService", "CountFilesByTargetId")); + self.inner.unary(req, path, codec).await + } + /// Returns stream of files metadata without content + pub async fn get_files_by_target_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UtilsService/GetFilesByTargetId", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UtilsService", "GetFilesByTargetId")); + self.inner.server_streaming(req, path, codec).await + } + /// Returns single file with content as stream + pub async fn get_file_by_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UtilsService/GetFileById", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UtilsService", "GetFileById")); + self.inner.server_streaming(req, path, codec).await + } + /// Send single file with content as stream + pub async fn upload_file( + &mut self, + request: impl tonic::IntoStreamingRequest, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UtilsService/UploadFile", + ); + let mut req = request.into_streaming_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UtilsService", "UploadFile")); + self.inner.streaming(req, path, codec).await + } + pub async fn delete_file_by_id( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/proto.UtilsService/DeleteFileById", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("proto.UtilsService", "DeleteFileById")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod users_service_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with UsersServiceServer. + #[async_trait] + pub trait UsersService: Send + Sync + 'static { + async fn create_user( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn auth( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn get_profile_by_user_id( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn create_profile( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn create_stripe_checkout( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn create_stripe_portal( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + } + #[derive(Debug)] + pub struct UsersServiceServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl UsersServiceServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for UsersServiceServer + where + T: UsersService, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/proto.UsersService/CreateUser" => { + #[allow(non_camel_case_types)] + struct CreateUserSvc(pub Arc); + impl tonic::server::UnaryService + for CreateUserSvc { + type Response = super::Id; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { (*inner).create_user(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CreateUserSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UsersService/Auth" => { + #[allow(non_camel_case_types)] + struct AuthSvc(pub Arc); + impl tonic::server::UnaryService + for AuthSvc { + type Response = super::AuthResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { (*inner).auth(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = AuthSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UsersService/GetProfileByUserId" => { + #[allow(non_camel_case_types)] + struct GetProfileByUserIdSvc(pub Arc); + impl tonic::server::UnaryService + for GetProfileByUserIdSvc { + type Response = super::Profile; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_profile_by_user_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetProfileByUserIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UsersService/CreateProfile" => { + #[allow(non_camel_case_types)] + struct CreateProfileSvc(pub Arc); + impl tonic::server::UnaryService + for CreateProfileSvc { + type Response = super::Profile; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).create_profile(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CreateProfileSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UsersService/CreateStripeCheckout" => { + #[allow(non_camel_case_types)] + struct CreateStripeCheckoutSvc(pub Arc); + impl tonic::server::UnaryService + for CreateStripeCheckoutSvc { + type Response = super::StripeUrlResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).create_stripe_checkout(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CreateStripeCheckoutSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UsersService/CreateStripePortal" => { + #[allow(non_camel_case_types)] + struct CreateStripePortalSvc(pub Arc); + impl tonic::server::UnaryService + for CreateStripePortalSvc { + type Response = super::StripeUrlResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).create_stripe_portal(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CreateStripePortalSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for UsersServiceServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::server::NamedService for UsersServiceServer { + const NAME: &'static str = "proto.UsersService"; + } +} +/// Generated server implementations. +pub mod notes_service_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with NotesServiceServer. + #[async_trait] + pub trait NotesService: Send + Sync + 'static { + async fn count_notes_by_user_id( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Server streaming response type for the GetNotesByUserId method. + type GetNotesByUserIdStream: futures_core::Stream< + Item = std::result::Result, + > + + Send + + 'static; + async fn get_notes_by_user_id( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_note_by_id( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn create_note( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn delete_note_by_id( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + } + #[derive(Debug)] + pub struct NotesServiceServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl NotesServiceServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for NotesServiceServer + where + T: NotesService, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/proto.NotesService/CountNotesByUserId" => { + #[allow(non_camel_case_types)] + struct CountNotesByUserIdSvc(pub Arc); + impl tonic::server::UnaryService + for CountNotesByUserIdSvc { + type Response = super::Count; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).count_notes_by_user_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CountNotesByUserIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.NotesService/GetNotesByUserId" => { + #[allow(non_camel_case_types)] + struct GetNotesByUserIdSvc(pub Arc); + impl< + T: NotesService, + > tonic::server::ServerStreamingService + for GetNotesByUserIdSvc { + type Response = super::NoteResponse; + type ResponseStream = T::GetNotesByUserIdStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_notes_by_user_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetNotesByUserIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.NotesService/GetNoteById" => { + #[allow(non_camel_case_types)] + struct GetNoteByIdSvc(pub Arc); + impl tonic::server::UnaryService + for GetNoteByIdSvc { + type Response = super::Note; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_note_by_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetNoteByIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.NotesService/CreateNote" => { + #[allow(non_camel_case_types)] + struct CreateNoteSvc(pub Arc); + impl tonic::server::UnaryService + for CreateNoteSvc { + type Response = super::Note; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { (*inner).create_note(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CreateNoteSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.NotesService/DeleteNoteById" => { + #[allow(non_camel_case_types)] + struct DeleteNoteByIdSvc(pub Arc); + impl tonic::server::UnaryService + for DeleteNoteByIdSvc { + type Response = super::Empty; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).delete_note_by_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = DeleteNoteByIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for NotesServiceServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::server::NamedService for NotesServiceServer { + const NAME: &'static str = "proto.NotesService"; + } +} +/// Generated server implementations. +pub mod utils_service_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with UtilsServiceServer. + #[async_trait] + pub trait UtilsService: Send + Sync + 'static { + async fn count_emails_by_target_id( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Server streaming response type for the GetEmailsByTargetId method. + type GetEmailsByTargetIdStream: futures_core::Stream< + Item = std::result::Result, + > + + Send + + 'static; + async fn get_emails_by_target_id( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn send_email( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn count_files_by_target_id( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Server streaming response type for the GetFilesByTargetId method. + type GetFilesByTargetIdStream: futures_core::Stream< + Item = std::result::Result, + > + + Send + + 'static; + /// Returns stream of files metadata without content + async fn get_files_by_target_id( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Server streaming response type for the GetFileById method. + type GetFileByIdStream: futures_core::Stream< + Item = std::result::Result, + > + + Send + + 'static; + /// Returns single file with content as stream + async fn get_file_by_id( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Server streaming response type for the UploadFile method. + type UploadFileStream: futures_core::Stream< + Item = std::result::Result, + > + + Send + + 'static; + /// Send single file with content as stream + async fn upload_file( + &self, + request: tonic::Request>, + ) -> std::result::Result, tonic::Status>; + async fn delete_file_by_id( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + } + #[derive(Debug)] + pub struct UtilsServiceServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl UtilsServiceServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for UtilsServiceServer + where + T: UtilsService, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/proto.UtilsService/CountEmailsByTargetId" => { + #[allow(non_camel_case_types)] + struct CountEmailsByTargetIdSvc(pub Arc); + impl tonic::server::UnaryService + for CountEmailsByTargetIdSvc { + type Response = super::Count; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).count_emails_by_target_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CountEmailsByTargetIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UtilsService/GetEmailsByTargetId" => { + #[allow(non_camel_case_types)] + struct GetEmailsByTargetIdSvc(pub Arc); + impl< + T: UtilsService, + > tonic::server::ServerStreamingService + for GetEmailsByTargetIdSvc { + type Response = super::Email; + type ResponseStream = T::GetEmailsByTargetIdStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_emails_by_target_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetEmailsByTargetIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UtilsService/SendEmail" => { + #[allow(non_camel_case_types)] + struct SendEmailSvc(pub Arc); + impl tonic::server::UnaryService + for SendEmailSvc { + type Response = super::Email; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { (*inner).send_email(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = SendEmailSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UtilsService/CountFilesByTargetId" => { + #[allow(non_camel_case_types)] + struct CountFilesByTargetIdSvc(pub Arc); + impl tonic::server::UnaryService + for CountFilesByTargetIdSvc { + type Response = super::Count; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).count_files_by_target_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CountFilesByTargetIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UtilsService/GetFilesByTargetId" => { + #[allow(non_camel_case_types)] + struct GetFilesByTargetIdSvc(pub Arc); + impl< + T: UtilsService, + > tonic::server::ServerStreamingService + for GetFilesByTargetIdSvc { + type Response = super::File; + type ResponseStream = T::GetFilesByTargetIdStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_files_by_target_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetFilesByTargetIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UtilsService/GetFileById" => { + #[allow(non_camel_case_types)] + struct GetFileByIdSvc(pub Arc); + impl< + T: UtilsService, + > tonic::server::ServerStreamingService + for GetFileByIdSvc { + type Response = super::File; + type ResponseStream = T::GetFileByIdStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_file_by_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetFileByIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UtilsService/UploadFile" => { + #[allow(non_camel_case_types)] + struct UploadFileSvc(pub Arc); + impl tonic::server::StreamingService + for UploadFileSvc { + type Response = super::File; + type ResponseStream = T::UploadFileStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request>, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { (*inner).upload_file(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = UploadFileSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/proto.UtilsService/DeleteFileById" => { + #[allow(non_camel_case_types)] + struct DeleteFileByIdSvc(pub Arc); + impl tonic::server::UnaryService + for DeleteFileByIdSvc { + type Response = super::Empty; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).delete_file_by_id(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = DeleteFileByIdSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for UtilsServiceServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::server::NamedService for UtilsServiceServer { + const NAME: &'static str = "proto.UtilsService"; + } +} diff --git a/service-notes/Cargo.lock b/service-notes/Cargo.lock index edd71292..a57d6239 100644 --- a/service-notes/Cargo.lock +++ b/service-notes/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.69" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "array-init" @@ -241,12 +241,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - [[package]] name = "either" version = "1.8.1" @@ -291,9 +285,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-io" @@ -974,7 +968,6 @@ version = "0.1.0" dependencies = [ "anyhow", "deadpool-postgres", - "dotenvy", "futures-core", "futures-util", "jsonwebtoken", diff --git a/service-notes/Cargo.toml b/service-notes/Cargo.toml index cec30009..db54d7a7 100644 --- a/service-notes/Cargo.toml +++ b/service-notes/Cargo.toml @@ -4,26 +4,23 @@ version = "0.1.0" edition = "2021" [dependencies] -# General -dotenvy = "0.15.7" -anyhow = "1.0.69" +# Main +anyhow = "1.0.72" time = "0.3.20" -tokio = { version = "1.27.0", features = ["rt-multi-thread", "macros", "sync", "time"] } -tokio-stream = "0.1.12" -futures-core = "0.3.28" -futures-util = "0.3.28" +uuid = { version = "1.3.2", features = ["default", "v7"] } +serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.96" -serde = "1.0.163" jsonwebtoken = "8.3.0" -uuid = { version = "1.6.1", features = ["default", "v7"] } # Trace tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } -# gRPC -prost = "0.11.9" -tonic = { version = "0.9.2", features = ["tls", "tls-roots"] } +# Async +tokio = { version = "1.27.0", features = ["rt-multi-thread", "macros", "sync" ] } +tokio-stream = "0.1.12" +futures-util = "0.3.28" +futures-core = "0.3.29" # Database tokio-postgres = { version = "0.7.8", features = ["with-uuid-1", "with-time-0_3", "array-impls"] } @@ -31,3 +28,8 @@ tokio-postgres-rustls = "0.10.0" rustls = "0.21.5" rustls-native-certs = "0.6.3" deadpool-postgres = "0.10.5" + +# gRPC +prost = "0.11.9" +tonic = { version = "0.9.2", features = ["tls", "tls-roots"] } + diff --git a/service-notes/src/note_service.rs b/service-notes/src/note_service.rs index b70e7b9e..6e45f506 100644 --- a/service-notes/src/note_service.rs +++ b/service-notes/src/note_service.rs @@ -9,7 +9,7 @@ use anyhow::Result; use futures_util::TryStreamExt; use tokio::sync::mpsc; use tokio_stream::wrappers::ReceiverStream; -use tonic::{transport::Endpoint, Request, Response, Status}; +use tonic::{Request, Response, Status}; #[tonic::async_trait] impl NotesService for MyService { @@ -61,17 +61,13 @@ impl NotesService for MyService { Status::internal("Failed to get notes") })?; - let endpoint: Endpoint = self.env.users_url.parse().map_err(|err| { - tracing::error!("Failed to parse users url: {:?}", err); - Status::internal("Failed to parse users url") - })?; let jwt_token = rusve_notes::generate_jwt_token(&self.env.jwt_secret, &user_id).map_err(|err| { tracing::error!("Failed to generate jwt token: {:?}", err); Status::internal("Failed to generate jwt token") })?; - let client = match UsersServiceClient::connect(endpoint).await { + let client = match UsersServiceClient::connect(self.env.users_url.to_owned()).await { Ok(client) => client, Err(e) => { tracing::error!("Failed to connect to users service: {:?}", e); diff --git a/service-users/Cargo.lock b/service-users/Cargo.lock index d580d8b3..27c94d46 100644 --- a/service-users/Cargo.lock +++ b/service-users/Cargo.lock @@ -25,6 +25,28 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.41", +] + [[package]] name = "async-stripe" version = "0.26.0" @@ -1795,6 +1817,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ + "async-stream", "async-trait", "axum", "base64 0.21.2", @@ -1809,7 +1832,10 @@ dependencies = [ "percent-encoding", "pin-project", "prost", + "rustls-native-certs", + "rustls-pemfile", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", diff --git a/service-users/Cargo.toml b/service-users/Cargo.toml index 15b8037a..cc7fc9ae 100644 --- a/service-users/Cargo.toml +++ b/service-users/Cargo.toml @@ -31,7 +31,7 @@ deadpool-postgres = "0.10.5" # gRPC prost = "0.11.9" -tonic = "0.9.2" +tonic = { version = "0.9.2", features = ["tls", "tls-roots"] } # Stripe async-stripe = { version = "*", default-features = false, features = ["runtime-tokio-hyper", "billing", "checkout"] }