Skip to content

About

一个面向 Go 的 Telegram Bot API SDK

Resources

Stars

2 stars

Watchers

1 watching

Forks

Latest commit

 

History

28 Commits

Folders and files

Repository files navigation

telegram-bot-api

一个面向 Go 的 Telegram Bot API SDK,模块路径为:

github.com/ijnkawakaze/telegram-bot-api

它在标准 BotAPI 之上增加了一层 Bot 处理器,适合快速编写轮询机器人,也保留完整的底层 Telegram API 调用能力。

特性

  • 支持长轮询和 Webhook。
  • 支持命令、私聊命令、回调查询、图片消息、回复消息、内联查询、入群/退群、入群申请等处理器。
  • 内置等待用户下一条消息、临时回调查询、权限校验、延迟删除消息等常用能力。
  • 提供 CallbackData、ExpiringSet、MessageCleaner 等工具类型。
  • 大部分类型和方法使用中文注释,便于阅读。
  • 当前同步到 Telegram Bot API 10.2。

安装

go get github.com/ijnkawakaze/telegram-bot-api

如果你在本地修改了 SDK,并希望另一个项目直接使用本地工作区,可以在 go.mod 中增加:

replace github.com/ijnkawakaze/telegram-bot-api => ../telegram-bot-api

../telegram-bot-api 是相对目标项目模块文件的路径,请按实际目录调整。

快速开始

轮询模式

package main

import (
	"log"

	tgbotapi "github.com/ijnkawakaze/telegram-bot-api"
)

func main() {
	bot, err := tgbotapi.NewBotAPI("YOUR_BOT_TOKEN")
	if err != nil {
		log.Fatal(err)
	}

	bot.Debug = true

	handler := bot.AddHandle()

	handler.NewCommandProcessor("start", func(update tgbotapi.Update) error {
		if update.Message == nil {
			return nil
		}

		_, err := update.Message.Reply("你好,我是机器人", bot)
		return err
	})

	handler.Run()
}

NewBotAPI 会立即调用 getMe 获取机器人信息;失败时返回错误,可以提前发现 token 或网络问题。

核心概念

BotAPI

BotAPI 是最底层的 Telegram API 客户端:

bot, err := tgbotapi.NewBotAPI("TOKEN")

它负责:

  • 发送请求:bot.Send(config)
  • 原始请求:bot.Request(config)
  • 获取更新:bot.GetUpdatesChan(config)
  • 文件下载:bot.GetFileDirectURL(fileID)

Bot

Bot 是处理器和状态层:

handler := bot.AddHandle()

Bot 内嵌了 *BotAPI,所以 handler 也可以直接调用 Send、SendText 等 API 方法:

handler.SendText(chatID, "hello")

推荐做法是:

  • 用 bot 处理 Telegram API 调用。
  • 用 handler 注册命令、回调和等待状态。
  • 最后调用 handler.Run() 启动长轮询。

发送消息

普通文本

message := tgbotapi.NewMessage(chatID, "hello")
message.ParseMode = tgbotapi.ModeMarkdownV2
bot.Send(message)

也可以使用快捷方法:

bot.SendText(chatID, "hello")
bot.SendMarkdownV2(chatID, "**hello**", messageID)
bot.ReplyText(chatID, messageID, "回复这条消息")

图片和文件

data, _ := os.ReadFile("photo.jpg")
bot.SendPhotoBytes(chatID, data, "photo.jpg")
doc := tgbotapi.NewDocument(chatID, tgbotapi.FilePath("./report.pdf"))
doc.Caption = "报告"
bot.Send(doc)

常用的文件表示:

  • tgbotapi.FileBytes{Name: "x.jpg", Bytes: data}
  • tgbotapi.FileReader{Name: "x.jpg", Reader: reader}
  • tgbotapi.FilePath("path/to/file")
  • tgbotapi.FileURL("https://example.com/file.jpg")

媒体组

photo := tgbotapi.NewInputMediaPhoto(tgbotapi.FilePath("1.jpg"))
video := tgbotapi.NewInputMediaVideo(tgbotapi.FileURL("https://example.com/v.mp4"))
mediaGroup := tgbotapi.NewMediaGroup(chatID, []interface{}{photo, video})
bot.SendMediaGroup(mediaGroup)

