Skip to content

Commit

Permalink
feat: add grpc support (#2)
Browse files Browse the repository at this point in the history
* feat: update db funcs

* feat: grpc demo

* feat: grpc

* feat: 实现 fruitbox-iam 的 gRPC 用户及登录接口

* feat: 添加了 role, permission 的 .proto 定义

* feat: Permission

* feat: permission and role

* lint: clippy-all

* feat: grpc reflection

* feat: tonic-web 和 tonic-reflection 条件编译

* feat: remove fruitbox-iam

---------

Co-authored-by: Yang Jing <[email protected]>
  • Loading branch information
yangbajing and yangjing authored Sep 11, 2024
1 parent 6a4c997 commit d2aabaf
Show file tree
Hide file tree
Showing 57 changed files with 847 additions and 380 deletions.
26 changes: 25 additions & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 设置运行 cargo 时的系统环境变量
[env]
RUST_LOG = "info,tower_http=debug,ultimate=debug,ultimate_common=debug"
RUST_LOG = "info,tower_http=debug,fruitbox_iam=debug,ultimate_web=debug,ultimate_db=debug,ultimate=debug,ultimate_common=debug"

[alias]
clippy-all = "clippy --all-features -- -D warnings"
Expand All @@ -9,3 +9,27 @@ check-all = "check --all-features"
# 设置 rustc 编译器参数
# [build]
# rustflags = ["--cfg", "uuid_unstable"]


# On Windows
# ```
# cargo install -f cargo-binutils
# rustup component add llvm-tools-preview
# ```
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
[target.x86_64-pc-windows-gnu]
rustflags = ["-C", "link-arg=-fuse-ld=lld"]

# On Linux:
# - Ubuntu, `sudo apt-get install lld clang`
# - Arch, `sudo pacman -S lld clang`
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "linker=clang", "-C", "link-arg=-fuse-ld=lld"]

# On MacOS, `brew install michaeleisel/zld/zld`
#[target.x86_64-apple-darwin]
#rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/zld"]
#[target.aarch64-apple-darwin]
#rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/zld"]

