From baa720b769a961d51e28160ccb35ddf36c47d471 Mon Sep 17 00:00:00 2001 From: jhoninck Date: Tue, 2 Sep 2025 15:06:31 +0000 Subject: [PATCH] Upload files to "src/core" --- src/core/docs_api_guide.rs | 408 +++++++++++++++++++++++++++++ src/core/docs_best_practices.rs | 379 +++++++++++++++++++++++++++ src/core/docs_examples.rs | 363 ++++++++++++++++++++++++++ src/core/types_enhanced.rs | 449 ++++++++++++++++++++++++++++++++ 4 files changed, 1599 insertions(+) create mode 100644 src/core/docs_api_guide.rs create mode 100644 src/core/docs_best_practices.rs create mode 100644 src/core/docs_examples.rs create mode 100644 src/core/types_enhanced.rs diff --git a/src/core/docs_api_guide.rs b/src/core/docs_api_guide.rs new file mode 100644 index 00000000..b6b9e166 --- /dev/null +++ b/src/core/docs_api_guide.rs @@ -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(); + } +} diff --git a/src/core/docs_best_practices.rs b/src/core/docs_best_practices.rs new file mode 100644 index 00000000..0e6a90ae --- /dev/null +++ b/src/core/docs_best_practices.rs @@ -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(); + } +} diff --git a/src/core/docs_examples.rs b/src/core/docs_examples.rs new file mode 100644 index 00000000..f10b1f79 --- /dev/null +++ b/src/core/docs_examples.rs @@ -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); + } +} diff --git a/src/core/types_enhanced.rs b/src/core/types_enhanced.rs new file mode 100644 index 00000000..61086eec --- /dev/null +++ b/src/core/types_enhanced.rs @@ -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, + pub topic: Option, + pub avatar_url: Option, + 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, + pub avatar_url: Option, + pub is_online: bool, + pub last_seen: Option, + 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, + pub events: HashMap, + 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, + pub format: Option, + pub relates_to: Option, + pub mentions: Option, + pub thread: Option, +} + +/// 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, + #[serde(rename = "rel_type")] + pub rel_type: Option, + #[serde(rename = "event_id")] + pub event_id: Option, +} + +/// 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, + pub room: bool, +} + +/// Thread information +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ThreadInfo { + pub event_id: String, + pub is_falling_back: Option, + pub is_editing: Option, +} + +/// Enhanced room creation request +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EnhancedRoomCreateRequest { + pub name: Option, + pub topic: Option, + pub preset: Option, + pub room_version: Option, + pub is_direct: Option, + pub invite: Option>, + pub initial_state: Option>, +} + +/// 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, + pub avatar_url: Option, + pub membership: MembershipState, + pub power_level: i32, + pub is_direct: bool, + pub third_party_invite: Option, +} + +/// 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>, +} + +/// Enhanced room summary for listings +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EnhancedRoomSummary { + pub room_id: String, + pub name: Option, + pub topic: Option, + pub avatar_url: Option, + 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, + pub avatar_url: Option, + pub is_online: bool, + pub last_seen: Option, + pub presence: PresenceState, + pub status_msg: Option, +} + +/// 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); + } +}