Skip to content

使用 telegram-Client ​

telegram-client 是基于 telegram4j-core 开发的库,旨在简化 Telegram 消息的处理。本文将介绍如何使用 telegram-client 来处理消息和命令,包括依赖配置、事件适配器、命令处理以及客户端配置等内容。

添加依赖 ​

首先,在项目的 pom.xml 文件中添加 telegram-client 的依赖:

xml
<dependency>
  <groupId>nexus.io</groupId>
  <artifactId>telegram-client</artifactId>
  <version>1.0.0</version>
</dependency>

创建消息分发器 ​

消息分发器负责处理收到的消息事件,根据消息内容执行相应的操作并发送回复。

java
package nexus.io.telegram.bots.dispatcher;

import org.reactivestreams.Publisher;

import nexus.io.telegram.dispatcher.TelegramMessageDispatcher;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
import telegram4j.core.event.domain.message.SendMessageEvent;
import telegram4j.core.object.Message;
import telegram4j.core.object.chat.Chat;
import telegram4j.core.spec.SendMessageSpec;
import telegram4j.core.util.Id;

@Slf4j
public class MyTelegramMessageDispatcher implements TelegramMessageDispatcher {

  /**
   * 处理 SendMessageEvent,执行翻译并发送回复
   *
   * @param event 发送消息事件
   * @return 翻译后的消息 Publisher
   */
  public Publisher<? extends Message> dispatch(SendMessageEvent event) {
    // 获取 Chat 对象,如果不存在则从消息中获取
    Mono<Chat> chatMono = Mono.justOrEmpty(event.getChat()).switchIfEmpty(event.getMessage().getChat());
    // 处理 Chat 和消息发送
    return chatMono.flatMap(chat -> processAndSendMessage(chat, event.getMessage()));
  }

  /**
   * 处理消息内容,执行翻译并发送回复
   *
   * @param chat    聊天对象
   * @param message 原始消息对象
   * @return 处理后的消息 Publisher
   */
  private Mono<Message> processAndSendMessage(Chat chat, Message message) {
    String text = message.getContent();
    log.info("接收到消息: {}", text);

    if (text.equals("/get_chat_id")) {
      Id id = chat.getId();
      return chat.sendMessage("Chat ID: " + id.asLong());
    }

    // 构建发送消息规范,这里可以集成翻译功能
    SendMessageSpec messageSpec = SendMessageSpec.of("Hi");

    // 发送回复消息
    return chat.sendMessage(messageSpec);
  }
}

实现事件适配器 ​

事件适配器用于监听和处理 Telegram 事件,例如消息发送和回调查询等。在此示例中,我们实现了 MyBotEventAdapter 来处理消息事件,并过滤掉机器人自身发送的消息。

java
package nexus.io.telegram.bots.adapter;

import java.util.Optional;

import org.reactivestreams.Publisher;

import nexus.io.telegram.bots.dispatcher.MyTelegramMessageDispatcher;
import nexus.io.telegram.dispatcher.TelegramBotEventDispatcher;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
import telegram4j.core.event.EventAdapter;
import telegram4j.core.event.domain.inline.CallbackQueryEvent;
import telegram4j.core.event.domain.message.SendMessageEvent;
import telegram4j.core.object.MentionablePeer;
import telegram4j.core.object.chat.Chat;

@Slf4j
public class MyBotEventAdapter extends EventAdapter {

  private final long botId;

  public MyBotEventAdapter(long selfId) {
    this.botId = selfId;
  }

  @Override
  public Publisher<?> onSendMessage(SendMessageEvent event) {
    Optional<MentionablePeer> optionalAuthor = event.getAuthor();
    Optional<Chat> optionalChat = event.getChat();

    // 防止机器人处理自己发送的消息
    if (optionalAuthor.isEmpty()) {
      log.info("消息发送者信息缺失,可能是机器人自身发送的消息。");
      return Mono.empty();
    }
    if (optionalChat.isEmpty()) {
      log.info("消息信息缺失,可能是机器人自身发送的消息。");
      return Mono.empty();
    }
    long messageAuthorId = optionalAuthor.get().getId().asLong();
    if (botId == messageAuthorId) {
      log.info("获取到机器人的自身消息,忽略处理。");
      return Mono.empty();
    }

    // 创建消息分发器并处理事件
    MyTelegramMessageDispatcher dispatcher = new MyTelegramMessageDispatcher();
    return TelegramBotEventDispatcher.adapt(event, dispatcher);
  }

  @Override
  public Publisher<?> onCallbackQuery(CallbackQueryEvent event) {
    return super.onCallbackQuery(event);
  }
}

定义命令处理函数 ​

定义具体的命令处理逻辑,例如 /start 和 /about 命令。每个命令对应一个函数类,实现特定的功能。

StartCommandFunction ​

处理 /start 命令,发送欢迎信息。

java
package nexus.io.telegram.bots.command;

import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import telegram4j.core.event.domain.message.SendMessageEvent;
import telegram4j.core.object.Message;
import telegram4j.core.object.chat.Chat;

public class StartCommandFunction {

  public Publisher<? extends Message> apply(SendMessageEvent event) {
    String welcomeMessage = "🌐 **翻译机器人** 🌐\n\n这个机器人使用 GPT 技术为您提供高质量的文本翻译服务。欢迎使用翻译机器人!\n\n";

    Mono<Chat> chat = event.getMessage().getChat();
    return chat.flatMap(c -> c.sendMessage(welcomeMessage));
  }
}

AboutUsCommandFunction ​

处理 /about 命令,发送关于机器人的信息。

java
package nexus.io.telegram.bots.command;

import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import telegram4j.core.event.domain.message.SendMessageEvent;
import telegram4j.core.object.Message;
import telegram4j.core.object.chat.Chat;

