Rust Matrix客户端API库ruma-client-api的使用,实现高效安全的Matrix协议通信与消息处理

ruma-client-api

ruma-client-api 包含用于 Matrix 客户端 API 规范中每个端点请求和响应的可序列化类型。这些类型可以被客户端和服务器代码共享。

安装

在项目目录中运行以下 Cargo 命令:

cargo add ruma-client-api

或者在 Cargo.toml 中添加以下行:

ruma-client-api = "0.20.4"

完整示例

以下是一个使用 ruma-client-api 实现 Matrix 协议通信与消息处理的完整示例:

use ruma_client_api::{
    error::Error as RumaError,
    r0::{
        account::register::{Request as RegisterRequest, Response as RegisterResponse},
        session::login::{Request as LoginRequest, Response as LoginResponse},
        sync::sync_events::{Request as SyncRequest, Response as SyncResponse},
    },
};
use ruma_common::presence::PresenceState;
use ruma_identifiers::{DeviceId, RoomId, UserId};
use ruma_client::{Client, HttpClient};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 创建 HTTP 客户端
    let client = Client::new().await?;

    // 1. 注册新用户
    let register_request = RegisterRequest::new().username("example_user").password("secure_password");
    let register_response: RegisterResponse = client.send_request(register_request).await?;
    println!("Registered user: {:?}", register_response.user_id);

    // 2. 登录
    let login_request = LoginRequest::Password {
        identifier: ruma_client_api::r0::session::login::UserIdentifier::MatrixId(register_response.user_id.clone()),
        password: "secure_password".to_string(),
        device_id: Some(DeviceId::new()),
        initial_device_display_name: Some("My Device".to_string()),
    };
    let login_response: LoginResponse = client.send_request(login_request).await?;
    println!("Logged in with access token: {}", login_response.access_token);

    // 3. 同步消息
    let sync_request = SyncRequest::new(login_response.next_batch.unwrap_or_default())
        .set_presence(PresenceState::Online);
    let sync_response: SyncResponse = client.send_request(sync_request).await?;
    println!("Received sync response with {} rooms", sync_response.rooms.join.len());

    // 4. 处理消息
    for (room_id, room_info) in sync_response.rooms.join {
        println!("Messages in room {}:", room_id);
        for event in room_info.timeline.events {
            println!("- {:?}", event);
        }
    }

    Ok(())
}

示例说明

  1. 用户注册:使用 RegisterRequest 创建新用户账户
  2. 用户登录:使用 LoginRequest 进行密码认证,获取访问令牌
  3. 消息同步:使用 SyncRequest 获取最新消息和房间状态
  4. 消息处理:遍历同步响应中的房间和消息事件

这个示例展示了如何使用 ruma-client-api 实现基本的 Matrix 客户端功能,包括用户认证、消息同步和处理。

扩展示例

以下是一个更完整的 Matrix 客户端实现示例,包含房间创建和消息发送功能:

use ruma_client_api::{
    r0::{
        account::register::{Request as RegisterRequest, Response as RegisterResponse},
        session::login::{Request as LoginRequest, Response as LoginResponse},
        sync::sync_events::{Request as SyncRequest, Response as SyncResponse},
        room::create_room::{Request as CreateRoomRequest, Response as CreateRoomResponse},
        message::send_message_event::{Request as SendMessageRequest, Response as SendMessageResponse},
    },
};
use ruma_common::presence::PresenceState;
use ruma_identifiers::{DeviceId, RoomId};
use ruma_events::{
    room::message::{MessageEventContent, TextMessageEventContent},
    EventType,
};
use ruma_client::{Client, HttpClient};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 初始化客户端
    let client = Client::new().await?;
    
    // 1. 用户注册
    let register_response: RegisterResponse = client
        .send_request(
            RegisterRequest::new()
                .username("rust_user")
                .password("matrix_rs")
        )
        .await?;
    
    // 2. 用户登录
    let login_response: LoginResponse = client
        .send_request(LoginRequest::Password {
            identifier: ruma_client_api::r0::session::login::UserIdentifier::MatrixId(
                register_response.user_id.clone(),
            ),
            password: "matrix_rs".to_string(),
            device_id: Some(DeviceId::new()),
            initial_device_display_name: Some("Rust Client".to_string()),
        })
        .await?;

    // 3. 创建房间
    let create_room_response: CreateRoomResponse = client
        .send_request(
            CreateRoomRequest::new()
                .name("Ruma Test Room")
                .visibility(ruma_client_api::r0::room::Visibility::Public)
        )
        .await?;
    println!("Created room: {}", create_room_response.room_id);

    // 4. 发送消息
    let message_content = MessageEventContent::Text(
        TextMessageEventContent::plain("Hello from Ruma client!")
    );
    
    let send_message_response: SendMessageResponse = client
        .send_request(
            SendMessageRequest::new(
                create_room_response.room_id.clone(),
                EventType::RoomMessage,
                &message_content
            )
        )
        .await?;
    println!("Sent message with event ID: {}", send_message_response.event_id);

    // 5. 同步消息
    let sync_response: SyncResponse = client
        .send_request(
            SyncRequest::new(login_response.next_batch.unwrap_or_default())
                .set_presence(PresenceState::Online)
        )
        .await?;

    // 6. 处理同步事件
    for (room_id, room_info) in sync_response.rooms.join {
        println!("Room {} has {} messages", room_id, room_info.timeline.events.len());
    }

    Ok(())
}