命令处理器

所有处理器的签名都是:

func(update tgbotapi.Update) error

普通命令

handler.NewCommandProcessor("start", func(update tgbotapi.Update) error {
	chatID := update.ChatID()
	userID := update.UserID()

	text := "欢迎使用机器人"
	_, err := bot.SendText(chatID, text)
	return err
})

私聊命令

handler.NewPrivateCommandProcessor("bind", bindHandler)

图片命令

当消息中包含照片且 Caption 以指定命令开头时触发:

handler.NewPhotoMessageProcessor("/ocr", func(update tgbotapi.Update) error {
	photo := update.Message.Photo
	// 处理图片
	return nil
})

回复消息

当用户回复某条消息并发送指定命令时触发:

handler.NewReplyMessageProcessor("/report", reportHandler)

内联查询

handler.NewInlineQueryProcessor("搜索", func(update tgbotapi.Update) error {
	if update.InlineQuery == nil {
		return nil
	}

	result := tgbotapi.NewInlineQueryResultArticle(
		update.InlineQuery.ID,
		"标题",
		"结果描述",
	)

	answer := tgbotapi.InlineConfig{
		InlineQueryID: update.InlineQuery.ID,
		Results:       []interface{}{result},
	}

	_, err := bot.Request(answer)
	return err
})

更多内联结果构造函数见 helpers.go。

回调查询

注册回调

handler.NewCallBackProcessor("choose", func(update tgbotapi.Update) error {
	query := update.CallbackQuery
	if query == nil {
		return nil
	}

	query.Answer(false, "", bot)
	return nil
})

回调数据通常使用逗号分隔:

data := tgbotapi.NewInlineKeyboardButtonData(
	"选择 A",
	"choose,A,123",
)

解析回调数据

handler.NewCallBackProcessor("choose", func(update tgbotapi.Update) error {
	data := tgbotapi.ParseCallbackData(update.CallbackData())
	action := data.StringAt(0) // "choose"
	itemID := data.StringAt(1) // "A"

	id, err := data.Int64At(2) // 123
	if err != nil {
		return err
	}

	_ = id
	return nil
})

也可以构造回调数据:

callbackData := tgbotapi.NewCallbackData("choose", "A", 123)
button := tgbotapi.NewInlineKeyboardButtonData("选择", callbackData.String())

等待用户下一条消息

有些流程需要先问用户一个问题,再等待用户回复。

注册等待处理器

handler.NewWaitMessageProcessor("setToken", func(update tgbotapi.Update) error {
	token := update.Message.Text
	// 处理用户输入的 token
	return nil
})

设置等待状态

handler.SetWaitMessage(userID, "setToken")

清除或检查等待状态:

handler.ClearWaitMessage(userID)

if handler.HasWaitMessage(userID) {
	// 用户仍处于等待输入状态
}

带上下文的等待

如果需要把上一步的数据带到下一步处理器:

handler.NewWaitContextProcessor("choosePlayer", func(update tgbotapi.Update, data any) error {
	uid := data.(string)
	_, _ = bot.SendText(update.ChatID(), "你选择了:"+uid)
	return nil
})

handler.SetWaitMessage(userID, "choosePlayer", "player-123")

临时回调查询

临时回调适合“只在短时间内有效,且只能由指定用户触发”的按钮。

callbackID, err := handler.RegisterEphemeralCallback(
	func(update tgbotapi.Update) error {
		_, err := bot.SendText(update.ChatID(), "你点击了临时按钮")
		return err
	},
	5*time.Minute,
	userID,
)
if err != nil {
	return err
}

button := tgbotapi.NewInlineKeyboardButtonData("确认", callbackID)

回调一旦被触发就会自动删除。

权限处理器

仅管理员可用

handler.NewAdminCommandProcessor("ban", banHandler)

带权限要求

handler.NewAdminCommandProcessorWithPermissions(
	"delete",
	tgbotapi.AdminCanDeleteMessages,
	deleteHandler,
)

仅所有者可用