public class AboutUsCommandFunction {

  public Publisher<? extends Message> apply(SendMessageEvent event) {
    String aboutMessage = "**开发者:** Litong Java\n**版本:** 1.0.0\n\n感谢您使用本机器人!";
    Mono<Chat> chat = event.getMessage().getChat();
    return chat.flatMap(c -> c.sendMessage(aboutMessage));
  }
}

配置 Telegram 客户端 ​

配置类负责初始化 Telegram 客户端,设置命令路由,并确保客户端在服务器关闭时正确断开连接。

java
package nexus.io.telegram.bots.config;

import java.nio.file.Path;
import java.time.Duration;
import java.util.function.Function;

import nexus.io.annotation.AConfiguration;
import nexus.io.annotation.Initialization;
import nexus.io.telegram.bots.adapter.MyBotEventAdapter;
import nexus.io.telegram.bots.command.AboutUsCommandFunction;
import nexus.io.telegram.bots.command.StartCommandFunction;
import nexus.io.telegram.command.TelegramClient;
import nexus.io.telegram.command.TelegramCommandRouter;
import nexus.io.telegram.config.TelegramBotConfig;
import nexus.io.tio.boot.server.TioBootServer;
import nexus.io.tio.utils.environment.EnvUtils;

import lombok.extern.slf4j.Slf4j;
import reactor.util.retry.Retry;
import telegram4j.core.MTProtoBootstrap;
import telegram4j.core.MTProtoTelegramClient;
import telegram4j.core.spec.BotCommandScopeSpec;
import telegram4j.mtproto.store.FileStoreLayout;
import telegram4j.mtproto.store.StoreLayoutImpl;

@Slf4j
@AConfiguration
public class MyTelegramBotConfig {

  @Initialization
  public void config() {
    // 从环境变量获取 Telegram API 配置信息
    int apiId = EnvUtils.getInt("telegram.api.id");
    String apiHash = EnvUtils.getStr("telegram.api.hash");
    String botAuthToken = EnvUtils.getStr("telegram.bot.auth.token");

    String botId = botAuthToken.split(":")[0];
    // 创建并连接 MTProto Telegram 客户端
    MTProtoBootstrap bootstrap = MTProtoTelegramClient.create(apiId, apiHash, botAuthToken);

    StoreLayoutImpl storeLayoutImpl = new StoreLayoutImpl(Function.identity());
    FileStoreLayout storeLayout = new FileStoreLayout(storeLayoutImpl, Path.of("t4j-bot_" + botId + ".bin"));
    bootstrap.setStoreLayout(storeLayout);

    MTProtoTelegramClient client = bootstrap.connect().block();
    if (client == null) {
      log.error("无法连接到 Telegram MTProto 客户端。");
      return;
    }
    log.info("成功连接到 Telegram MTProto 客户端。");

    // 删除已有的命令
    deleteCommand(client);

    // 添加命令路由
    TelegramCommandRouter.add("start", "Start using the bot", new StartCommandFunction()::apply);
    TelegramCommandRouter.add("about", "About this bot", new AboutUsCommandFunction()::apply);

    // 初始化事件适配器
    MyBotEventAdapter myBotEventAdapter = new MyBotEventAdapter(apiId);
    new TelegramBotConfig().init(client, apiId, apiHash, botAuthToken, myBotEventAdapter);

    // 添加客户端到 TelegramClient 管理器
    TelegramClient.addClient("translator", client);

    // 在服务器关闭时,断开 Telegram 客户端连接
    HookCan.me().addDestroyMethod(client::disconnect);
  }

  /**
   * 删除现有的命令,确保命令路由的正确性
   *
   * @param client MTProto Telegram 客户端
   */
  private void deleteCommand(MTProtoTelegramClient client) {
    client.resetCommands(BotCommandScopeSpec.of(BotCommandScopeSpec.Type.DEFAULT), "")
        .retryWhen(Retry.backoff(3, Duration.ofSeconds(2)))
        .doOnSuccess(v -> log.info("成功删除现有命令!"))
        .doOnError(e -> log.error("删除命令失败。", e))
        .block();
  }
}

详细说明 ​

  1. 环境变量配置:通过 EnvUtils 从环境变量中获取 Telegram API 的配置信息,包括 apiId、apiHash 和 botAuthToken。

  2. 创建客户端:使用 MTProtoBootstrap 创建 Telegram 客户端,并设置存储布局。这里使用 FileStoreLayout 将客户端数据存储在文件中。

  3. 连接客户端:调用 bootstrap.connect().block() 连接 Telegram 客户端,并检查连接是否成功。

  4. 命令管理:

    • 删除现有命令:调用 deleteCommand 方法,确保之前设置的命令被清除,避免命令冲突。
    • 添加新命令:通过 TelegramCommandRouter 添加 /start 和 /about 命令,并绑定对应的处理函数。
  5. 初始化事件适配器:创建 MyBotEventAdapter 实例,并将其传递给 TelegramBotConfig 进行初始化。

  6. 管理客户端:将创建的客户端添加到 TelegramClient 管理器中,以便在需要时进行管理和使用。

  7. 断开连接:通过 HookCan.me().addDestroyMethod(client::disconnect) 确保在服务器关闭时,Telegram 客户端能够正确断开连接,释放资源。

总结 ​

本文介绍了如何使用 telegram-client 库来简化 Telegram 机器人的开发过程。通过添加依赖、创建消息分发器、实现事件适配器、定义命令处理函数以及配置 Telegram 客户端,您可以快速搭建一个功能完善的 Telegram 机器人。上述示例代码展示了基本的消息处理和命令响应逻辑,您可以根据需求进行扩展和定制,以实现更复杂的功能。