示例说明

  1. 用户注册:创建新用户账户
  2. 用户登录:使用密码认证登录
  3. 房间创建:创建一个新的公开聊天室
  4. 消息发送:向新创建的聊天室发送文本消息
  5. 消息同步:获取最新的消息和房间状态
  6. 事件处理:处理同步响应中的房间和消息事件

这个扩展示例展示了更完整的 Matrix 客户端功能,包括房间创建和消息发送等高级操作。

许可证

MIT 许可证


1 回复

Rust Matrix客户端API库ruma-client-api的使用

介绍

ruma-client-api是一个用于与Matrix协议服务器交互的Rust客户端API库。它提供了类型安全的接口来构建Matrix客户端应用,支持高效、安全的Matrix协议通信。

Matrix是一个开放标准的去中心化实时通信协议,提供端到端加密的消息传递、VoIP/VoIP通话等功能。ruma-client-api是ruma项目的一部分,专注于客户端API的实现。

主要特性

  • 完全类型安全的Matrix API请求和响应
  • 支持同步、消息发送、房间管理等核心功能
  • 异步/等待支持
  • 良好的错误处理
  • 可扩展的认证机制

完整示例代码

下面是一个完整的Matrix客户端示例,包含初始化、同步消息、发送消息和处理消息的功能:

use ruma_client_api::{
    self,
    r0::{
        message::create_message_event,
        sync::sync_events,
    },
    ruma_api,
};
use ruma_common::{
    api::MatrixVersion,
    authentication::AccessToken,
};
use ruma_events::{
    room::message::MessageEventContent,
    AnyMessageEventContent,
    AnySyncRoomEvent,
};
use ruma_identifiers::{RoomId, UserId};
use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // 1. 初始化客户端
    let homeserver_url = "https://matrix.org".parse()?;
    let user_id = UserId::parse("@youruser:matrix.org")?;
    let access_token = AccessToken::new("your_access_token".to_owned());
    
    let client = ruma_client_api::Client::builder()
        .homeserver_url(homeserver_url)
        .access_token(access_token)
        .build()?;
    
    // 2. 持续同步和处理消息
    let mut since = None;
    loop {
        // 同步消息请求
        let request = sync_events::Request::new()
            .since(since)
            .timeout(Duration::from_secs(30));
        
        match client.send_request(request).await {
            Ok(response) => {
                since = Some(response.next_batch.clone());
                
                // 处理加入的房间
                for (room_id, joined_room) in response.rooms.join {
                    println!("房间 {} 有新事件", room_id);
                    
                    // 处理时间线事件
                    for event in joined_room.timeline.events {
                        if let Ok(AnySyncRoomEvent::Message(msg_event)) = event.deserialize() {
                            println!("收到新消息: {:?}", msg_event.content);
                            
                            // 自动回复
                            if let Some(sender) = msg_event.sender {
                                if sender != user_id {
                                    reply_to_message(&client, &room_id, &msg_event.content).await?;
                                }
                            }
                        }
                    }
                }
            }
            Err(e) => eprintln!("同步错误: {}", e),
        }
        
        sleep(Duration::from_secs(5)).await;
    }
}

/// 回复消息
async fn reply_to_message(
    client: &ruma_client_api::Client,
    room_id: &RoomId,
    original_content: &MessageEventContent,
) -> anyhow::Result<()> {
    let reply_content = match original_content {
        MessageEventContent::Text(text) => {
            MessageEventContent::text_plain(format!("回复: {}", text.body))
        }
        _ => MessageEventContent::text_plain("已收到您的消息".to_owned()),
    };
    
    let event_content = AnyMessageEventContent::RoomMessage(reply_content);
    
    client
        .send_request(create_message_event::Request::new(
            room_id.clone(),
            format!("txn_{}", chrono::Utc::now().timestamp()),
            &event_content,
        ))
        .await?;
    
    Ok(())
}

代码说明

  1. 客户端初始化

    • 配置Matrix服务器URL、用户ID和访问令牌
    • 使用ClientBuilder创建客户端实例
  2. 消息同步循环

    • 使用sync_events API定期同步新消息
    • 维护since token以实现增量同步
    • 设置30秒超时防止长轮询阻塞
  3. 消息处理

    • 解析收到的消息事件
    • 过滤出文本消息内容
    • 自动回复收到的消息
  4. 消息发送

    • 构建回复消息内容
    • 使用create_message_event API发送消息
    • 为每个消息生成唯一的事务ID

使用方法

  1. 将上述代码保存为main.rs
  2. 在Cargo.toml中添加依赖:
[dependencies]
ruma-client-api = "0.10"
tokio = { version = "1.0", features = ["full"] }
anyhow = "1.0"
chrono = "0.4"
  1. 运行程序:cargo run

注意事项

  1. 需要替换示例中的homeserver_url、user_id和access_token为实际值
  2. 程序会持续运行并自动回复收到的消息
  3. 按Ctrl+C可停止程序
  4. 生产环境应考虑添加更完善的错误处理和日志记录
回到顶部