机器人

TDLib 与 MTProto 深入解析:自定义 Telegram 客户端与自动化

本文厘清常被混淆的两个 Telegram API:机器人接口与客户端库。说明各自能做什么、以谁的身份行动、客户端库会把哪些数据留在你的服务器上,并给出判断该用哪一种的实用方法。

内容导读

本文厘清常被混淆的两个 Telegram API:机器人接口与客户端库。说明各自能做什么、以谁的身份行动、客户端库会把哪些数据留在你的服务器上,并给出判断该用哪一种的实用方法。

TDLib 与 MTProto 深入解析:自定义 Telegram 客户端与自动化主题插画

有两个完全不同的东西都被叫做“Telegram API”,把它们混为一谈是这部分课程里后果最严重的错误。其中一个让你构建机器人。另一个让你构建客户端——这意味着以某个人的身份登录,拥有那个人能看到和能做的一切。

两者的区别不在于性能,尽管人们通常是这样介绍的。而在于拿谁的账号去冒险。

完成这一步后你将能够做到

  • 根据两个接口以什么身份行动来区分它们,而不是根据它们的成本。
  • 说出构建客户端的正当理由,以及那些会导致账号被限制的理由。
  • 权衡客户端库会在你自己的服务器上留下什么。
  • 针对一个真实项目,判断你实际需要两者中的哪一个。
并排对比

机器人,还是一个人

在讨论任何技术细节之前先问一个问题:这件事必须以人类账号的身份行动吗?几乎答案都是否定的,于是整个第二列就不再适用。

构建机器人

被标识为机器人。人们能看出自己在和什么对话。
只出现在有人添加它的地方,且只拥有对方授予的权限。
不暴露个人账号。犯错损失的只是一个机器人,而不是一个身份。
基本涵盖了人们说“自动化”时所指的一切。

构建客户端

你是以某个人的身份登录,一切都以他的名义发生。
它能触及那个人能触及的一切——每个聊天、每个群组、每个文件。
在人类账号上进行自动化行为,正是账号被限制的原因。
你的服务器现在持有那个人消息的一份副本。

左列是绝大多数项目的答案,包括许多本应选它却伸手去够右列的项目。右列是用于构建真正的客户端应用程序的 ——而不是用来做一个能比机器人被允许的范围做更多事的机器人。

客户端库究竟是什么

每个 Telegram 应用程序底层都是一种二进制协议,使用它涉及序列化、会话处理、密钥交换和加密。没有哪个理智的人会从零实现它;Telegram 发布了一个官方库来完成这些,并暴露出任何语言都能调用的接口。

你得到的东西确实相当可观:一个持续维护的协议实现、一个把账号状态保存在磁盘上的本地加密数据库、能从断线中恢复的同步机制,以及访问用户账号能做的一切(而非机器人可做的子集)的能力。

你还会得到、并且在构建任何东西之前应该大声说出来的东西:该账号数据的完整本地副本,就在你的服务器上。 消息、文件、联系人、群组成员关系。这不是一个可以以后再处理的副作用;它就是你构建出来的东西,它改变了你的托管意味着什么、谁可以访问它,以及它被攻破意味着什么。

而且它创建的登录是该账号上的一个会话 ——在第 028 步的设备列表中可见,可以从手机撤销,并且能做已登录设备能做的一切。如果这个账号属于别人,你就是在向他们索取这个,他们应该明白自己同意的是什么。

界线,直白地说

这个库是官方的、合法的。人们用它构建的某些东西则不是,而一旦点明,这条界线并不微妙。

合理的用途。 构建客户端应用程序——一个替代界面、一个无障碍客户端、为没人写过应用的那种设备做的东西。归档或导出你自己的 账号,因为机器人接口根本无法触及你的历史记录。对你运营的社区执行机器人不被允许执行的管理操作。你自己使用的桌面工具。在每一种情况里,涉及的账号都是你自己的,行为也是一个人的行为。

会导致账号被限制的用途。 从群组收集成员列表。给从未联系过你的人发消息。大规模自动加入频道。运行一个像人一样按计划发帖、回应或回复的账号。从一个系统操作多个账号来模拟活动。

这些不是灰色地带,而且执法不是理论上的——它正是第 037 步所述限制的直接原因。后果落在账号上,通常意味着一个真实的人的电话号码、联系人和聊天记录,而且它来得毫无预警、无从申诉。

写下一行代码之前的两个问题 这件事真的必须以人类账号的身份行动吗,还是它只是需要你还没在机器人接口里找到的能力?还有:这是谁的账号,失去这个账号可以接受吗?如果第二个答案是“我自己的,而且不可以”,那这个项目需要的是另一种设计,而不是更多的谨慎。

人们实际想要的是什么

大多数伸手去够客户端库的项目,其实是在解决一个机器人接口用另一种方式解决的问题。反复出现的有四种:

“机器人读不到群里的消息。” 它能读到,只要关闭隐私模式或者它是管理员——第 086 步。默认设置是一项可以更改的限制,而不是一堵墙。

“我需要知道群里都有谁。” 拥有正确权限的机器人可以看到它管理的群组的成员列表。它做不到的是收集你不运营的社区的成员,而这正是这项限制存在的理由。

“文件太大了。” 机器人接口有大小限制,对于真正大的文件,诚实的答案是把它托管在某处然后发个链接,或者把它拆分——这两者对接收方来说都比一次他们没要求过的数 GB 传输要好。

“我想导出所有东西。” 这些应用程序有内置导出功能,在第 048 步有介绍,它无需任何人写代码就能生成完整归档。这几乎总是“我需要用 MTProto 来归档我的聊天”实际所指的意思。

