feat(auth): add authentication protocol definitions and build configuration

- Add TokenClaims message for JWT payload structure with user id, issuer, timestamps, and scopes
- Implement IssueTokenRequest/Response for creating access and refresh tokens with TTL support
- Create RefreshTokenRequest/Response for token rotation functionality
- Define RevokeTokenRequest/Response with support for single token or user-wide revocation
- Add VerifyTokenRequest/Response for validating JWT tokens with detailed claims information
- Implement signing key distribution system with GetSigningKeysRequest/Response
- Create TokenService gRPC service with IssueToken, RefreshToken, RevokeToken, VerifyToken, and GetSigningKeys methods
- Add build.rs configuration to compile proto files using tonic_prost_build
- Include channel, channel_settings, member, and permission protocol definitions for IM services
- Generate Rust code bindings through pb/core.rs and pb/im.rs modules
This commit is contained in:
zhenyi
2026-06-10 23:45:40 +08:00
commit 06e8ee96a5
43 changed files with 9671 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
use imks::engine::session::{generate_sid, SessionState, SessionStore, TransportType};
#[test]
fn test_session_store_create_and_get() {
let store = SessionStore::new();
let sid = generate_sid();
let _rx = store.create(sid.clone(), TransportType::Polling);
assert!(store.exists(&sid));
assert!(store.get(&sid).is_some());
assert_eq!(store.len(), 1);
}
#[test]
fn test_session_store_remove() {
let store = SessionStore::new();
let sid = generate_sid();
let _rx = store.create(sid.clone(), TransportType::Polling);
assert!(store.exists(&sid));
store.remove(&sid);
assert!(!store.exists(&sid));
assert!(store.get(&sid).is_none());
}
#[test]
fn test_session_store_multiple_sessions() {
let store = SessionStore::new();
let sid1 = generate_sid();
let sid2 = generate_sid();
let sid3 = generate_sid();
let _rx1 = store.create(sid1.clone(), TransportType::Polling);
let _rx2 = store.create(sid2.clone(), TransportType::WebSocket);
let _rx3 = store.create(sid3.clone(), TransportType::WebTransport);
assert_eq!(store.len(), 3);
assert!(store.exists(&sid1));
assert!(store.exists(&sid2));
assert!(store.exists(&sid3));
}
#[test]
fn test_generate_sid_uniqueness() {
let sids: Vec<String> = (0..100).map(|_| generate_sid()).collect();
let unique_sids: std::collections::HashSet<String> = sids.into_iter().collect();
assert_eq!(unique_sids.len(), 100);
}
#[test]
fn test_generate_sid_format() {
let sid = generate_sid();
assert_eq!(sid.len(), 20);
assert!(sid.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'));
}
#[tokio::test]
async fn test_session_state_transitions() {
let store = SessionStore::new();
let sid = generate_sid();
let _rx = store.create(sid.clone(), TransportType::Polling);
if let Some(session) = store.get(&sid) {
let mut session = session.write().await;
assert_eq!(session.state, SessionState::Connecting);
session.set_state(SessionState::Open);
assert_eq!(session.state, SessionState::Open);
session.set_state(SessionState::Upgrading);
assert_eq!(session.state, SessionState::Upgrading);
session.set_state(SessionState::Open);
assert_eq!(session.state, SessionState::Open);
session.set_state(SessionState::Closing);
assert_eq!(session.state, SessionState::Closing);
session.set_state(SessionState::Closed);
assert_eq!(session.state, SessionState::Closed);
}
}
#[tokio::test]
async fn test_session_transport_change() {
let store = SessionStore::new();
let sid = generate_sid();
let _rx = store.create(sid.clone(), TransportType::Polling);
if let Some(session) = store.get(&sid) {
let mut session = session.write().await;
assert_eq!(session.transport, TransportType::Polling);
session.set_transport(TransportType::WebSocket);
assert_eq!(session.transport, TransportType::WebSocket);
}
}
#[tokio::test]
async fn test_session_ping_update() {
let store = SessionStore::new();
let sid = generate_sid();
let _rx = store.create(sid.clone(), TransportType::Polling);
if let Some(session) = store.get(&sid) {
let mut session = session.write().await;
let initial_ping = session.last_ping;
std::thread::sleep(std::time::Duration::from_millis(10));
session.update_ping();
assert!(session.last_ping > initial_ping);
}
}
#[test]
fn test_transport_type_as_str() {
assert_eq!(TransportType::Polling.as_str(), "polling");
assert_eq!(TransportType::WebSocket.as_str(), "websocket");
assert_eq!(TransportType::WebTransport.as_str(), "webtransport");
}