mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2025-09-10 13:12:49 +02:00
Upload files to "src/core"
This commit is contained in:
parent
f84966f5a2
commit
baa720b769
4 changed files with 1599 additions and 0 deletions
408
src/core/docs_api_guide.rs
Normal file
408
src/core/docs_api_guide.rs
Normal file
|
@ -0,0 +1,408 @@
|
|||
//! API Guide for Continuwuity Enhanced Types
|
||||
//!
|
||||
//! This module provides a comprehensive guide for using our enhanced types
|
||||
//! and error handling in Continuwuity applications.
|
||||
|
||||
use crate::types::*;
|
||||
use crate::error::*;
|
||||
|
||||
/// API Guide: Enhanced Error Handling
|
||||
///
|
||||
/// Our enhanced error system provides better user experience and debugging capabilities.
|
||||
///
|
||||
/// # Key Features
|
||||
///
|
||||
/// - **User-friendly messages**: Clear, actionable error messages for users
|
||||
/// - **Sanitized logging**: Safe error messages for logs without sensitive data
|
||||
/// - **Matrix compliance**: Proper Matrix error codes and HTTP status codes
|
||||
/// - **Contextual information**: Rich error context for better debugging
|
||||
///
|
||||
/// # Usage Examples
|
||||
///
|
||||
/// ## Creating Errors
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::error::*;
|
||||
///
|
||||
/// // Authentication errors
|
||||
/// let auth_error = EnhancedError::auth_failed("Invalid token");
|
||||
///
|
||||
/// // Room errors
|
||||
/// let room_error = EnhancedError::room_not_found("!room123:example.com");
|
||||
///
|
||||
/// // User errors
|
||||
/// let user_error = EnhancedError::user_not_found("@user:example.com");
|
||||
///
|
||||
/// // Permission errors
|
||||
/// let perm_error = EnhancedError::insufficient_permissions("Admin role required");
|
||||
///
|
||||
/// // Federation errors
|
||||
/// let fed_error = EnhancedError::federation_error("matrix.org", "Connection timeout");
|
||||
///
|
||||
/// // Configuration errors
|
||||
/// let config_error = EnhancedError::config_error("database_url", "Invalid format");
|
||||
///
|
||||
/// // Database errors
|
||||
/// let db_error = EnhancedError::database_error("user_lookup", "Connection lost");
|
||||
///
|
||||
/// // Network errors
|
||||
/// let net_error = EnhancedError::network_error("federation", "DNS resolution failed");
|
||||
///
|
||||
/// // Validation errors
|
||||
/// let val_error = EnhancedError::validation_error("room_name", "Too long");
|
||||
///
|
||||
/// // Rate limit errors
|
||||
/// let rate_error = EnhancedError::rate_limit_exceeded("room_creation", 60);
|
||||
/// ```
|
||||
///
|
||||
/// ## Using Error Information
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::error::*;
|
||||
///
|
||||
/// let error = EnhancedError::room_not_found("!room123:example.com");
|
||||
///
|
||||
/// // Get user-friendly message
|
||||
/// let user_msg = error.user_message();
|
||||
/// // "The room '!room123:example.com' could not be found. It may have been deleted or you may not have access."
|
||||
///
|
||||
/// // Get sanitized message for logging
|
||||
/// let log_msg = error.sanitized_message();
|
||||
/// // "Room not found: !room123:example.com"
|
||||
///
|
||||
/// // Get Matrix error code
|
||||
/// let matrix_code = error.matrix_error_code();
|
||||
/// // "M_NOT_FOUND"
|
||||
///
|
||||
/// // Get HTTP status code
|
||||
/// let http_code = error.http_status_code();
|
||||
/// // 404
|
||||
/// ```
|
||||
pub fn enhanced_error_guide() {
|
||||
// This function demonstrates the enhanced error handling API
|
||||
let _auth_error = EnhancedError::auth_failed("Invalid token");
|
||||
let _room_error = EnhancedError::room_not_found("!room123:example.com");
|
||||
let _user_error = EnhancedError::user_not_found("@user:example.com");
|
||||
}
|
||||
|
||||
/// API Guide: Enhanced Room Types
|
||||
///
|
||||
/// Our enhanced room types provide better organization and functionality for room operations.
|
||||
///
|
||||
/// # Key Features
|
||||
///
|
||||
/// - **Rich room information**: Comprehensive room data with metadata
|
||||
/// - **Permission checking**: Built-in methods for checking user permissions
|
||||
/// - **Power level management**: Easy power level configuration and checking
|
||||
/// - **State management**: Proper room state handling
|
||||
///
|
||||
/// # Usage Examples
|
||||
///
|
||||
/// ## Creating Room Information
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let room = EnhancedRoomInfo::new("!room123:example.com".to_string());
|
||||
///
|
||||
/// // Set room properties
|
||||
/// let mut room = EnhancedRoomInfo::new("!room123:example.com".to_string());
|
||||
/// room.name = Some("My Awesome Room".to_string());
|
||||
/// room.topic = Some("A room for awesome discussions".to_string());
|
||||
/// room.is_public = true;
|
||||
/// room.join_rule = JoinRule::Public;
|
||||
/// ```
|
||||
///
|
||||
/// ## Checking Permissions
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let room = EnhancedRoomInfo::new("!room123:example.com".to_string());
|
||||
///
|
||||
/// // Check if user is admin
|
||||
/// let is_admin = room.is_admin("@admin:example.com");
|
||||
///
|
||||
/// // Check if user can send messages
|
||||
/// let can_send = room.can_send_message("@user:example.com");
|
||||
/// ```
|
||||
///
|
||||
/// ## Power Level Management
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut power_levels = PowerLevels::default();
|
||||
/// power_levels.users.insert("@admin:example.com".to_string(), 100);
|
||||
/// power_levels.users.insert("@moderator:example.com".to_string(), 50);
|
||||
/// power_levels.events_default = 0;
|
||||
/// power_levels.state_default = 50;
|
||||
/// ```
|
||||
pub fn enhanced_room_guide() {
|
||||
// This function demonstrates the enhanced room types API
|
||||
let room = EnhancedRoomInfo::new("!room123:example.com".to_string());
|
||||
let _is_admin = room.is_admin("@admin:example.com");
|
||||
let _can_send = room.can_send_message("@user:example.com");
|
||||
}
|
||||
|
||||
/// API Guide: Enhanced User Types
|
||||
///
|
||||
/// Our enhanced user types provide better user information and management.
|
||||
///
|
||||
/// # Key Features
|
||||
///
|
||||
/// - **Rich user information**: Comprehensive user data with presence
|
||||
/// - **Membership checking**: Built-in methods for checking user membership
|
||||
/// - **Permission checking**: Easy permission level checking
|
||||
/// - **Profile management**: Complete user profile information
|
||||
///
|
||||
/// # Usage Examples
|
||||
///
|
||||
/// ## Creating User Information
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let user = EnhancedUserInfo::new("@user:example.com".to_string());
|
||||
///
|
||||
/// // Set user properties
|
||||
/// let mut user = EnhancedUserInfo::new("@user:example.com".to_string());
|
||||
/// user.display_name = Some("Alice".to_string());
|
||||
/// user.avatar_url = Some("mxc://example.com/avatar123".to_string());
|
||||
/// user.is_online = true;
|
||||
/// user.power_level = 50;
|
||||
/// user.membership_state = MembershipState::Join;
|
||||
/// ```
|
||||
///
|
||||
/// ## Checking User Status
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let user = EnhancedUserInfo::new("@user:example.com".to_string());
|
||||
///
|
||||
/// // Check if user is a member
|
||||
/// let is_member = user.is_member();
|
||||
///
|
||||
/// // Check if user is a moderator
|
||||
/// let is_moderator = user.is_moderator();
|
||||
/// ```
|
||||
///
|
||||
/// ## User Profiles
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let profile = EnhancedUserProfile {
|
||||
/// user_id: "@alice:example.com".to_string(),
|
||||
/// display_name: Some("Alice".to_string()),
|
||||
/// avatar_url: Some("mxc://example.com/avatar123".to_string()),
|
||||
/// is_online: true,
|
||||
/// last_seen: Some(1640995200),
|
||||
/// presence: PresenceState::Online,
|
||||
/// status_msg: Some("Working on Matrix stuff".to_string()),
|
||||
/// };
|
||||
/// ```
|
||||
pub fn enhanced_user_guide() {
|
||||
// This function demonstrates the enhanced user types API
|
||||
let user = EnhancedUserInfo::new("@user:example.com".to_string());
|
||||
let _is_member = user.is_member();
|
||||
let _is_moderator = user.is_moderator();
|
||||
}
|
||||
|
||||
/// API Guide: Enhanced Message Types
|
||||
///
|
||||
/// Our enhanced message types provide better message handling and processing.
|
||||
///
|
||||
/// # Key Features
|
||||
///
|
||||
/// - **Rich message content**: Comprehensive message data with metadata
|
||||
/// - **Reply handling**: Built-in support for message replies
|
||||
/// - **Thread support**: Easy thread message handling
|
||||
/// - **Mention support**: Built-in mention handling
|
||||
///
|
||||
/// # Usage Examples
|
||||
///
|
||||
/// ## Creating Messages
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// // Create a simple text message
|
||||
/// let message = EnhancedMessageContent::new_text("Hello, world!".to_string());
|
||||
///
|
||||
/// // Create a notice message
|
||||
/// let notice = EnhancedMessageContent::new_notice("System message".to_string());
|
||||
/// ```
|
||||
///
|
||||
/// ## Creating Replies
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let mut reply = EnhancedMessageContent::new_text("This is a reply".to_string());
|
||||
/// reply.relates_to = Some(RelatesTo {
|
||||
/// in_reply_to: Some(InReplyTo {
|
||||
/// event_id: "$original_event_id".to_string(),
|
||||
/// }),
|
||||
/// rel_type: None,
|
||||
/// event_id: None,
|
||||
/// });
|
||||
///
|
||||
/// // Check if message is a reply
|
||||
/// let is_reply = reply.is_reply();
|
||||
/// ```
|
||||
///
|
||||
/// ## Creating Thread Messages
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let mut thread_message = EnhancedMessageContent::new_text("Thread message".to_string());
|
||||
/// thread_message.thread = Some(ThreadInfo {
|
||||
/// event_id: "$thread_root_event_id".to_string(),
|
||||
/// is_falling_back: None,
|
||||
/// is_editing: None,
|
||||
/// });
|
||||
///
|
||||
/// // Check if message is in a thread
|
||||
/// let is_thread = thread_message.is_thread();
|
||||
/// ```
|
||||
///
|
||||
/// ## Adding Mentions
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let mut message = EnhancedMessageContent::new_text("Hello @alice:example.com!".to_string());
|
||||
/// message.mentions = Some(Mentions {
|
||||
/// user_ids: vec!["@alice:example.com".to_string()],
|
||||
/// room: false,
|
||||
/// });
|
||||
/// ```
|
||||
pub fn enhanced_message_guide() {
|
||||
// This function demonstrates the enhanced message types API
|
||||
let message = EnhancedMessageContent::new_text("Hello, world!".to_string());
|
||||
let _is_reply = message.is_reply();
|
||||
let _is_thread = message.is_thread();
|
||||
}
|
||||
|
||||
/// API Guide: Room Creation and Management
|
||||
///
|
||||
/// Our enhanced types provide better room creation and management capabilities.
|
||||
///
|
||||
/// # Key Features
|
||||
///
|
||||
/// - **Structured room creation**: Well-defined room creation requests
|
||||
/// - **Member management**: Easy room member handling
|
||||
/// - **Room summaries**: Rich room information for listings
|
||||
/// - **State management**: Proper room state handling
|
||||
///
|
||||
/// # Usage Examples
|
||||
///
|
||||
/// ## Creating Rooms
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let room_request = EnhancedRoomCreateRequest {
|
||||
/// name: Some("My Awesome Room".to_string()),
|
||||
/// topic: Some("A room for awesome discussions".to_string()),
|
||||
/// preset: Some(RoomPreset::PublicChat),
|
||||
/// room_version: Some("10".to_string()),
|
||||
/// is_direct: Some(false),
|
||||
/// invite: Some(vec!["@alice:example.com".to_string()]),
|
||||
/// initial_state: None,
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// ## Managing Room Members
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let member = EnhancedRoomMember {
|
||||
/// user_id: "@alice:example.com".to_string(),
|
||||
/// display_name: Some("Alice".to_string()),
|
||||
/// avatar_url: Some("mxc://example.com/avatar123".to_string()),
|
||||
/// membership: MembershipState::Join,
|
||||
/// power_level: 50,
|
||||
/// is_direct: false,
|
||||
/// third_party_invite: None,
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// ## Room Summaries
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let room_summary = EnhancedRoomSummary {
|
||||
/// room_id: "!room123:example.com".to_string(),
|
||||
/// name: Some("General Discussion".to_string()),
|
||||
/// topic: Some("A place for general chat".to_string()),
|
||||
/// avatar_url: Some("mxc://example.com/room_avatar".to_string()),
|
||||
/// member_count: 42,
|
||||
/// is_public: true,
|
||||
/// last_activity: 1640995200,
|
||||
/// unread_count: 5,
|
||||
/// highlight_count: 2,
|
||||
/// notification_count: 7,
|
||||
/// };
|
||||
/// ```
|
||||
pub fn room_management_guide() {
|
||||
// This function demonstrates the room management API
|
||||
let _room_request = EnhancedRoomCreateRequest {
|
||||
name: Some("Example Room".to_string()),
|
||||
topic: Some("Example topic".to_string()),
|
||||
preset: Some(RoomPreset::PublicChat),
|
||||
room_version: Some("10".to_string()),
|
||||
is_direct: Some(false),
|
||||
invite: None,
|
||||
initial_state: None,
|
||||
};
|
||||
|
||||
let _room_summary = EnhancedRoomSummary {
|
||||
room_id: "!room123:example.com".to_string(),
|
||||
name: Some("General Discussion".to_string()),
|
||||
topic: Some("A place for general chat".to_string()),
|
||||
avatar_url: Some("mxc://example.com/room_avatar".to_string()),
|
||||
member_count: 42,
|
||||
is_public: true,
|
||||
last_activity: 1640995200,
|
||||
unread_count: 5,
|
||||
highlight_count: 2,
|
||||
notification_count: 7,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_enhanced_error_guide() {
|
||||
enhanced_error_guide();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enhanced_room_guide() {
|
||||
enhanced_room_guide();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enhanced_user_guide() {
|
||||
enhanced_user_guide();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enhanced_message_guide() {
|
||||
enhanced_message_guide();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_room_management_guide() {
|
||||
room_management_guide();
|
||||
}
|
||||
}
|
379
src/core/docs_best_practices.rs
Normal file
379
src/core/docs_best_practices.rs
Normal file
|
@ -0,0 +1,379 @@
|
|||
//! Best Practices for Continuwuity Development
|
||||
//!
|
||||
//! This module provides best practices and guidelines for developing
|
||||
//! with Continuwuity and our enhanced types.
|
||||
|
||||
use crate::types::*;
|
||||
use crate::error::*;
|
||||
|
||||
/// Best Practice: Error Handling
|
||||
///
|
||||
/// Always use our enhanced error types for better user experience.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Use Enhanced Errors**: Always use `EnhancedError` for user-facing errors
|
||||
/// 2. **Provide Context**: Include relevant context in error messages
|
||||
/// 3. **Sanitize Logs**: Use `sanitized_message()` for logging to avoid sensitive data
|
||||
/// 4. **Return Proper Codes**: Ensure Matrix error codes are correct
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::error::*;
|
||||
///
|
||||
/// fn validate_room_id(room_id: &str) -> Result<(), EnhancedError> {
|
||||
/// if room_id.is_empty() {
|
||||
/// return Err(EnhancedError::validation_error("room_id", "Room ID cannot be empty"));
|
||||
/// }
|
||||
///
|
||||
/// if !room_id.starts_with('!') {
|
||||
/// return Err(EnhancedError::validation_error("room_id", "Room ID must start with '!'"));
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn error_handling_best_practices() {
|
||||
// This function demonstrates error handling best practices
|
||||
let _example_error = EnhancedError::validation_error("room_id", "Room ID cannot be empty");
|
||||
}
|
||||
|
||||
/// Best Practice: Room Management
|
||||
///
|
||||
/// Use enhanced types for room operations to ensure consistency.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Use Enhanced Types**: Always use `EnhancedRoomInfo` for room data
|
||||
/// 2. **Validate Permissions**: Check power levels before operations
|
||||
/// 3. **Handle State Changes**: Properly manage room state transitions
|
||||
/// 4. **Log Important Events**: Log room creation, member changes, etc.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// fn can_user_send_message(room: &EnhancedRoomInfo, user_id: &str) -> bool {
|
||||
/// room.can_send_message(user_id)
|
||||
/// }
|
||||
///
|
||||
/// fn is_user_admin(room: &EnhancedRoomInfo, user_id: &str) -> bool {
|
||||
/// room.is_admin(user_id)
|
||||
/// }
|
||||
/// ```
|
||||
pub fn room_management_best_practices() {
|
||||
// This function demonstrates room management best practices
|
||||
let room = EnhancedRoomInfo::new("!example:example.com".to_string());
|
||||
let _can_send = room.can_send_message("@user:example.com");
|
||||
let _is_admin = room.is_admin("@admin:example.com");
|
||||
}
|
||||
|
||||
/// Best Practice: Message Handling
|
||||
///
|
||||
/// Use enhanced message types for consistent message processing.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Use Enhanced Types**: Always use `EnhancedMessageContent` for messages
|
||||
/// 2. **Handle Replies**: Properly process reply relationships
|
||||
/// 3. **Support Threads**: Handle thread messages correctly
|
||||
/// 4. **Validate Content**: Check message content before processing
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// fn process_message(message: &EnhancedMessageContent) -> Result<(), EnhancedError> {
|
||||
/// if message.body.is_empty() {
|
||||
/// return Err(EnhancedError::validation_error("body", "Message body cannot be empty"));
|
||||
/// }
|
||||
///
|
||||
/// if message.is_reply() {
|
||||
/// // Handle reply logic
|
||||
/// }
|
||||
///
|
||||
/// if message.is_thread() {
|
||||
/// // Handle thread logic
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn message_handling_best_practices() {
|
||||
// This function demonstrates message handling best practices
|
||||
let message = EnhancedMessageContent::new_text("Hello, world!".to_string());
|
||||
let _is_reply = message.is_reply();
|
||||
let _is_thread = message.is_thread();
|
||||
}
|
||||
|
||||
/// Best Practice: User Management
|
||||
///
|
||||
/// Use enhanced user types for consistent user operations.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Use Enhanced Types**: Always use `EnhancedUserInfo` for user data
|
||||
/// 2. **Check Membership**: Verify user membership before operations
|
||||
/// 3. **Handle Permissions**: Check user permissions appropriately
|
||||
/// 4. **Update Presence**: Keep user presence information current
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// fn can_user_access_room(user: &EnhancedUserInfo, room: &EnhancedRoomInfo) -> bool {
|
||||
/// user.is_member() && room.can_send_message(&user.user_id)
|
||||
/// }
|
||||
///
|
||||
/// fn is_user_moderator(user: &EnhancedUserInfo) -> bool {
|
||||
/// user.is_moderator()
|
||||
/// }
|
||||
/// ```
|
||||
pub fn user_management_best_practices() {
|
||||
// This function demonstrates user management best practices
|
||||
let user = EnhancedUserInfo::new("@user:example.com".to_string());
|
||||
let _is_member = user.is_member();
|
||||
let _is_moderator = user.is_moderator();
|
||||
}
|
||||
|
||||
/// Best Practice: Power Level Management
|
||||
///
|
||||
/// Properly manage power levels for room permissions.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Use Default Values**: Start with sensible defaults
|
||||
/// 2. **Document Changes**: Log power level changes
|
||||
/// 3. **Validate Levels**: Ensure power levels are within valid ranges
|
||||
/// 4. **Handle Inheritance**: Properly handle power level inheritance
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// fn set_user_power_level(power_levels: &mut PowerLevels, user_id: &str, level: i32) -> Result<(), EnhancedError> {
|
||||
/// if level < -1 || level > 100 {
|
||||
/// return Err(EnhancedError::validation_error("power_level", "Power level must be between -1 and 100"));
|
||||
/// }
|
||||
///
|
||||
/// power_levels.users.insert(user_id.to_string(), level);
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn power_level_management_best_practices() {
|
||||
// This function demonstrates power level management best practices
|
||||
let mut power_levels = PowerLevels::default();
|
||||
power_levels.users.insert("@user:example.com".to_string(), 0);
|
||||
}
|
||||
|
||||
/// Best Practice: Federation Handling
|
||||
///
|
||||
/// Properly handle federation operations with enhanced error types.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Use Enhanced Errors**: Use `EnhancedError::federation_error` for federation issues
|
||||
/// 2. **Handle Timeouts**: Implement proper timeout handling
|
||||
/// 3. **Log Federation Events**: Log important federation operations
|
||||
/// 4. **Validate Responses**: Validate federation responses before processing
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::error::*;
|
||||
///
|
||||
/// async fn send_federation_request(server: &str, data: &[u8]) -> Result<(), EnhancedError> {
|
||||
/// // Simulate federation request
|
||||
/// if server.is_empty() {
|
||||
/// return Err(EnhancedError::federation_error("unknown", "Server name cannot be empty"));
|
||||
/// }
|
||||
///
|
||||
/// // Handle federation logic here
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn federation_handling_best_practices() {
|
||||
// This function demonstrates federation handling best practices
|
||||
let _example_error = EnhancedError::federation_error("matrix.org", "Connection timeout");
|
||||
}
|
||||
|
||||
/// Best Practice: Configuration Management
|
||||
///
|
||||
/// Use enhanced error types for configuration validation.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Validate Early**: Validate configuration at startup
|
||||
/// 2. **Use Enhanced Errors**: Use `EnhancedError::config_error` for config issues
|
||||
/// 3. **Provide Context**: Include field names in error messages
|
||||
/// 4. **Handle Defaults**: Provide sensible defaults where possible
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::error::*;
|
||||
///
|
||||
/// fn validate_config_field(field_name: &str, value: &str) -> Result<(), EnhancedError> {
|
||||
/// if value.is_empty() {
|
||||
/// return Err(EnhancedError::config_error(field_name, "Value cannot be empty"));
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn configuration_management_best_practices() {
|
||||
// This function demonstrates configuration management best practices
|
||||
let _example_error = EnhancedError::config_error("database_url", "Invalid format");
|
||||
}
|
||||
|
||||
/// Best Practice: Database Operations
|
||||
///
|
||||
/// Use enhanced error types for database operations.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Use Enhanced Errors**: Use `EnhancedError::database_error` for DB issues
|
||||
/// 2. **Include Operation Context**: Specify the operation that failed
|
||||
/// 3. **Handle Connections**: Properly handle database connection issues
|
||||
/// 4. **Log Operations**: Log important database operations
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::error::*;
|
||||
///
|
||||
/// async fn save_user_data(user_id: &str, data: &[u8]) -> Result<(), EnhancedError> {
|
||||
/// // Simulate database operation
|
||||
/// if user_id.is_empty() {
|
||||
/// return Err(EnhancedError::database_error("save_user_data", "User ID cannot be empty"));
|
||||
/// }
|
||||
///
|
||||
/// // Handle database logic here
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn database_operations_best_practices() {
|
||||
// This function demonstrates database operations best practices
|
||||
let _example_error = EnhancedError::database_error("save_user_data", "Connection lost");
|
||||
}
|
||||
|
||||
/// Best Practice: Network Operations
|
||||
///
|
||||
/// Use enhanced error types for network operations.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Use Enhanced Errors**: Use `EnhancedError::network_error` for network issues
|
||||
/// 2. **Specify Service**: Include the service that failed
|
||||
/// 3. **Handle Timeouts**: Implement proper timeout handling
|
||||
/// 4. **Retry Logic**: Implement appropriate retry logic
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::error::*;
|
||||
///
|
||||
/// async fn make_http_request(url: &str) -> Result<(), EnhancedError> {
|
||||
/// if url.is_empty() {
|
||||
/// return Err(EnhancedError::network_error("http_client", "URL cannot be empty"));
|
||||
/// }
|
||||
///
|
||||
/// // Handle HTTP request logic here
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn network_operations_best_practices() {
|
||||
// This function demonstrates network operations best practices
|
||||
let _example_error = EnhancedError::network_error("http_client", "Connection timeout");
|
||||
}
|
||||
|
||||
/// Best Practice: Rate Limiting
|
||||
///
|
||||
/// Use enhanced error types for rate limiting.
|
||||
///
|
||||
/// # Best Practices
|
||||
///
|
||||
/// 1. **Use Enhanced Errors**: Use `EnhancedError::rate_limit_exceeded` for rate limits
|
||||
/// 2. **Include Resource**: Specify which resource was rate limited
|
||||
/// 3. **Provide Retry Time**: Include when the user can retry
|
||||
/// 4. **Log Rate Limits**: Log rate limit violations for monitoring
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::error::*;
|
||||
///
|
||||
/// fn check_rate_limit(resource: &str, user_id: &str) -> Result<(), EnhancedError> {
|
||||
/// // Simulate rate limit check
|
||||
/// if resource == "room_creation" {
|
||||
/// return Err(EnhancedError::rate_limit_exceeded(resource, 60));
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn rate_limiting_best_practices() {
|
||||
// This function demonstrates rate limiting best practices
|
||||
let _example_error = EnhancedError::rate_limit_exceeded("room_creation", 60);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_error_handling_best_practices() {
|
||||
error_handling_best_practices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_room_management_best_practices() {
|
||||
room_management_best_practices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_message_handling_best_practices() {
|
||||
message_handling_best_practices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_user_management_best_practices() {
|
||||
user_management_best_practices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_power_level_management_best_practices() {
|
||||
power_level_management_best_practices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_federation_handling_best_practices() {
|
||||
federation_handling_best_practices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configuration_management_best_practices() {
|
||||
configuration_management_best_practices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_database_operations_best_practices() {
|
||||
database_operations_best_practices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_network_operations_best_practices() {
|
||||
network_operations_best_practices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiting_best_practices() {
|
||||
rate_limiting_best_practices();
|
||||
}
|
||||
}
|
363
src/core/docs_examples.rs
Normal file
363
src/core/docs_examples.rs
Normal file
|
@ -0,0 +1,363 @@
|
|||
//! Comprehensive Examples for Continuwuity
|
||||
//!
|
||||
//! This module provides practical examples for common Matrix operations
|
||||
//! using our enhanced types and error handling.
|
||||
|
||||
use crate::types::*;
|
||||
use crate::error::*;
|
||||
|
||||
/// Example: Creating a new room with enhanced types
|
||||
///
|
||||
/// This example shows how to create a new Matrix room using our enhanced
|
||||
/// room creation request structure.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let room_request = EnhancedRoomCreateRequest {
|
||||
/// name: Some("My Awesome Room".to_string()),
|
||||
/// topic: Some("A room for awesome discussions".to_string()),
|
||||
/// preset: Some(RoomPreset::PublicChat),
|
||||
/// room_version: Some("10".to_string()),
|
||||
/// is_direct: Some(false),
|
||||
/// invite: Some(vec!["@alice:example.com".to_string()]),
|
||||
/// initial_state: None,
|
||||
/// };
|
||||
///
|
||||
/// // The room request is now ready to be sent to the Matrix server
|
||||
/// ```
|
||||
pub fn create_room_example() -> EnhancedRoomCreateRequest {
|
||||
EnhancedRoomCreateRequest {
|
||||
name: Some("Example Room".to_string()),
|
||||
topic: Some("This is an example room created with enhanced types".to_string()),
|
||||
preset: Some(RoomPreset::PublicChat),
|
||||
room_version: Some("10".to_string()),
|
||||
is_direct: Some(false),
|
||||
invite: Some(vec!["@alice:example.com".to_string(), "@bob:example.com".to_string()]),
|
||||
initial_state: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Example: Creating a text message with enhanced content
|
||||
///
|
||||
/// This example shows how to create a Matrix message using our enhanced
|
||||
/// message content structure.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let message = EnhancedMessageContent::new_text("Hello, Matrix!".to_string());
|
||||
///
|
||||
/// // The message is ready to be sent to a room
|
||||
/// ```
|
||||
pub fn create_message_example() -> EnhancedMessageContent {
|
||||
EnhancedMessageContent::new_text("Hello from Continuwuity!".to_string())
|
||||
}
|
||||
|
||||
/// Example: Creating a reply message
|
||||
///
|
||||
/// This example shows how to create a reply to another message.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let mut reply = EnhancedMessageContent::new_text("This is a reply".to_string());
|
||||
/// reply.relates_to = Some(RelatesTo {
|
||||
/// in_reply_to: Some(InReplyTo {
|
||||
/// event_id: "$original_event_id".to_string(),
|
||||
/// }),
|
||||
/// rel_type: None,
|
||||
/// event_id: None,
|
||||
/// });
|
||||
///
|
||||
/// // The reply is now properly linked to the original message
|
||||
/// ```
|
||||
pub fn create_reply_example() -> EnhancedMessageContent {
|
||||
let mut reply = EnhancedMessageContent::new_text("This is a reply to your message".to_string());
|
||||
reply.relates_to = Some(RelatesTo {
|
||||
in_reply_to: Some(InReplyTo {
|
||||
event_id: "$example_event_id".to_string(),
|
||||
}),
|
||||
rel_type: None,
|
||||
event_id: None,
|
||||
});
|
||||
reply
|
||||
}
|
||||
|
||||
/// Example: Creating a thread message
|
||||
///
|
||||
/// This example shows how to create a message in a thread.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let mut thread_message = EnhancedMessageContent::new_text("Thread message".to_string());
|
||||
/// thread_message.thread = Some(ThreadInfo {
|
||||
/// event_id: "$thread_root_event_id".to_string(),
|
||||
/// is_falling_back: None,
|
||||
/// is_editing: None,
|
||||
/// });
|
||||
///
|
||||
/// // The message is now part of a thread
|
||||
/// ```
|
||||
pub fn create_thread_message_example() -> EnhancedMessageContent {
|
||||
let mut thread_message = EnhancedMessageContent::new_text("This is a thread message".to_string());
|
||||
thread_message.thread = Some(ThreadInfo {
|
||||
event_id: "$thread_root_event_id".to_string(),
|
||||
is_falling_back: None,
|
||||
is_editing: None,
|
||||
});
|
||||
thread_message
|
||||
}
|
||||
|
||||
/// Example: Setting up room power levels
|
||||
///
|
||||
/// This example shows how to configure power levels for a room.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut power_levels = PowerLevels::default();
|
||||
/// power_levels.users.insert("@admin:example.com".to_string(), 100);
|
||||
/// power_levels.users.insert("@moderator:example.com".to_string(), 50);
|
||||
/// power_levels.events_default = 0; // Anyone can send messages
|
||||
/// power_levels.state_default = 50; // Only moderators can change state
|
||||
///
|
||||
/// // Power levels are now configured
|
||||
/// ```
|
||||
pub fn setup_power_levels_example() -> PowerLevels {
|
||||
let mut power_levels = PowerLevels::default();
|
||||
power_levels.users.insert("@admin:example.com".to_string(), 100);
|
||||
power_levels.users.insert("@moderator:example.com".to_string(), 50);
|
||||
power_levels.users.insert("@user:example.com".to_string(), 0);
|
||||
power_levels.events_default = 0; // Anyone can send messages
|
||||
power_levels.state_default = 50; // Only moderators can change state
|
||||
power_levels.ban = 50; // Moderators can ban users
|
||||
power_levels.kick = 50; // Moderators can kick users
|
||||
power_levels
|
||||
}
|
||||
|
||||
/// Example: Creating a user profile
|
||||
///
|
||||
/// This example shows how to create a user profile with enhanced information.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let user_profile = EnhancedUserProfile {
|
||||
/// user_id: "@alice:example.com".to_string(),
|
||||
/// display_name: Some("Alice".to_string()),
|
||||
/// avatar_url: Some("mxc://example.com/avatar123".to_string()),
|
||||
/// is_online: true,
|
||||
/// last_seen: Some(1640995200), // Unix timestamp
|
||||
/// presence: PresenceState::Online,
|
||||
/// status_msg: Some("Working on Matrix stuff".to_string()),
|
||||
/// };
|
||||
///
|
||||
/// // User profile is now complete
|
||||
/// ```
|
||||
pub fn create_user_profile_example() -> EnhancedUserProfile {
|
||||
EnhancedUserProfile {
|
||||
user_id: "@alice:example.com".to_string(),
|
||||
display_name: Some("Alice".to_string()),
|
||||
avatar_url: Some("mxc://example.com/avatar123".to_string()),
|
||||
is_online: true,
|
||||
last_seen: Some(1640995200), // Unix timestamp
|
||||
presence: PresenceState::Online,
|
||||
status_msg: Some("Working on Matrix stuff".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Example: Error handling with enhanced errors
|
||||
///
|
||||
/// This example shows how to use our enhanced error handling for better
|
||||
/// user experience and debugging.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::error::*;
|
||||
///
|
||||
/// // Create a user-friendly error
|
||||
/// let error = EnhancedError::room_not_found("!nonexistent:example.com");
|
||||
///
|
||||
/// // Get user-friendly message
|
||||
/// let user_message = error.user_message();
|
||||
/// println!("User sees: {}", user_message);
|
||||
///
|
||||
/// // Get sanitized message for logging
|
||||
/// let log_message = error.sanitized_message();
|
||||
/// println!("Log shows: {}", log_message);
|
||||
///
|
||||
/// // Get Matrix error code
|
||||
/// let matrix_code = error.matrix_error_code();
|
||||
/// println!("Matrix error code: {}", matrix_code);
|
||||
/// ```
|
||||
pub fn error_handling_example() -> EnhancedError {
|
||||
let error = EnhancedError::room_not_found("!example:example.com");
|
||||
|
||||
// Demonstrate different error message types
|
||||
let _user_message = error.user_message();
|
||||
let _log_message = error.sanitized_message();
|
||||
let _matrix_code = error.matrix_error_code();
|
||||
|
||||
error
|
||||
}
|
||||
|
||||
/// Example: Room member management
|
||||
///
|
||||
/// This example shows how to manage room members using enhanced types.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let member = EnhancedRoomMember {
|
||||
/// user_id: "@alice:example.com".to_string(),
|
||||
/// display_name: Some("Alice".to_string()),
|
||||
/// avatar_url: Some("mxc://example.com/avatar123".to_string()),
|
||||
/// membership: MembershipState::Join,
|
||||
/// power_level: 50,
|
||||
/// is_direct: false,
|
||||
/// third_party_invite: None,
|
||||
/// };
|
||||
///
|
||||
/// // Member information is now available
|
||||
/// ```
|
||||
pub fn room_member_example() -> EnhancedRoomMember {
|
||||
EnhancedRoomMember {
|
||||
user_id: "@alice:example.com".to_string(),
|
||||
display_name: Some("Alice".to_string()),
|
||||
avatar_url: Some("mxc://example.com/avatar123".to_string()),
|
||||
membership: MembershipState::Join,
|
||||
power_level: 50,
|
||||
is_direct: false,
|
||||
third_party_invite: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Example: Room summary for listings
|
||||
///
|
||||
/// This example shows how to create a room summary for display in room lists.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use conduwuit_core::types::*;
|
||||
///
|
||||
/// let room_summary = EnhancedRoomSummary {
|
||||
/// room_id: "!room123:example.com".to_string(),
|
||||
/// name: Some("General Discussion".to_string()),
|
||||
/// topic: Some("A place for general chat".to_string()),
|
||||
/// avatar_url: Some("mxc://example.com/room_avatar".to_string()),
|
||||
/// member_count: 42,
|
||||
/// is_public: true,
|
||||
/// last_activity: 1640995200,
|
||||
/// unread_count: 5,
|
||||
/// highlight_count: 2,
|
||||
/// notification_count: 7,
|
||||
/// };
|
||||
///
|
||||
/// // Room summary is ready for display
|
||||
/// ```
|
||||
pub fn room_summary_example() -> EnhancedRoomSummary {
|
||||
EnhancedRoomSummary {
|
||||
room_id: "!room123:example.com".to_string(),
|
||||
name: Some("General Discussion".to_string()),
|
||||
topic: Some("A place for general chat".to_string()),
|
||||
avatar_url: Some("mxc://example.com/room_avatar".to_string()),
|
||||
member_count: 42,
|
||||
is_public: true,
|
||||
last_activity: 1640995200,
|
||||
unread_count: 5,
|
||||
highlight_count: 2,
|
||||
notification_count: 7,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_create_room_example() {
|
||||
let room_request = create_room_example();
|
||||
assert_eq!(room_request.name, Some("Example Room".to_string()));
|
||||
assert_eq!(room_request.preset, Some(RoomPreset::PublicChat));
|
||||
assert!(room_request.invite.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_message_example() {
|
||||
let message = create_message_example();
|
||||
assert_eq!(message.msgtype, MessageType::Text);
|
||||
assert_eq!(message.body, "Hello from Continuwuity!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_reply_example() {
|
||||
let reply = create_reply_example();
|
||||
assert!(reply.is_reply());
|
||||
assert!(reply.relates_to.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_thread_message_example() {
|
||||
let thread_message = create_thread_message_example();
|
||||
assert!(thread_message.is_thread());
|
||||
assert!(thread_message.thread.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_setup_power_levels_example() {
|
||||
let power_levels = setup_power_levels_example();
|
||||
assert_eq!(power_levels.users.len(), 3);
|
||||
assert_eq!(power_levels.events_default, 0);
|
||||
assert_eq!(power_levels.state_default, 50);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_user_profile_example() {
|
||||
let profile = create_user_profile_example();
|
||||
assert_eq!(profile.user_id, "@alice:example.com");
|
||||
assert_eq!(profile.presence, PresenceState::Online);
|
||||
assert!(profile.is_online);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_handling_example() {
|
||||
let error = error_handling_example();
|
||||
assert_eq!(error.matrix_error_code(), "M_NOT_FOUND");
|
||||
assert_eq!(error.http_status_code(), 404);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_room_member_example() {
|
||||
let member = room_member_example();
|
||||
assert_eq!(member.user_id, "@alice:example.com");
|
||||
assert_eq!(member.membership, MembershipState::Join);
|
||||
assert_eq!(member.power_level, 50);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_room_summary_example() {
|
||||
let summary = room_summary_example();
|
||||
assert_eq!(summary.room_id, "!room123:example.com");
|
||||
assert_eq!(summary.member_count, 42);
|
||||
assert!(summary.is_public);
|
||||
}
|
||||
}
|
449
src/core/types_enhanced.rs
Normal file
449
src/core/types_enhanced.rs
Normal file
|
@ -0,0 +1,449 @@
|
|||
// Enhanced Type Definitions for Continuwuity
|
||||
// Contributed from our chat-system improvements
|
||||
// Provides cleaner, more focused type definitions for Matrix operations
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Enhanced room information with better organization
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnhancedRoomInfo {
|
||||
pub room_id: String,
|
||||
pub name: Option<String>,
|
||||
pub topic: Option<String>,
|
||||
pub avatar_url: Option<String>,
|
||||
pub member_count: u32,
|
||||
pub is_public: bool,
|
||||
pub join_rule: JoinRule,
|
||||
pub power_levels: PowerLevels,
|
||||
pub creation_time: u64,
|
||||
pub last_activity: u64,
|
||||
}
|
||||
|
||||
/// Enhanced user information
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnhancedUserInfo {
|
||||
pub user_id: String,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar_url: Option<String>,
|
||||
pub is_online: bool,
|
||||
pub last_seen: Option<u64>,
|
||||
pub power_level: i32,
|
||||
pub membership_state: MembershipState,
|
||||
}
|
||||
|
||||
/// Join rules for rooms
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum JoinRule {
|
||||
#[serde(rename = "public")]
|
||||
Public,
|
||||
#[serde(rename = "invite")]
|
||||
Invite,
|
||||
#[serde(rename = "private")]
|
||||
Private,
|
||||
#[serde(rename = "knock")]
|
||||
Knock,
|
||||
#[serde(rename = "knock_restricted")]
|
||||
KnockRestricted,
|
||||
}
|
||||
|
||||
/// Membership states
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum MembershipState {
|
||||
#[serde(rename = "invite")]
|
||||
Invite,
|
||||
#[serde(rename = "join")]
|
||||
Join,
|
||||
#[serde(rename = "knock")]
|
||||
Knock,
|
||||
#[serde(rename = "leave")]
|
||||
Leave,
|
||||
#[serde(rename = "ban")]
|
||||
Ban,
|
||||
}
|
||||
|
||||
/// Power levels for room permissions
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PowerLevels {
|
||||
pub users: HashMap<String, i32>,
|
||||
pub events: HashMap<String, i32>,
|
||||
pub events_default: i32,
|
||||
pub state_default: i32,
|
||||
pub ban: i32,
|
||||
pub kick: i32,
|
||||
pub redact: i32,
|
||||
pub invite: i32,
|
||||
}
|
||||
|
||||
impl Default for PowerLevels {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
users: HashMap::new(),
|
||||
events: HashMap::new(),
|
||||
events_default: 0,
|
||||
state_default: 50,
|
||||
ban: 50,
|
||||
kick: 50,
|
||||
redact: 50,
|
||||
invite: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enhanced message content with better structure
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnhancedMessageContent {
|
||||
pub msgtype: MessageType,
|
||||
pub body: String,
|
||||
pub formatted_body: Option<String>,
|
||||
pub format: Option<String>,
|
||||
pub relates_to: Option<RelatesTo>,
|
||||
pub mentions: Option<Mentions>,
|
||||
pub thread: Option<ThreadInfo>,
|
||||
}
|
||||
|
||||
/// Message types
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum MessageType {
|
||||
#[serde(rename = "m.text")]
|
||||
Text,
|
||||
#[serde(rename = "m.notice")]
|
||||
Notice,
|
||||
#[serde(rename = "m.emote")]
|
||||
Emote,
|
||||
#[serde(rename = "m.image")]
|
||||
Image,
|
||||
#[serde(rename = "m.file")]
|
||||
File,
|
||||
#[serde(rename = "m.video")]
|
||||
Video,
|
||||
#[serde(rename = "m.audio")]
|
||||
Audio,
|
||||
#[serde(rename = "m.location")]
|
||||
Location,
|
||||
}
|
||||
|
||||
/// Relates to information for replies/threads
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RelatesTo {
|
||||
#[serde(rename = "m.in_reply_to")]
|
||||
pub in_reply_to: Option<InReplyTo>,
|
||||
#[serde(rename = "rel_type")]
|
||||
pub rel_type: Option<String>,
|
||||
#[serde(rename = "event_id")]
|
||||
pub event_id: Option<String>,
|
||||
}
|
||||
|
||||
/// In-reply-to information
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InReplyTo {
|
||||
pub event_id: String,
|
||||
}
|
||||
|
||||
/// Mentions in messages
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Mentions {
|
||||
pub user_ids: Vec<String>,
|
||||
pub room: bool,
|
||||
}
|
||||
|
||||
/// Thread information
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ThreadInfo {
|
||||
pub event_id: String,
|
||||
pub is_falling_back: Option<bool>,
|
||||
pub is_editing: Option<bool>,
|
||||
}
|
||||
|
||||
/// Enhanced room creation request
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnhancedRoomCreateRequest {
|
||||
pub name: Option<String>,
|
||||
pub topic: Option<String>,
|
||||
pub preset: Option<RoomPreset>,
|
||||
pub room_version: Option<String>,
|
||||
pub is_direct: Option<bool>,
|
||||
pub invite: Option<Vec<String>>,
|
||||
pub initial_state: Option<Vec<InitialStateEvent>>,
|
||||
}
|
||||
|
||||
/// Room presets
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum RoomPreset {
|
||||
#[serde(rename = "private_chat")]
|
||||
PrivateChat,
|
||||
#[serde(rename = "trusted_private_chat")]
|
||||
TrustedPrivateChat,
|
||||
#[serde(rename = "public_chat")]
|
||||
PublicChat,
|
||||
}
|
||||
|
||||
/// Initial state events for room creation
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InitialStateEvent {
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: String,
|
||||
pub state_key: String,
|
||||
pub content: serde_json::Value,
|
||||
}
|
||||
|
||||
/// Enhanced room member information
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnhancedRoomMember {
|
||||
pub user_id: String,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar_url: Option<String>,
|
||||
pub membership: MembershipState,
|
||||
pub power_level: i32,
|
||||
pub is_direct: bool,
|
||||
pub third_party_invite: Option<ThirdPartyInvite>,
|
||||
}
|
||||
|
||||
/// Third party invite information
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ThirdPartyInvite {
|
||||
pub display_name: String,
|
||||
pub signed: SignedInvite,
|
||||
}
|
||||
|
||||
/// Signed invite information
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SignedInvite {
|
||||
pub mxid: String,
|
||||
pub token: String,
|
||||
pub signatures: HashMap<String, HashMap<String, String>>,
|
||||
}
|
||||
|
||||
/// Enhanced room summary for listings
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnhancedRoomSummary {
|
||||
pub room_id: String,
|
||||
pub name: Option<String>,
|
||||
pub topic: Option<String>,
|
||||
pub avatar_url: Option<String>,
|
||||
pub member_count: u32,
|
||||
pub is_public: bool,
|
||||
pub last_activity: u64,
|
||||
pub unread_count: u32,
|
||||
pub highlight_count: u32,
|
||||
pub notification_count: u32,
|
||||
}
|
||||
|
||||
/// Enhanced user profile
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnhancedUserProfile {
|
||||
pub user_id: String,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar_url: Option<String>,
|
||||
pub is_online: bool,
|
||||
pub last_seen: Option<u64>,
|
||||
pub presence: PresenceState,
|
||||
pub status_msg: Option<String>,
|
||||
}
|
||||
|
||||
/// Presence states
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum PresenceState {
|
||||
#[serde(rename = "online")]
|
||||
Online,
|
||||
#[serde(rename = "offline")]
|
||||
Offline,
|
||||
#[serde(rename = "unavailable")]
|
||||
Unavailable,
|
||||
}
|
||||
|
||||
/// Helper functions for enhanced types
|
||||
impl EnhancedRoomInfo {
|
||||
pub fn new(room_id: String) -> Self {
|
||||
Self {
|
||||
room_id,
|
||||
name: None,
|
||||
topic: None,
|
||||
avatar_url: None,
|
||||
member_count: 0,
|
||||
is_public: false,
|
||||
join_rule: JoinRule::Invite,
|
||||
power_levels: PowerLevels::default(),
|
||||
creation_time: 0,
|
||||
last_activity: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_admin(&self, user_id: &str) -> bool {
|
||||
self.power_levels.users.get(user_id)
|
||||
.map(|level| *level >= 100)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn can_send_message(&self, user_id: &str) -> bool {
|
||||
let user_level = self.power_levels.users.get(user_id).unwrap_or(&0);
|
||||
*user_level >= self.power_levels.events_default
|
||||
}
|
||||
}
|
||||
|
||||
impl EnhancedUserInfo {
|
||||
pub fn new(user_id: String) -> Self {
|
||||
Self {
|
||||
user_id,
|
||||
display_name: None,
|
||||
avatar_url: None,
|
||||
is_online: false,
|
||||
last_seen: None,
|
||||
power_level: 0,
|
||||
membership_state: MembershipState::Leave,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_member(&self) -> bool {
|
||||
self.membership_state == MembershipState::Join
|
||||
}
|
||||
|
||||
pub fn is_moderator(&self) -> bool {
|
||||
self.power_level >= 50
|
||||
}
|
||||
}
|
||||
|
||||
impl EnhancedMessageContent {
|
||||
pub fn new_text(body: String) -> Self {
|
||||
Self {
|
||||
msgtype: MessageType::Text,
|
||||
body,
|
||||
formatted_body: None,
|
||||
format: None,
|
||||
relates_to: None,
|
||||
mentions: None,
|
||||
thread: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_notice(body: String) -> Self {
|
||||
Self {
|
||||
msgtype: MessageType::Notice,
|
||||
body,
|
||||
formatted_body: None,
|
||||
format: None,
|
||||
relates_to: None,
|
||||
mentions: None,
|
||||
thread: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_reply(&self) -> bool {
|
||||
self.relates_to.as_ref()
|
||||
.and_then(|r| r.in_reply_to.as_ref())
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn is_thread(&self) -> bool {
|
||||
self.thread.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_enhanced_room_info_creation() {
|
||||
let room = EnhancedRoomInfo::new("!test:example.com".to_string());
|
||||
assert_eq!(room.room_id, "!test:example.com");
|
||||
assert_eq!(room.member_count, 0);
|
||||
assert_eq!(room.join_rule, JoinRule::Invite);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enhanced_user_info_creation() {
|
||||
let user = EnhancedUserInfo::new("@user:example.com".to_string());
|
||||
assert_eq!(user.user_id, "@user:example.com");
|
||||
assert!(!user.is_online);
|
||||
assert_eq!(user.membership_state, MembershipState::Leave);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enhanced_message_content_creation() {
|
||||
let message = EnhancedMessageContent::new_text("Hello world".to_string());
|
||||
assert_eq!(message.msgtype, MessageType::Text);
|
||||
assert_eq!(message.body, "Hello world");
|
||||
assert!(!message.is_reply());
|
||||
assert!(!message.is_thread());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_room_admin_check() {
|
||||
let mut room = EnhancedRoomInfo::new("!test:example.com".to_string());
|
||||
room.power_levels.users.insert("@admin:example.com".to_string(), 100);
|
||||
room.power_levels.users.insert("@user:example.com".to_string(), 0);
|
||||
|
||||
assert!(room.is_admin("@admin:example.com"));
|
||||
assert!(!room.is_admin("@user:example.com"));
|
||||
assert!(!room.is_admin("@nonexistent:example.com"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_room_message_permission() {
|
||||
let mut room = EnhancedRoomInfo::new("!test:example.com".to_string());
|
||||
room.power_levels.events_default = 0;
|
||||
room.power_levels.users.insert("@user:example.com".to_string(), 0);
|
||||
room.power_levels.users.insert("@muted:example.com".to_string(), -1);
|
||||
|
||||
assert!(room.can_send_message("@user:example.com"));
|
||||
assert!(!room.can_send_message("@muted:example.com"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_user_membership_check() {
|
||||
let mut user = EnhancedUserInfo::new("@user:example.com".to_string());
|
||||
user.membership_state = MembershipState::Join;
|
||||
assert!(user.is_member());
|
||||
|
||||
user.membership_state = MembershipState::Leave;
|
||||
assert!(!user.is_member());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_user_moderator_check() {
|
||||
let mut user = EnhancedUserInfo::new("@user:example.com".to_string());
|
||||
user.power_level = 50;
|
||||
assert!(user.is_moderator());
|
||||
|
||||
user.power_level = 49;
|
||||
assert!(!user.is_moderator());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_message_reply_check() {
|
||||
let mut message = EnhancedMessageContent::new_text("Reply".to_string());
|
||||
message.relates_to = Some(RelatesTo {
|
||||
in_reply_to: Some(InReplyTo {
|
||||
event_id: "$event123".to_string(),
|
||||
}),
|
||||
rel_type: None,
|
||||
event_id: None,
|
||||
});
|
||||
|
||||
assert!(message.is_reply());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_message_thread_check() {
|
||||
let mut message = EnhancedMessageContent::new_text("Thread message".to_string());
|
||||
message.thread = Some(ThreadInfo {
|
||||
event_id: "$thread123".to_string(),
|
||||
is_falling_back: None,
|
||||
is_editing: None,
|
||||
});
|
||||
|
||||
assert!(message.is_thread());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_power_levels_default() {
|
||||
let power_levels = PowerLevels::default();
|
||||
assert_eq!(power_levels.events_default, 0);
|
||||
assert_eq!(power_levels.state_default, 50);
|
||||
assert_eq!(power_levels.ban, 50);
|
||||
assert_eq!(power_levels.kick, 50);
|
||||
assert_eq!(power_levels.redact, 50);
|
||||
assert_eq!(power_levels.invite, 0);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue