Skip to content
16 changes: 16 additions & 0 deletions application-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,19 @@ tracing-appender = { version = "0.2.3" }

prometheus = { version = "0.14.0" }
ulid = { version = "3.0.0" }

[workspace.lints.rust]
unsafe_code = "forbid"
unreachable_pub = "warn"
missing_docs = "allow"

[workspace.lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
unwrap_used = "warn"
expect_used = "warn"
panic = "warn"
cast_precision_loss = "allow"
derivable_impls = "allow"
must_use_candidate = "allow"
missing_errors_doc = "allow"
3 changes: 3 additions & 0 deletions application-rs/application-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ version.workspace = true
edition.workspace = true
publish.workspace = true

[lints]
workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[[bin]]
Expand Down
17 changes: 11 additions & 6 deletions application-rs/application-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,27 @@ use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::time::Duration;

mod middleware;
mod request;
mod response;
mod routes;
mod service;
mod v1;
pub mod middleware;
pub mod request;
pub mod response;
pub mod routes;
pub mod service;
pub mod v1;

pub struct App;

impl App {
/// # Panics
///
/// 当 `G_CONFIG.bin_api.listen` 不是合法的 IP 地址时 panic。此为启动期配置错误,
/// 预期 fail-fast。
pub fn listen() -> SocketAddr {
let api_config = &G_CONFIG.bin_api;

let listen = api_config.listen.as_str();
let port = api_config.port;

#[allow(clippy::expect_used)]
SocketAddr::from((
IpAddr::from_str(listen).expect("API 监听地址格式无效"),
port,
Expand Down
26 changes: 14 additions & 12 deletions application-rs/application-api/src/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ pub async fn tracing_id(
ctrl: &mut FlowCtrl,
) {
let id = Ulid::generate().to_string();
request
.headers_mut()
.insert("x-request-id", id.parse().unwrap());
response
.headers_mut()
.insert("x-request-id", id.parse().unwrap());
let request_id = id
.parse()
.unwrap_or_else(|_| salvo::http::HeaderValue::from_static("unknown"));
request.headers_mut().insert("x-request-id", request_id);
response.headers_mut().insert(
"x-request-id",
id.parse()
.unwrap_or_else(|_| salvo::http::HeaderValue::from_static("unknown")),
);

let span = tracing::info_span!("http.request", request_id = %id);
application_kernel::logger::TracingId::attach(&span, &id);
Expand All @@ -50,12 +53,11 @@ pub async fn authorization(
}};
}

let auth = match request.headers().get(AUTHORIZATION) {
Some(h) => match h.to_str() {
Ok(a) => a,
Err(_) => abort!(ErrorCode::AuthorizationInvalidFormat),
},
None => abort!(ErrorCode::AuthorizationHeaderMissing),
let Some(header) = request.headers().get(AUTHORIZATION) else {
abort!(ErrorCode::AuthorizationHeaderMissing)
};
let Ok(auth) = header.to_str() else {
abort!(ErrorCode::AuthorizationInvalidFormat)
};

let token = auth.strip_prefix("Bearer ").unwrap_or(auth);
Expand Down
4 changes: 2 additions & 2 deletions application-rs/application-api/src/request/access_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl Validator for LoginRequest {
return Ok(LoginRequestParams {
platform,
third_id: third_id.to_owned(),
code: code.to_string(),
code: code.clone(),
});
}

Expand Down Expand Up @@ -84,7 +84,7 @@ impl Validator for LoginRefreshRequest {
return Ok(LoginRefreshRequestParams {
platform,
third_id: third_id.to_owned(),
refresh_token: refresh_token.to_string(),
refresh_token: refresh_token.clone(),
});
}

Expand Down
8 changes: 4 additions & 4 deletions application-rs/application-api/src/request/totp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ impl TryFrom<Totp> for DetailResponse {
id: totp.id.to_string(),
issuer: totp
.issuer
.to_owned()
.clone()
.unwrap_or_else(|| "未知发行方".to_string()),
username: totp.username.to_owned(),
config: totp.config.deref().to_owned().into(),
username: totp.username.clone(),
config: totp.config.deref().clone().into(),
code: totp.generate_code()?,
})
}
Expand Down Expand Up @@ -111,7 +111,7 @@ impl Validator for EditIssuerRequest {

Ok(Self::Data {
id,
issuer: self.issuer.to_owned().unwrap_or_default(),
issuer: self.issuer.clone().unwrap_or_default(),
})
}
}
Expand Down
2 changes: 2 additions & 0 deletions application-rs/application-api/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ impl From<ParseError> for AppErr {

#[cfg(test)]
mod tests {
#![allow(clippy::all)]

use super::*;
use serde_json::json;

Expand Down
13 changes: 5 additions & 8 deletions application-rs/application-api/src/service/access_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub async fn login(
let (user_id, access_token_data) = match platform {
Platform::Wechat => login_wechat(request).await,
Platform::Huawei => login_huawei(request).await,
_ => Err(ErrorCode::ParamsLoginPlatformUnsupported),
Platform::Unsupported => Err(ErrorCode::ParamsLoginPlatformUnsupported),
}?;

let access_token = access_token::update_or_insert(
Expand Down Expand Up @@ -134,18 +134,15 @@ async fn get_user_id(
) -> Result<u64> {
let result = third_user::fetch(platform, third_id).await;

if let Ok(user) = result {
return Ok(user.user_id);
}

match result.unwrap_err() {
ErrorCode::ParamsThirdUserNotFound => {
match result {
Ok(user) => Ok(user.user_id),
Err(ErrorCode::ParamsThirdUserNotFound) => {
let user_id = user::insert(None, user::Config::default()).await?;

third_user::insert(platform, third_id, user_id, config).await?;

Ok(user_id)
}
e => Err(e),
Err(e) => Err(e),
}
}
4 changes: 3 additions & 1 deletion application-rs/application-api/src/service/totp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use tracing::error;
pub async fn all(access_token: &access_token::AccessToken) -> Result<Vec<DetailResponse>> {
let totp = totp::all(access_token.user_id).await?;

totp.into_iter().map(|t| t.try_into()).collect()
totp.into_iter()
.map(std::convert::TryInto::try_into)
.collect()
}

pub async fn sort(
Expand Down
4 changes: 2 additions & 2 deletions application-rs/application-api/src/v1/access_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub async fn login(request: &mut Request) -> Resp<LoginResponse> {
let (refresh_token, access_token) = service::access_token::login(&req).await?;

Ok(Response::success(LoginResponse {
access_token: access_token.access_token.to_owned(),
access_token: access_token.access_token.clone(),
expired_in: access_token.get_expired_in(),
refresh_token: refresh_token.refresh_token,
}))
Expand All @@ -30,7 +30,7 @@ pub async fn login_refresh(request: &mut Request) -> Resp<LoginRefreshResponse>
let (refresh_token, access_token) = service::access_token::login_refresh(&req).await?;

Ok(Response::success(LoginRefreshResponse {
access_token: access_token.access_token.to_owned(),
access_token: access_token.access_token.clone(),
expired_in: access_token.get_expired_in(),
refresh_token: refresh_token.refresh_token,
}))
Expand Down
3 changes: 3 additions & 0 deletions application-rs/application-database/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ version.workspace = true
edition.workspace = true
publish.workspace = true

[lints]
workspace = true

[dependencies]
application-kernel = { path = "../application-kernel" }
application-util = { path = "../application-util" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ pub async fn update(mut access_token: AccessToken, data: AccessTokenData) -> Res

#[cfg(test)]
mod tests {
#![allow(clippy::all)]

use super::*;
use chrono::Duration;

Expand Down
2 changes: 1 addition & 1 deletion application-rs/application-database/src/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl From<&Platform> for &str {
match v {
Platform::Wechat => "wechat",
Platform::Huawei => "huawei",
_ => "unsupported",
Platform::Unsupported => "unsupported",
}
}
}
Expand Down
1 change: 1 addition & 0 deletions application-rs/application-database/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ impl Pool {
}

fn connect_mysql(config: &Database) -> MySqlPool {
#[allow(clippy::expect_used)]
let connection_options =
MySqlConnectOptions::from_str(config.url.as_str()).expect("数据库 URL 格式无效");

Expand Down
2 changes: 2 additions & 0 deletions application-rs/application-database/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ macro_rules! delete {

#[cfg(test)]
mod tests {
#![allow(clippy::all)]

#[test]
fn test_insert_macro_sql_validation() {
let valid_sql = "INSERT INTO users (name) VALUES (?)";
Expand Down
6 changes: 3 additions & 3 deletions application-rs/application-database/src/tool/totp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl Totp {
pub fn generate_code(&self) -> Result<String> {
let config = &self.config;

let secret = Secret::Encoded(config.secret.to_owned())
let secret = Secret::Encoded(config.secret.clone())
.to_bytes()
.map_err(|e| {
error!("TOTP Secret 解码失败: {:?}", e);
Expand All @@ -52,8 +52,8 @@ impl Totp {
1,
config.period,
secret,
self.issuer.to_owned(),
self.username.to_owned(),
self.issuer.clone(),
self.username.clone(),
);

totp.generate_current().map_err(|e| {
Expand Down
3 changes: 3 additions & 0 deletions application-rs/application-kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ version.workspace = true
edition.workspace = true
publish.workspace = true

[lints]
workspace = true

[dependencies]
serde = { workspace = true }
chrono = { workspace = true }
Expand Down
6 changes: 4 additions & 2 deletions application-rs/application-kernel/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::collections::HashMap;
use std::sync::LazyLock;

pub static G_CONFIG: LazyLock<Config> = LazyLock::new(|| {
#[allow(clippy::expect_used)]
let config = C::builder()
.add_source(File::with_name("./config.toml").required(false))
.add_source(
Expand All @@ -16,6 +17,7 @@ pub static G_CONFIG: LazyLock<Config> = LazyLock::new(|| {
.build()
.expect("加载配置失败");

#[allow(clippy::expect_used)]
config.try_deserialize::<Config>().expect("解析配置失败")
});

Expand Down Expand Up @@ -114,11 +116,11 @@ impl Default for AccessToken {

impl AccessToken {
pub fn get_expired_at(&self) -> DateTime<Local> {
Local::now() + chrono::Duration::seconds(self.expired_in as i64)
Local::now() + chrono::Duration::seconds(i64::from(self.expired_in))
}

pub fn get_refresh_expired_at(&self) -> DateTime<Local> {
Local::now() + chrono::Duration::seconds(self.refresh_expired_in as i64)
Local::now() + chrono::Duration::seconds(i64::from(self.refresh_expired_in))
}
}

Expand Down
15 changes: 9 additions & 6 deletions application-rs/application-kernel/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,14 @@ impl ErrorCode {
match self {
Self::Success => "success",
Self::AuthorizationHeaderMissing => "认证失败: 缺少认证信息,请重新登录",
Self::AuthorizationAccessTokenInvalid => "认证失败: 认证信息不正确,请重新登录",
Self::AuthorizationAccessTokenInvalid | Self::AuthorizationRefreshTokenInvalid => {
"认证失败: 认证信息不正确,请重新登录"
}
Self::AuthorizationInvalidFormat => "认证失败: 认证信息格式不正确,请重新登录",
Self::AuthorizationPermissionUngranted => "认证失败: 未授权,请勿越权使用",
Self::AuthorizationAccessTokenExpired => "认证失败: 认证信息已过期,请重新登录",
Self::AuthorizationRefreshTokenInvalid => "认证失败: 认证信息不正确,请重新登录",
Self::AuthorizationRefreshTokenExpired => "认证失败: 认证信息已过期,请重新登录",
Self::AuthorizationAccessTokenExpired | Self::AuthorizationRefreshTokenExpired => {
"认证失败: 认证信息已过期,请重新登录"
}
Self::ParamsJsonInvalid => "参数错误: Json 解析失败,请确认您的参数是否符合规范",
Self::ParamsLoginPlatformUnsupported => "参数错误: platform 参数值不支持",
Self::ParamsLoginCodeFormatInvalid => "参数错误: 登录秘钥格式错误",
Expand All @@ -94,8 +96,7 @@ impl ErrorCode {
Self::ParamsShortlinkFormatInvalid => "参数错误: URL 格式不正确",
Self::ParamsUserSloganLengthInvalid => "参数错误: Slogan 长度应大于 3,请正确填写",
Self::ParamsUserAvatarLengthInvalid => "参数错误: 头像格式不正确,请正确填写",
Self::ParamsThirdConfigNotFound => "参数错误: 您访问的平台暂不支持,请重试或联系管理员",
Self::ParamsLoginPlatformThirdIdFormatInvalid => {
Self::ParamsThirdConfigNotFound | Self::ParamsLoginPlatformThirdIdFormatInvalid => {
"参数错误: 您访问的平台暂不支持,请重试或联系管理员"
}
Self::ParamsRefreshTokenNotFound => "参数错误: Refresh Token 未找到",
Expand Down Expand Up @@ -134,6 +135,8 @@ impl std::error::Error for ErrorCode {}

#[cfg(test)]
mod tests {
#![allow(clippy::all)]

use super::*;

#[test]
Expand Down
3 changes: 3 additions & 0 deletions application-rs/application-util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ version.workspace = true
edition.workspace = true
publish.workspace = true

[lints]
workspace = true

[dependencies]
application-kernel = { path = "../application-kernel" }

Expand Down
3 changes: 2 additions & 1 deletion application-rs/application-util/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ pub struct HttpResponse<T> {
}

static G_CLIENT: LazyLock<Client> = LazyLock::new(|| {
#[allow(clippy::expect_used)]
Client::builder()
.user_agent("yansongda/application-rs")
.connect_timeout(Duration::from_secs(1))
.timeout(Duration::from_secs(3))
.pool_idle_timeout(Duration::from_secs(30))
.pool_max_idle_per_host(8)
.tcp_keepalive(Duration::from_secs(60))
.tcp_keepalive(Duration::from_mins(1))
.tcp_nodelay(true)
.build()
.expect("HTTP 客户端初始化失败")
Expand Down
Loading