From e37701840de126c2370e4ae8dc5380ad7eacf4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Tue, 31 May 2022 21:09:38 +0800 Subject: [PATCH] init --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ bot.go | 52 +++++++++++++++++++++++++++++++++++++++++ client.go | 52 +++++++++++++++++++++++++++++++++++++++++ event.go | 38 ++++++++++++++++++++++++++++++ example/main.go | 48 ++++++++++++++++++++++++++++++++++++++ go.mod | 5 ++++ go.sum | 2 ++ handler.go | 39 +++++++++++++++++++++++++++++++ 8 files changed, 297 insertions(+) create mode 100644 bot.go create mode 100644 client.go create mode 100644 event.go create mode 100644 example/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 handler.go diff --git a/README.md b/README.md index 3dea496..c63e97d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,63 @@ # ReiBot Lightweight Telegram bot framework + +## Instructions + +This framework is a simple wrapper for [go-telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api), aiming to make the event processing easier. + +## Example + +See under `example` folder or below. + +![example](https://user-images.githubusercontent.com/41315874/171180885-c888a031-7797-4b4b-a232-9ff23f031b32.png) + +```go +package main + +import ( + "log" + "strings" + + rei "github.com/fumiama/ReiBot" + tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +func main() { + rei.Run(rei.Bot{ + Token: "", + Buffer: 256, + UpdateConfig: tgba.UpdateConfig{ + Offset: 0, + Limit: 0, + Timeout: 60, + }, + Debug: true, + Handler: rei.Handler{ + OnMessage: func(updateid int, bot *rei.TelegramClient, msg *tgba.Message) { + if len(msg.Text) <= len("测试") { + return + } + if !strings.HasPrefix(msg.Text, "测试") { + return + } + _, err := bot.Send(tgba.NewMessage(msg.Chat.ID, msg.Text[len("测试"):])) + if err != nil { + log.Println("[ERRO]", err) + } + }, + OnEditedMessage: func(updateid int, bot *rei.TelegramClient, msg *tgba.Message) { + if len(msg.Text) <= len("测试") { + return + } + if !strings.HasPrefix(msg.Text, "测试") { + return + } + _, err := bot.Send(tgba.NewMessage(msg.Chat.ID, "已编辑:"+msg.Text[len("测试"):])) + if err != nil { + log.Println("[ERRO]", err) + } + }, + }, + }) +} +``` \ No newline at end of file diff --git a/bot.go b/bot.go new file mode 100644 index 0000000..d723551 --- /dev/null +++ b/bot.go @@ -0,0 +1,52 @@ +// Package rei ReiBot created in 2022.5.31 +package rei + +import ( + tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +// Bot bot 的配置 +type Bot struct { + // Token bot 的 token + // see https://core.telegram.org/bots#3-how-do-i-create-a-bot + Token string `json:"token"` + // Buffer 控制消息队列的长度 + Buffer int `json:"buffer"` + // UpdateConfig 配置消息获取 + tgba.UpdateConfig + // Debug 控制调试信息的输出与否 + Debug bool `json:"debug"` + // Handler 注册对各种事件的处理 + Handler Handler +} + +// Start clients without blocking +func Start(bots ...Bot) { + for _, c := range bots { + tc := NewTelegramClient(&c) + tc.Connect() + go tc.Listen() + } +} + +// Run clients and block self in listening last one +func Run(bots ...Bot) { + var tc TelegramClient + switch len(bots) { + case 0: + return + case 1: + c := bots[0] + tc = NewTelegramClient(&c) + default: + for _, c := range bots[:len(bots)-1] { + tc := NewTelegramClient(&c) + tc.Connect() + go tc.Listen() + } + c := bots[len(bots)-1] + tc = NewTelegramClient(&c) + } + tc.Connect() + tc.Listen() +} diff --git a/client.go b/client.go new file mode 100644 index 0000000..ae80db8 --- /dev/null +++ b/client.go @@ -0,0 +1,52 @@ +package rei + +import ( + "log" + "time" + + tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +// TelegramClient ... +type TelegramClient struct { + tgba.BotAPI + b Bot +} + +// NewTelegramClient ... +func NewTelegramClient(c *Bot) (tc TelegramClient) { + tc.b = *c + return +} + +// Connect ... +func (tc *TelegramClient) Connect() { + log.Println("[INFO] 开始尝试连接到Telegram服务器, token:", tc.b.Token) + for { + ba, err := tgba.NewBotAPI(tc.b.Token) + if err != nil { + log.Println("[WARN] 连接到Telegram服务器时出现错误:", err, ", token:", tc.b.Token) + time.Sleep(2 * time.Second) // 等待两秒后重新连接 + continue + } + tc.BotAPI = *ba + tc.Debug = tc.b.Debug + tc.Buffer = tc.b.Buffer + break + } + log.Println("[INFO] 连接到Telegram服务器成功, token:", tc.b.Token) +} + +// Listen 开始监听事件 +func (tc *TelegramClient) Listen() { + log.Println("[INFO] 开始监听", tc.Self.UserName, "的事件") + for { + updates := tc.GetUpdatesChan(tc.b.UpdateConfig) + for update := range updates { + tc.processEvent(update) + } + log.Println("[WARN] Telegram服务器连接断开...") + time.Sleep(time.Millisecond * time.Duration(3)) + tc.Connect() + } +} diff --git a/event.go b/event.go new file mode 100644 index 0000000..5160e3f --- /dev/null +++ b/event.go @@ -0,0 +1,38 @@ +package rei + +import ( + "log" + "reflect" + "unsafe" + + tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +// Event ... +type Event struct { + // Type is the non-null field name in Update + Type string + // UpdateID is the update's unique identifier. + UpdateID int + // Value is the non-null field value in Update + Value reflect.Value +} + +func (tc *TelegramClient) processEvent(update tgba.Update) { + v := reflect.ValueOf(&update).Elem() + t := reflect.ValueOf(&update).Elem().Type() + h := reflect.ValueOf(tc.b.Handler) + for i := 1; i < v.NumField(); i++ { + f := v.Field(i) + if f.IsZero() { + continue + } + m := h.FieldByName("On" + t.Field(i).Name) + if m.IsZero() { + continue + } + log.Println("[INFO] processEvent call", "On"+t.Field(i).Name) + handler := m.Interface() + go (*(*GeneralHandleType)(unsafe.Add(unsafe.Pointer(&handler), unsafe.Sizeof(uintptr(0)))))(update.UpdateID, tc, f.UnsafePointer()) + } +} diff --git a/example/main.go b/example/main.go new file mode 100644 index 0000000..aff9309 --- /dev/null +++ b/example/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "log" + "strings" + + rei "github.com/fumiama/ReiBot" + tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +func main() { + rei.Run(rei.Bot{ + Token: "", + Buffer: 256, + UpdateConfig: tgba.UpdateConfig{ + Offset: 0, + Limit: 0, + Timeout: 60, + }, + Debug: true, + Handler: rei.Handler{ + OnMessage: func(updateid int, bot *rei.TelegramClient, msg *tgba.Message) { + if len(msg.Text) <= len("测试") { + return + } + if !strings.HasPrefix(msg.Text, "测试") { + return + } + _, err := bot.Send(tgba.NewMessage(msg.Chat.ID, msg.Text[len("测试"):])) + if err != nil { + log.Println("[ERRO]", err) + } + }, + OnEditedMessage: func(updateid int, bot *rei.TelegramClient, msg *tgba.Message) { + if len(msg.Text) <= len("测试") { + return + } + if !strings.HasPrefix(msg.Text, "测试") { + return + } + _, err := bot.Send(tgba.NewMessage(msg.Chat.ID, "已编辑:"+msg.Text[len("测试"):])) + if err != nil { + log.Println("[ERRO]", err) + } + }, + }, + }) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9c5171d --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/fumiama/ReiBot + +go 1.18 + +require github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..db8e45c --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= diff --git a/handler.go b/handler.go new file mode 100644 index 0000000..1e434d0 --- /dev/null +++ b/handler.go @@ -0,0 +1,39 @@ +package rei + +import ( + "unsafe" + + tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +type GeneralHandleType func(int, *TelegramClient, unsafe.Pointer) + +type Handler struct { + OnMessage func(updateid int, bot *TelegramClient, msg *tgba.Message) + + OnEditedMessage func(updateid int, bot *TelegramClient, msg *tgba.Message) + + OnChannelPost func(updateid int, bot *TelegramClient, msg *tgba.Message) + + OnEditedChannelPost func(updateid int, bot *TelegramClient, msg *tgba.Message) + + OnInlineQuery func(updateid int, bot *TelegramClient, q *tgba.InlineQuery) + + OnChosenInlineResult func(updateid int, bot *TelegramClient, r *tgba.ChosenInlineResult) + + OnCallbackQuery func(updateid int, bot *TelegramClient, q *tgba.CallbackQuery) + + OnShippingQuery func(updateid int, bot *TelegramClient, q *tgba.ShippingQuery) + + OnPreCheckoutQuery func(updateid int, bot *TelegramClient, q *tgba.PreCheckoutQuery) + + OnPoll func(updateid int, bot *TelegramClient, p *tgba.Poll) + + OnPollAnswer func(updateid int, bot *TelegramClient, pa *tgba.PollAnswer) + + OnMyChatMember func(updateid int, bot *TelegramClient, m *tgba.ChatMemberUpdated) + + OnChatMember func(updateid int, bot *TelegramClient, m *tgba.ChatMemberUpdated) + + OnChatJoinRequest func(updateid int, bot *TelegramClient, r *tgba.ChatJoinRequest) +}