诚实地过一遍这四种情况,大多数时候就能消除这个需求。当它不能消除时——确实存在真实的情况——你现在知道你是在构建一个客户端,而不是在绕过机器人。

现在试一试——五分钟

四个步骤。前两个就会为大多数读者终结这个问题。

  1. 写下你认为自己需要的能力 一句话。然后在假设机器人接口做不到之前,对照上面四种情况检查一下。
  2. 如果它仍然成立,说出是哪个账号 不是“某个账号”——而是一个具体的、属于某个具体的人的、上面有具体历史记录的账号。
  3. 打开你的设备列表 从账号的角度看看一个已登录会话是什么样子。那就是你的程序将会呈现的样子。
  4. 决定本地数据库放在哪里 如果你继续,答案就是一块存着某人消息的磁盘。加密它、限制访问它,要么刻意备份,要么干脆不备份。

如果你确实要构建一个

教程里很少提到的四个运维现实。

状态存在磁盘上,而且很重要。 这个库维护着一个代表该账号的数据库,删除它并不是一次干净的重启——它意味着一次全新的同步,某些情况下还意味着一次全新的登录。把这个目录当作你部署中重要的部分,而不是当作缓存。

第一次登录是交互式的。 有人要输入验证码,可能还要输入密码。这不符合部署流水线,所以要尽早决定首次运行和重新认证如何进行,因为“有人登录到服务器上”这个答案会是你不知不觉中最终得到的那个。

速率限制依然存在,而且在精神上更严格。 表现得像一个人,就意味着被期望像人一样行事。机器人只会被限流的突发活动,在用户账号上看起来,恰恰就是这些限制所针对的东西。

秘密聊天是唯一要避开的东西。 它们按设计绑定到设备,而一个同步账号内容的系统与这些对话存在的理由相冲突。如果某个账号有秘密聊天,要向它的所有者说清楚你的工具触及和不触及什么。

专用账号,以及为什么它不是护盾

对以上一切通常的回应是创建一个单独的账号来运行自动化,这样个人账号就永远不会处于风险之中。这是一种明智的直觉,但它起的作用比人们期望的要小。

它并不会让这种行为被允许。 规则描述的是账号可以做什么,而不是哪个账号在做,所以一个专门创建的账号运行同样的活动,会以同样的标准被限制——往往更快,因为一个没有历史记录、行为机械的新账号是最容易被识别出来的模式。

它仍然需要一个真实号码,这意味着一条真实的电话线或第 090 步中的某种安排,以及随之而来关于保管和找回的一切。账号不会凭空出现。

而且它拥有什么,就会带走什么。 这是代价高昂的部分。如果这个专用账号是某个群组或频道的创建者或所有者,那么对该账号的限制就是社区的问题,而不是脚本的问题——所有权、管理员权限以及找回这个空间的能力,全都系于一个你刚刚置于风险之中的身份。

如果你无论如何都要用一个,纪律很简单:它什么都不拥有。 它是一个拥有所需权限的成员,待在由某个人拥有的空间里,失去它让你付出的代价是一次重建,而不是一个社区。

这个阶段的常见问题

使用客户端库违反规则吗?

不——它是官方的、公开发布的,就是为了构建客户端而设计的。违反规则的是某一类行为而不是某个工具:在人类账号上进行的自动化活动、群发消息,以及收集没有与你互动过的人的数据。你可以用它构建一个完全合法的应用程序,也可以用同一个库让一个账号被永久限制,区别在于你让它做什么。

我能用它运行一个拥有额外权限的机器人吗?

这是关于这个主题的大多数问题背后的意图,而答案是:你运行的不会是机器人——而是一个假装成机器人的账号。你群里的人看到的会是一个人;承担风险的会是你自己的账号;而这种行为恰恰是执法所寻找的模式。如果机器人确实做不到你的社区需要的事,诚实的途径是换一种设计,或者接受这个限制。

我应该用哪种语言?

用你已经在用的任何一种,因为这个库暴露的接口大多数语言都能调用,而且流行的语言都有社区封装。真正重要的选择不是语言,而是你到底用不用官方库:自己实现协议是一个庞大的项目,有着微妙的失败模式,而且这些失败不是“连不上”这种明显的,而是状态悄悄失去同步这种安静的。

客户端库能读取秘密聊天吗?

它支持秘密聊天,因为客户端正是它们存在的环境——但一段秘密对话属于某个特定设备,所以一个新会话不会继承某人手机上的那些。这正是设计在正确运作,如第 025 步所解释的。如果你构建客户端的理由是为了触及那些被刻意限制在某个设备上的对话,那么设计正在告诉你一些值得听的东西。

如果账号被限制了,我的项目会怎样?

它会立即停止,毫无预警,建立在该身份之上的一切也随之而去——包括对该账号曾是所有者的任何社区的访问。这就是人们低估的风险:这不是一次服务中断,而是一个其他东西所依赖的身份的丧失。如果一个账号对任何东西来说是承重的,它就不应该同时是运行自动化的那个账号。

机器人和客户端之间有中间地带吗?

有,而且它没被充分利用:一个在你控制的房间里拥有正确管理权限的机器人,能做的事比人们以为的多得多,包括读取它管理的群里说的一切。把它与用于历史记录的普通导出、以及用于任何需要真正界面的东西的小程序结合起来,剩下的差距就很小了。大多数时候,中间地带不是另一种协议——而是给你自己的机器人授予你试图绕过的那些权限。

← 返回 TG知识库