refactor(tests): reformat code and update dependency management

- Reorganized import statements in adapter tests for better readability
- Replaced or_insert_with(Vec::new) with or_default() in test closures
- Updated Cargo.lock with new dependency versions and checksums
- Added TLS features to tonic dependency configuration
- Included sqlx, chrono, and uuid dependencies with specific features
- Added jsonwebtoken and arc-swap as project dependencies
- Reformatted assertion statements to comply with line length limits
- Adjusted base64 import order in engine codec module
- Updated protobuf include statement formatting
This commit is contained in:
zhenyi
2026-06-11 12:11:05 +08:00
parent 06e8ee96a5
commit 821537186e
111 changed files with 10458 additions and 385 deletions
+108
View File
@@ -0,0 +1,108 @@
//! Aggregate gRPC client holder for all appks core services.
//!
//! A single TCP `Channel` is shared across all four service clients
//! to avoid redundant connections.
use std::fs;
use std::time::Duration;
use tonic::transport::{Certificate, Channel, ClientTlsConfig, Endpoint, Identity};
use crate::pb::core::token_service_client::TokenServiceClient;
use crate::pb::im::{
channel_service_client::ChannelServiceClient, member_service_client::MemberServiceClient,
permission_service_client::PermissionServiceClient,
};
use crate::{ImksError, ImksResult};
use super::config::RpcConfig;
/// Holds gRPC clients for all appks core services consumed by imks.
///
/// Cheaply cloneable — each inner client wraps a shared `Arc<Channel>`.
#[derive(Clone)]
pub struct AppksClients {
/// JWT token lifecycle: issue, refresh, revoke, verify, signing keys.
pub token: TokenServiceClient<Channel>,
/// Channel and category CRUD + statistics.
pub channel: ChannelServiceClient<Channel>,
/// Channel member invite / kick / join / leave.
pub member: MemberServiceClient<Channel>,
/// Permission checks and overwrite rules.
pub permission: PermissionServiceClient<Channel>,
}
impl AppksClients {
/// Connect to all appks services using a shared gRPC channel.
pub async fn connect(config: &RpcConfig) -> ImksResult<Self> {
let mut endpoint = Endpoint::from_shared(config.appks_addr.clone())
.map_err(|e| ImksError::Internal(format!("Invalid gRPC endpoint: {e}")))?
.connect_timeout(Duration::from_secs(config.connect_timeout_secs));
if config.appks_addr.starts_with("https://")
|| config.tls_ca_cert_path.is_some()
|| config.tls_client_cert_path.is_some()
|| config.tls_client_key_path.is_some()
{
endpoint = endpoint.tls_config(build_tls_config(config)?)?;
}
let channel = endpoint
.connect()
.await
.map_err(|e| ImksError::Internal(format!("gRPC connect failed: {e}")))?;
tracing::info!(addr = %config.appks_addr, "Connected to appks gRPC services");
Ok(Self {
token: TokenServiceClient::new(channel.clone()),
channel: ChannelServiceClient::new(channel.clone()),
member: MemberServiceClient::new(channel.clone()),
permission: PermissionServiceClient::new(channel),
})
}
/// Build from pre-connected clients (useful for tests with mock servers).
pub fn new(
token: TokenServiceClient<Channel>,
channel: ChannelServiceClient<Channel>,
member: MemberServiceClient<Channel>,
permission: PermissionServiceClient<Channel>,
) -> Self {
Self {
token,
channel,
member,
permission,
}
}
}
fn build_tls_config(config: &RpcConfig) -> ImksResult<ClientTlsConfig> {
let mut tls = ClientTlsConfig::new();
if let Some(domain) = &config.tls_domain_name {
tls = tls.domain_name(domain);
}
if let Some(path) = &config.tls_ca_cert_path {
let pem = fs::read(path)?;
tls = tls.ca_certificate(Certificate::from_pem(pem));
}
match (&config.tls_client_cert_path, &config.tls_client_key_path) {
(Some(cert_path), Some(key_path)) => {
let cert = fs::read(cert_path)?;
let key = fs::read(key_path)?;
tls = tls.identity(Identity::from_pem(cert, key));
}
(None, None) => {}
_ => {
return Err(ImksError::InvalidInput(
"Both APPKS_GRPC_TLS_CLIENT_CERT and APPKS_GRPC_TLS_CLIENT_KEY are required for mTLS".into(),
));
}
}
Ok(tls)
}
+65
View File
@@ -0,0 +1,65 @@
//! gRPC client configuration for connecting to appks core services.
//!
//! Reads the appks address and timeout from environment variables.
use std::env;
/// Configuration for appks gRPC connections.
#[derive(Debug, Clone)]
pub struct RpcConfig {
/// appks gRPC endpoint, e.g. `http://localhost:50051`.
pub appks_addr: String,
/// Connection establishment timeout (seconds).
pub connect_timeout_secs: u64,
/// Optional CA certificate PEM path for appks mTLS.
pub tls_ca_cert_path: Option<String>,
/// Optional client certificate PEM path for appks mTLS.
pub tls_client_cert_path: Option<String>,
/// Optional client private key PEM path for appks mTLS.
pub tls_client_key_path: Option<String>,
/// TLS domain name used for certificate verification.
pub tls_domain_name: Option<String>,
}
impl RpcConfig {
/// Build config from environment variables with defaults.
pub fn from_env() -> Self {
Self {
appks_addr: env::var("APPKS_GRPC_ADDR")
.unwrap_or_else(|_| "http://localhost:50051".to_string()),
connect_timeout_secs: env::var("APPKS_GRPC_TIMEOUT")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(10),
tls_ca_cert_path: env::var("APPKS_GRPC_TLS_CA_CERT").ok(),
tls_client_cert_path: env::var("APPKS_GRPC_TLS_CLIENT_CERT").ok(),
tls_client_key_path: env::var("APPKS_GRPC_TLS_CLIENT_KEY").ok(),
tls_domain_name: env::var("APPKS_GRPC_TLS_DOMAIN").ok(),
}
}
}
impl Default for RpcConfig {
fn default() -> Self {
Self::from_env()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let cfg = RpcConfig {
appks_addr: "http://localhost:50051".to_string(),
connect_timeout_secs: 10,
tls_ca_cert_path: None,
tls_client_cert_path: None,
tls_client_key_path: None,
tls_domain_name: None,
};
assert_eq!(cfg.connect_timeout_secs, 10);
assert!(cfg.appks_addr.starts_with("http"));
}
}
+5
View File
@@ -0,0 +1,5 @@
pub mod clients;
pub mod config;
pub use clients::AppksClients;
pub use config::RpcConfig;