4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,7 @@
"accessibility.signals.positionHasError": {
"sound": "off"
},
"editor.tabSize": 2
"editor.tabSize": 2,
"rust-analyzer.cargo.buildScripts.enable": true,
"editor.formatOnSave": true
}
33 changes: 24 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ resolver = "2"
[workspace.package]
version = "0.1.0"
edition = "2021"
rust-version = "1.79"
rust-version = "1.80"
description = "Rust libraries of The ultimate-common"
license-file = "LICENSE"
repository = "https://gitee.com/yangbajing/ultimate-common"
Expand All @@ -17,13 +17,17 @@ unsafe_code = "forbid"
[workspace.dependencies]
# -- projects begin
cloud-storage = { version = "0.1", path = "crates/storage" }
weixin-common = { version = "0.1", path = "crates/weixin-common" }
weixin-sdk = { version = "0.1", path = "crates/weixin-sdk" }
wework-sdk = { version = "0.1", path = "crates/wework-sdk" }
huaweicloud-sdk-obs = { version = "0.1", path = "crates/huaweicloud-sdk-obs" }
huaweicloud-sdk-core = { version = "0.1", path = "crates/huaweicloud-sdk-core" }
ultimate-common = { version = "0.1", path = "crates/ultimate-common" }
ultimate = { version = "0.1", path = "crates/ultimate" }
ultimate-api = { version = "0.1", path = "crates/ultimate-api" }
ultimate-db = { version = "0.1", path = "crates/ultimate-db" }
ultimate-web = { version = "0.1", path = "crates/ultimate-web" }
ultimate-grpc = { version = "0.1", path = "crates/ultimate-grpc" }
# -- projects end
# begin -- memory allocator
tikv-jemallocator = "0.6"
Expand Down Expand Up @@ -53,9 +57,10 @@ chrono = { version = "0.4", default-features = false, features = [
"clock",
"serde",
] }
typed-builder = "0.19"
typed-builder = "0.20"
derive-getters = "0.5"
clap = { version = "4.5.7", features = ["derive"] }
o2o = { version = "0.4" }
# -- Helpful macros for working with enums and strings
enum-iterator = "2"
# -- Error
Expand All @@ -74,6 +79,7 @@ aliri = "0.6"
# -- Async
futures = "0.3"
async-trait = "0.1"
async-stream = "0.3"
tokio = { version = "1", features = [
"rt",
"rt-multi-thread",
Expand Down Expand Up @@ -119,21 +125,25 @@ urlencoding = "2.1"
serde_urlencoded = "0.7"
headers = "0.4"
mime = "0.3"
http = "1.1"
reqwest = { version = "0.12", features = ["json"] }
hyper = "1"
hyper-util = "0.1"
tower = "0.5"
tower-http = { version = "0.5", features = [
"fs",
"trace",
"cors",
"compression-full",
] }
tower-service = { version = "0.3" }
tower-cookies = "0.10"
cookie = "0.18"
axum = { version = "0.7", features = ["macros", "form"] }
axum-extra = { version = "0.9", features = ["typed-header"] }
axum-macros = { version = "0.4" }
# openapi
utoipa = { version = "5.0.0-alpha", features = [
utoipa = { version = "5.0.0-beta", features = [
"axum_extras",
"chrono",
"decimal",
Expand All @@ -142,23 +152,28 @@ utoipa = { version = "5.0.0-alpha", features = [
"preserve_order",
"preserve_path_order",
] }
utoipa-scalar = { version = "0.2.0-alpha", features = ["axum"] }
utoipa-scalar = { version = "0.2.0-beta", features = ["axum"] }
# -- Dev/Test
asserhttp = { version = "0.7.1", features = ["reqwest"] }
asserhttp = { version = "0.7", features = ["reqwest"] }
dotenvy = "0.15"
# -- Data Science
polars = "0.41"
polars = "0.42"
# An Excel/OpenDocument Spreadsheets reader and deserializer in pure rust
calamine = "0.25"
# -- RPC
tonic = "0.12"
tonic-types = "0.12"
tonic-reflection = "0.12"
tonic-web = "0.12"
tonic-build = { version = "0.12", features = ["prost"] }
prost = "0.13"
prost-build = "0.13"
prost-types = "0.13"

# -- opendal
opendal = { version = "0.48", features = ["services-obs"] }
opendal = { version = "0.49", features = ["services-obs"] }

# build-dependencies
# tonic-build = "0.12"
strum = { version = "0.26", features = ["derive"] }
strum_macros = "0.26"

pretty_assertions = "1.4"
19 changes: 19 additions & 0 deletions crates/ultimate-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "ultimate-api"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
description.workspace = true
license-file.workspace = true
repository.workspace = true

[lints]
workspace = true

[dependencies]
serde = { workspace = true }
serde_repr = { workspace = true }
bytes = { workspace = true }
prost = { workspace = true }
utoipa = { workspace = true, optional = true }
modql = { workspace = true, optional = true }
1 change: 1 addition & 0 deletions crates/ultimate-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod v1;
3 changes: 3 additions & 0 deletions crates/ultimate-api/src/v1/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod page;

pub use page::*;
177 changes: 177 additions & 0 deletions crates/ultimate-api/src/v1/page.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};

#[derive(Clone, PartialEq, ::prost::Message, Serialize)]
pub struct OperationResponse {
#[prost(int32, tag = "1")]
pub code: i32,
#[prost(string, optional, tag = "2")]
pub message: ::core::option::Option<::prost::alloc::string::String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct PagePayload<T> {
pub page: Page,
pub items: Vec<T>,
}

impl<T> PagePayload<T> {
pub fn new(page: Page, items: Vec<T>) -> Self {
Self { page, items }
}
}

#[derive(Clone, PartialEq, ::prost::Message, Serialize, Deserialize)]
pub struct Pagination {
#[prost(int64, tag = "1")]
pub page: i64,
#[prost(int64, tag = "2")]
pub page_size: i64,
#[prost(message, repeated, tag = "3")]
pub sort_bys: ::prost::alloc::vec::Vec<SortBy>,
#[prost(int64, optional, tag = "4")]
pub offset: ::core::option::Option<i64>,
}

impl Pagination {
pub fn page(&self) -> i64 {
self.page
}

pub fn page_size(&self) -> i64 {
self.page_size
}

pub fn sort_bys(&self) -> Vec<&SortBy> {
self.sort_bys.iter().collect()
}

pub fn offset_value(&self) -> i64 {
if let Some(offset) = self.offset {
return offset;
}
let page = self.page();
let page_size = self.page_size();
if page < 2 {
return 0;
}
page_size * (page - 1)
}

pub fn new_default() -> Self {
Self {
page: default_page(),
page_size: default_page_size(),
sort_bys: Default::default(),
offset: Default::default(),
}
}
}

#[derive(Clone, Copy, PartialEq, ::prost::Message, Serialize, Deserialize)]
pub struct Page {
#[prost(int64, tag = "1")]
pub page: i64,
#[prost(int64, tag = "2")]
pub page_size: i64,
#[prost(int64, tag = "3")]
pub total_size: i64,
#[prost(int64, tag = "4")]
pub total_page: i64,
}

impl Page {
pub fn new(pagination: &Pagination, total_size: i64) -> Self {
let page = pagination.page;
let page_size = pagination.page_size;
let total_page = if total_size == 0 { 0 } else { (total_size + page_size - 1) / page_size };
Self { page, page_size, total_size, total_page }
}
}

#[derive(Clone, PartialEq, ::prost::Message, Serialize, Deserialize)]
pub struct SortBy {
#[prost(string, tag = "1")]
pub f: ::prost::alloc::string::String,
#[prost(enumeration = "SortDirection", tag = "2")]
pub d: i32,
}

#[cfg(feature = "modql")]
impl From<SortBy> for modql::filter::OrderBy {
fn from(value: SortBy) -> Self {
match value.d.try_into().unwrap_or_default() {
SortDirection::ASC => modql::filter::OrderBy::Asc(value.f),
SortDirection::DESC => modql::filter::OrderBy::Desc(value.f),
}
}
}

#[cfg(feature = "modql")]
impl From<&SortBy> for modql::filter::OrderBy {
fn from(value: &SortBy) -> Self {
match value.d.try_into().unwrap_or_default() {
SortDirection::ASC => modql::filter::OrderBy::Asc(value.f.clone()),
SortDirection::DESC => modql::filter::OrderBy::Desc(value.f.clone()),
}
}
}

#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, Serialize_repr, Deserialize_repr,
)]
#[repr(i32)]
#[allow(non_camel_case_types)]
pub enum SortDirection {
ASC = 0,
DESC = 1,
}

impl SortDirection {
/// 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 {
SortDirection::ASC => "ASC",
SortDirection::DESC => "DESC",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"ASC" => Some(Self::ASC),
"DESC" => Some(Self::DESC),
_ => None,
}
}
}

#[cfg(feature = "modql")]
impl From<Pagination> for modql::filter::ListOptions {
fn from(value: Pagination) -> Self {
let offset = Some(value.offset_value());
let limit = Some(if value.page_size > 0 { value.page_size } else { default_page_size() });
let order_bys = Some(modql::filter::OrderBys::new(value.sort_bys.into_iter().map(Into::into).collect()));
modql::filter::ListOptions { limit, offset, order_bys }
}
}

#[cfg(feature = "modql")]
impl From<&Pagination> for modql::filter::ListOptions {
fn from(value: &Pagination) -> Self {
let offset = Some(value.offset_value());
let limit = Some(if value.page_size > 0 { value.page_size } else { default_page_size() });
let order_bys = Some(modql::filter::OrderBys::new(value.sort_bys.iter().map(|v| v.into()).collect()));
modql::filter::ListOptions { limit, offset, order_bys }
}
}

fn default_page() -> i64 {
1
}

fn default_page_size() -> i64 {
20
}
3 changes: 3 additions & 0 deletions crates/ultimate-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ license-file.workspace = true
repository.workspace = true
readme = "README.md"

[features]
prost = ["dep:prost-types"]

[dependencies]
thiserror.workspace = true
serde.workspace = true
Expand Down
8 changes: 6 additions & 2 deletions crates/ultimate-common/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,21 @@ pub fn now_utc_plus_sec_str(sec: u64) -> Result<String> {
format_time(new_time)
}

pub fn from_milliseconds(milliseconds: i64) -> DateTime<Utc> {
DateTime::<Utc>::MIN_UTC + Duration::milliseconds(milliseconds)
}

pub fn parse_utc(moment: &str) -> Result<UtcDateTime> {
let time = moment.parse::<UtcDateTime>().unwrap();
Ok(time)
}

#[cfg(feature = "prost-types")]
#[cfg(feature = "prost")]
pub fn to_prost_timestamp(d: &UtcDateTime) -> prost_types::Timestamp {
prost_types::Timestamp { seconds: d.timestamp(), nanos: d.timestamp_subsec_nanos() as i32 }
}

#[cfg(feature = "prost-types")]
#[cfg(feature = "prost")]
pub fn from_prost_timestamp(t: &prost_types::Timestamp) -> Option<UtcDateTime> {
DateTime::from_timestamp(t.seconds, t.nanos as u32)
}
Expand Down
Loading

0 comments on commit d2aabaf

Please sign in to comment.