handler.SetOwnerID(123456789)
handler.NewOwnerCommandProcessor("update", updateHandler)
handler.NewOwnerPrivateCommandProcessor("admin", adminHandler)

自定义包装

protected := handler.RequireAdmin(tgbotapi.AdminCanRestrictMembers, myHandler)
handler.NewCommandProcessor("mute", protected)

常用权限常量:

tgbotapi.AdminCanRestrictMembers
tgbotapi.AdminCanDeleteMessages
tgbotapi.AdminCanPromoteMembers
tgbotapi.AdminCanPostMessages
tgbotapi.AdminCanEditMessages
tgbotapi.AdminCanPinMessages
tgbotapi.AdminCanManageChat

群成员相关

handler.NewMemberProcessor(func(update tgbotapi.Update) error {
	// 新成员入群
	return nil
})

handler.LeftMemberProcessor(func(update tgbotapi.Update) error {
	// 成员退群或被移出
	return nil
})

handler.JoinRequestProcessor(func(update tgbotapi.Update) error {
	// 处理 ChatJoinRequest
	return nil
})

底层管理能力:

bot.RestrictChatMember(chatID, userID, tgbotapi.NoMessagesPermission)
bot.BanChatMember(chatID, userID)
bot.UnbanChatMember(chatID, userID)
bot.ApproveChatJoinRequest(chatID, userID)
bot.DeclineChatJoinRequest(chatID, userID)

下载文件

body, extension, err := bot.DownloadFile(fileID)
if err != nil {
	return err
}
defer body.Close()
data, extension, err := bot.DownloadFileBytes(fileID)

删除消息

立即删除

update.Message.Delete(bot)
update.CallbackQuery.Delete(bot)

延迟删除

update.Message.DeleteAfter(10*time.Second, bot)

批量清理器

cleaner := tgbotapi.NewMessageCleaner(bot)
defer cleaner.Close()

cleaner.DeleteAfter(chatID, messageID, 5*time.Second)

MessageCleaner.Close() 会等待正在执行的删除任务结束。

ExpiringSet

适合保存“待验证成员”“临时授权”等有过期时间的状态。

set := tgbotapi.NewExpiringSet()
set.Add(userKey, 5*time.Minute)

if set.Contains(userKey) {
	// 尚未过期
}

if set.Pop(userKey) {
	// 取出并删除,且尚未过期
}

Webhook 模式

基础用法:

bot, err := tgbotapi.NewBotAPI("TOKEN")
if err != nil {
	log.Fatal(err)
}

updates := bot.ListenForWebhook("/" + bot.Token)
for update := range updates {
	// 处理 update
}

http.ListenAndServe(":8443", nil)

也可直接处理单个请求:

update, err := bot.HandleUpdate(r)

Webhook 部署时还需要在 Telegram 侧设置:

https://你的域名:8443/<bot_token>

生产环境建议使用 Nginx 或 Caddy 提供 TLS。

常用工具

转义 MarkdownV2

text := tgbotapi.EscapeText(tgbotapi.ModeMarkdownV2, "hello_world")
bot.SendMarkdownV2(chatID, text)

判断消息是否发给机器人

if bot.IsMessageToMe(update.Message) {
	// 处理
}

获取机器人信息

me, err := bot.GetMe()

目录结构

bot.go       BotAPI 客户端、HTTP 请求、轮询和 Webhook
configs.go   Telegram API 请求配置类型
types.go     Telegram API 对象类型
helpers.go   创建请求配置的构造函数
custom.go    Bot 处理器、等待状态、临时回调和增强快捷方法
passport.go  Telegram Passport 相关类型
params.go    HTTP 参数处理

本地开发调试

当同时开发 SDK 和业务项目时,推荐使用 replace 指向本地目录:

// 业务项目 go.mod
replace github.com/ijnkawakaze/telegram-bot-api => ../telegram-bot-api

然后在业务项目中:

bot, _ := tgbotapi.NewBotAPI("TOKEN")
handler := bot.AddHandle()

如果业务代码只需要一个变量,也可以让 Bot 同时承担 API 和处理器职责:

bot := &tgbotapi.Bot{BotAPI: api}

参考

About

一个面向 Go 的 Telegram Bot API SDK

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages