diff --git a/api.go b/api.go index aa9983e..31de0b6 100644 --- a/api.go +++ b/api.go @@ -7,8 +7,27 @@ import ( "io" "net/http" "strings" + + "git.nix13.pw/scuroneko/slog" ) +type Api struct { + token string + logger *slog.Logger +} + +func NewAPI(token string) *Api { + l := slog.CreateLogger().Level(GetLoggerLevel()).Prefix("API") + l.AddWriter(l.CreateJsonStdoutWriter()) + return &Api{ + token: token, + logger: l, + } +} +func (api *Api) CloseApi() { + api.logger.Close() +} + type ApiResponse[R any] struct { Ok bool `json:"ok"` Description string `json:"description,omitempty"` @@ -24,21 +43,21 @@ type TelegramRequest[R, P any] struct { func NewRequest[R, P any](method string, params P) TelegramRequest[R, P] { return TelegramRequest[R, P]{method: method, params: params} } -func (r TelegramRequest[R, P]) Do(bot *Bot) (*R, error) { +func (r TelegramRequest[R, P]) Do(api *Api) (*R, error) { var buf bytes.Buffer err := json.NewEncoder(&buf).Encode(r.params) if err != nil { return nil, err } - if bot.requestLogger != nil { - bot.requestLogger.Debugln(strings.ReplaceAll(fmt.Sprintf( + if api.logger != nil { + api.logger.Debugln(strings.ReplaceAll(fmt.Sprintf( "POST https://api.telegram.org/bot%s/%s %s", "", r.method, buf.String(), ), "\n", "")) } - req, err := http.Post(fmt.Sprintf("https://api.telegram.org/bot%s/%s", bot.token, r.method), "application/json", &buf) + req, err := http.Post(fmt.Sprintf("https://api.telegram.org/bot%s/%s", api.token, r.method), "application/json", &buf) if err != nil { return nil, err } @@ -48,8 +67,8 @@ func (r TelegramRequest[R, P]) Do(bot *Bot) (*R, error) { return nil, err } - if bot.requestLogger != nil { - bot.requestLogger.Debugln(fmt.Sprintf("RES %s %s", r.method, string(data))) + if api.logger != nil { + api.logger.Debugln(fmt.Sprintf("RES %s %s", r.method, string(data))) } response := new(ApiResponse[R]) diff --git a/bot.go b/bot.go index 9295a9c..f17db42 100644 --- a/bot.go +++ b/bot.go @@ -37,6 +37,9 @@ type Bot struct { runners []Runner dbContext *DatabaseContext + api *Api + + dbWriterRequested extypes.Slice[*slog.Logger] updateOffset int updateTypes []string @@ -75,12 +78,14 @@ func LoadPrefixesFromEnv() []string { } func NewBot(settings *BotSettings) *Bot { updateQueue := extypes.CreateQueue[*Update](256) + api := NewAPI(settings.Token) bot := &Bot{ updateOffset: 0, plugins: make([]Plugin, 0), debug: settings.Debug, errorTemplate: "%s", prefixes: settings.Prefixes, updateTypes: make([]string, 0), runners: make([]Runner, 0), - updateQueue: updateQueue, - token: settings.Token, + updateQueue: updateQueue, api: api, dbWriterRequested: make([]*slog.Logger, 0), + token: settings.Token, } + bot.dbWriterRequested = bot.dbWriterRequested.Push(api.logger) if len(settings.ErrorTemplate) > 0 { bot.errorTemplate = settings.ErrorTemplate @@ -118,7 +123,7 @@ func NewBot(settings *BotSettings) *Bot { } } - u, err := bot.GetMe() + u, err := api.GetMe() if err != nil { bot.logger.Fatal(err) } @@ -150,6 +155,9 @@ func (b *Bot) AddDatabaseLogger(writer func(db *DatabaseContext) slog.LoggerWrit if b.requestLogger != nil { b.requestLogger.AddWriter(w) } + for _, l := range b.dbWriterRequested { + l.AddWriter(w) + } return b } @@ -251,7 +259,7 @@ func (b *Bot) Run() { continue } - ctx := &MsgContext{Bot: b, Update: u} + ctx := &MsgContext{Bot: b, Update: u, Api: b.api} for _, middleware := range b.middlewares { middleware.Execute(ctx, b.dbContext) } diff --git a/handler.go b/handler.go index c2f8877..487843d 100644 --- a/handler.go +++ b/handler.go @@ -35,6 +35,18 @@ func (b *Bot) handleMessage(update *Update, ctx *MsgContext) { if !strings.HasPrefix(text, cmd) { continue } + requestParts := strings.Split(text, " ") + cmdParts := strings.Split(cmd, " ") + isValid := true + for i, part := range cmdParts { + if part != requestParts[i] { + isValid = false + break + } + } + if !isValid { + continue + } ctx.Text = strings.TrimSpace(text[len(cmd):]) ctx.Args = strings.Split(ctx.Text, " ") diff --git a/keyboard.go b/keyboard.go index bdb9e35..b023332 100644 --- a/keyboard.go +++ b/keyboard.go @@ -41,11 +41,11 @@ func (in *InlineKeyboard) AddLine() *InlineKeyboard { in.CurrentLine = make([]InlineKeyboardButton, 0) return in } -func (in *InlineKeyboard) Get() InlineKeyboardMarkup { +func (in *InlineKeyboard) Get() *InlineKeyboardMarkup { if len(in.CurrentLine) > 0 { in.Lines = append(in.Lines, in.CurrentLine) } - return InlineKeyboardMarkup{ + return &InlineKeyboardMarkup{ InlineKeyboard: in.Lines, } } diff --git a/methods.go b/methods.go index 81ef1b6..2dc3372 100644 --- a/methods.go +++ b/methods.go @@ -23,7 +23,7 @@ func (b *Bot) Updates() ([]*Update, error) { } req := NewRequest[[]*Update]("getUpdates", params) - res, err := req.Do(b) + res, err := req.Do(b.api) if err != nil { return []*Update{}, err } @@ -47,30 +47,143 @@ func (b *Bot) Updates() ([]*Update, error) { return updates, err } -func (b *Bot) GetMe() (*User, error) { +func (api *Api) GetMe() (*User, error) { req := NewRequest[User, EmptyParams]("getMe", NoParams) - return req.Do(b) + return req.Do(api) +} +func (api *Api) LogOut() (bool, error) { + req := NewRequest[bool, EmptyParams]("logOut", NoParams) + res, err := req.Do(api) + if err != nil { + return false, err + } + return *res, nil +} +func (api *Api) Close() (bool, error) { + req := NewRequest[bool, EmptyParams]("close", NoParams) + res, err := req.Do(api) + if err != nil { + return false, err + } + return *res, nil } type SendMessageP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - Text string `json:"text"` - Entities []*MessageEntity `json:"entities,omitempty"` - LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` - DisableNotifications bool `json:"disable_notifications,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` - ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` - ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"` + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + Text string `json:"text"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + Entities []*MessageEntity `json:"entities,omitempty"` + LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` + DisableNotifications bool `json:"disable_notifications,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } -func (b *Bot) SendMessage(params *SendMessageP) (*Message, error) { +func (api *Api) SendMessage(params *SendMessageP) (*Message, error) { req := NewRequest[Message, SendMessageP]("sendMessage", *params) - return req.Do(b) + return req.Do(api) +} + +type ForwardMessageP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + MessageID int `json:"message_id,omitempty"` + FromChatID int `json:"from_chat_id,omitempty"` + VideoStartTimestamp int `json:"video_start_timestamp,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + + MessageEffectID string `json:"message_effect_id,omitempty"` + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` +} + +func (api *Api) ForwardMessage(params ForwardMessageP) (*Message, error) { + req := NewRequest[Message]("forwardMessage", params) + return req.Do(api) +} + +type ForwardMessagesP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + FromChatID int `json:"from_chat_id,omitempty"` + MessageIDs []int `json:"message_ids,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` +} + +func (api *Api) ForwardMessages(params ForwardMessagesP) ([]int, error) { + req := NewRequest[[]int]("forwardMessages", params) + res, err := req.Do(api) + if err != nil { + return []int{}, err + } + return *res, nil +} + +type CopyMessageP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + FromChatID int `json:"from_chat_id"` + MessageID int `json:"message_id"` + VideoStartTimestamp int `json:"video_start_timestamp,omitempty"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +func (api *Api) CopyMessage(params CopyMessageP) (int, error) { + req := NewRequest[int]("copyMessage", params) + res, err := req.Do(api) + if err != nil { + return 0, err + } + return *res, nil +} + +type CopyMessagesP struct { + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessageTopicID int `json:"direct_message_topic_id,omitempty"` + + FromChatID int `json:"from_chat_id,omitempty"` + MessageIDs []int `json:"message_ids,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + RemoveCaption bool `json:"remove_caption,omitempty"` +} + +func (api *Api) CopyMessages(params CopyMessagesP) ([]int, error) { + req := NewRequest[[]int]("copyMessages", params) + res, err := req.Do(api) + if err != nil { + return []int{}, err + } + return *res, nil } type SendPhotoBaseP struct { @@ -89,55 +202,61 @@ type SendPhotoBaseP struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } type SendPhotoP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - Caption string `json:"caption,omitempty"` - CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` - ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` - HasSpoiler bool `json:"has_spoiler,omitempty"` - DisableNotifications bool `json:"disable_notifications,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` - MessageEffectID string `json:"message_effect_id,omitempty"` - ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"` - Photo string `json:"photo"` + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + DirectMessagesTopicID int `json:"direct_messages_topic_id,omitempty"` + + Photo string `json:"photo"` + Caption string `json:"caption,omitempty"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"` + + ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"` + HasSpoiler bool `json:"has_spoiler,omitempty"` + DisableNotifications bool `json:"disable_notifications,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` + MessageEffectID string `json:"message_effect_id,omitempty"` + + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } -func (b *Bot) SendPhoto(params *SendPhotoP) (*Message, error) { +func (api *Api) SendPhoto(params *SendPhotoP) (*Message, error) { req := NewRequest[Message]("sendPhoto", params) - return req.Do(b) + return req.Do(api) } type EditMessageTextP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id,omitempty"` - MessageID int `json:"message_id,omitempty"` - InlineMessageID string `json:"inline_message_id,omitempty"` - Text string `json:"text"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"` + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + Text string `json:"text"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } -func (b *Bot) EditMessageText(params *EditMessageTextP) (*Message, error) { +func (api *Api) EditMessageText(params *EditMessageTextP) (*Message, error) { req := NewRequest[Message]("editMessageText", params) - return req.Do(b) + return req.Do(api) } type EditMessageCaptionP struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID int `json:"chat_id,omitempty"` - MessageID int `json:"message_id,omitempty"` - InlineMessageID string `json:"inline_message_id,omitempty"` - Caption string `json:"caption"` - ParseMode ParseMode `json:"parse_mode,omitempty"` - ReplyMarkup InlineKeyboardMarkup `json:"reply_markup,omitempty"` + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id,omitempty"` + InlineMessageID string `json:"inline_message_id,omitempty"` + Caption string `json:"caption"` + ParseMode ParseMode `json:"parse_mode,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } -func (b *Bot) EditMessageCaption(params *EditMessageCaptionP) (*Message, error) { +func (api *Api) EditMessageCaption(params *EditMessageCaptionP) (*Message, error) { req := NewRequest[Message]("editMessageCaption", params) - return req.Do(b) + return req.Do(api) } type DeleteMessageP struct { @@ -145,9 +264,9 @@ type DeleteMessageP struct { MessageID int `json:"message_id"` } -func (b *Bot) DeleteMessage(params *DeleteMessageP) (bool, error) { +func (api *Api) DeleteMessage(params *DeleteMessageP) (bool, error) { req := NewRequest[bool]("deleteMessage", params) - ok, err := req.Do(b) + ok, err := req.Do(api) if err != nil { return false, err } @@ -162,9 +281,9 @@ type AnswerCallbackQueryP struct { CacheTime int `json:"cache_time,omitempty"` } -func (b *Bot) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) { +func (api *Api) AnswerCallbackQuery(params *AnswerCallbackQueryP) (bool, error) { req := NewRequest[bool]("answerCallbackQuery", params) - ok, err := req.Do(b) + ok, err := req.Do(api) if err != nil { return false, err } @@ -175,9 +294,9 @@ type GetFileP struct { FileId string `json:"file_id"` } -func (b *Bot) GetFile(params *GetFileP) (*File, error) { +func (api *Api) GetFile(params *GetFileP) (*File, error) { req := NewRequest[File]("getFile", params) - return req.Do(b) + return req.Do(api) } type SendChatActionP struct { @@ -187,9 +306,9 @@ type SendChatActionP struct { Action ChatActions `json:"action"` } -func (b *Bot) SendChatAction(params SendChatActionP) (bool, error) { +func (api *Api) SendChatAction(params SendChatActionP) (bool, error) { req := NewRequest[bool]("sendChatAction", params) - res, err := req.Do(b) + res, err := req.Do(api) if err != nil { return false, err } @@ -206,9 +325,9 @@ type SetMessageReactionEmojiP struct { Reaction []ReactionTypeEmoji `json:"reaction"` } -func (b *Bot) SetMessageReactionEmoji(params SetMessageReactionEmojiP) (bool, error) { +func (api *Api) SetMessageReactionEmoji(params SetMessageReactionEmojiP) (bool, error) { req := NewRequest[bool]("setMessageReaction", params) - res, err := req.Do(b) + res, err := req.Do(api) if err != nil { return false, err } @@ -220,9 +339,9 @@ type SetMessageReactionCustomEmojiP struct { Reaction []ReactionTypeCustomEmoji `json:"reaction"` } -func (b *Bot) SetMessageReactionCustom(params SetMessageReactionCustomEmojiP) (bool, error) { +func (api *Api) SetMessageReactionCustom(params SetMessageReactionCustomEmojiP) (bool, error) { req := NewRequest[bool]("setMessageReaction", params) - res, err := req.Do(b) + res, err := req.Do(api) if err != nil { return false, err } @@ -233,9 +352,9 @@ type SetMessageReactionPaidP struct { SetMessageReactionP } -func (b *Bot) SetMessageReactionPaid(params SetMessageReactionPaidP) (bool, error) { +func (api *Api) SetMessageReactionPaid(params SetMessageReactionPaidP) (bool, error) { req := NewRequest[bool]("setMessageReaction", params) - res, err := req.Do(b) + res, err := req.Do(api) if err != nil { return false, err } diff --git a/msg_context.go b/msg_context.go index e1d92bc..fa9f2c0 100644 --- a/msg_context.go +++ b/msg_context.go @@ -3,7 +3,9 @@ package laniakea import "fmt" type MsgContext struct { - Bot *Bot + Bot *Bot + Api *Api + Msg *Message Update *Update From *User @@ -33,9 +35,9 @@ func (ctx *MsgContext) edit(messageId int, text string, keyboard *InlineKeyboard if keyboard != nil { params.ReplyMarkup = keyboard.Get() } - msg, err := ctx.Bot.EditMessageText(params) + msg, err := ctx.Api.EditMessageText(params) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) return nil } return &AnswerMessage{ @@ -47,7 +49,7 @@ func (m *AnswerMessage) Edit(text string) *AnswerMessage { } func (ctx *MsgContext) EditCallback(text string, keyboard *InlineKeyboard) *AnswerMessage { if ctx.CallbackMsgId == 0 { - ctx.Bot.logger.Errorln("Can't edit non-callback update message") + ctx.Api.logger.Errorln("Can't edit non-callback update message") return nil } @@ -67,9 +69,9 @@ func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeybo if kb != nil { params.ReplyMarkup = kb.Get() } - msg, err := ctx.Bot.EditMessageCaption(params) + msg, err := ctx.Api.EditMessageCaption(params) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) } return &AnswerMessage{ MessageID: msg.MessageID, ctx: ctx, Text: text, IsMedia: true, @@ -77,7 +79,7 @@ func (ctx *MsgContext) editPhotoText(messageId int, text string, kb *InlineKeybo } func (m *AnswerMessage) EditCaption(text string) *AnswerMessage { if m.MessageID == 0 { - m.ctx.Bot.logger.Errorln("Can't edit caption message, message id is zero") + m.ctx.Api.logger.Errorln("Can't edit caption message, message id is zero") return m } return m.ctx.editPhotoText(m.MessageID, text, nil) @@ -96,9 +98,9 @@ func (ctx *MsgContext) answer(text string, keyboard *InlineKeyboard) *AnswerMess params.ReplyMarkup = keyboard.Get() } - msg, err := ctx.Bot.SendMessage(params) + msg, err := ctx.Api.SendMessage(params) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) return nil } return &AnswerMessage{ @@ -125,9 +127,9 @@ func (ctx *MsgContext) answerPhoto(photoId, text string, kb *InlineKeyboard) *An if kb != nil { params.ReplyMarkup = kb.Get() } - msg, err := ctx.Bot.SendPhoto(params) + msg, err := ctx.Api.SendPhoto(params) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) return &AnswerMessage{ ctx: ctx, Text: text, IsMedia: true, } @@ -144,12 +146,12 @@ func (ctx *MsgContext) AnswerPhotoKeyboard(photoId, text string, kb *InlineKeybo } func (ctx *MsgContext) delete(messageId int) { - _, err := ctx.Bot.DeleteMessage(&DeleteMessageP{ + _, err := ctx.Api.DeleteMessage(&DeleteMessageP{ ChatID: ctx.Msg.Chat.ID, MessageID: messageId, }) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) } } func (m *AnswerMessage) Delete() { @@ -163,12 +165,12 @@ func (ctx *MsgContext) answerCallbackQuery(url, text string, showAlert bool) { if len(ctx.CallbackQueryId) == 0 { return } - _, err := ctx.Bot.AnswerCallbackQuery(&AnswerCallbackQueryP{ + _, err := ctx.Api.AnswerCallbackQuery(&AnswerCallbackQueryP{ CallbackQueryID: ctx.CallbackQueryId, Text: text, ShowAlert: showAlert, URL: url, }) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) } } func (ctx *MsgContext) AnswerCbQuery() { @@ -185,11 +187,11 @@ func (ctx *MsgContext) AnswerCbQueryUrl(u string) { } func (ctx *MsgContext) SendAction(action ChatActions) { - _, err := ctx.Bot.SendChatAction(SendChatActionP{ + _, err := ctx.Api.SendChatAction(SendChatActionP{ ChatID: ctx.Msg.Chat.ID, Action: action, }) if err != nil { - ctx.Bot.logger.Errorln(err) + ctx.Api.logger.Errorln(err) } } diff --git a/plugins.go b/plugins.go index 86b5e96..945bbc3 100644 --- a/plugins.go +++ b/plugins.go @@ -58,7 +58,7 @@ func (p *PluginBuilder) Middleware(middleware *PluginMiddleware) *PluginBuilder func (p *PluginBuilder) Build() Plugin { if len(p.commands) == 0 && len(p.payloads) == 0 { - log.Println("no command or payloads") + log.Printf("no command or payloads for %s", p.name) } return Plugin{ Name: p.name, diff --git a/types.go b/types.go index 974f144..50f652e 100644 --- a/types.go +++ b/types.go @@ -83,13 +83,15 @@ type MessageEntity struct { } type ReplyParameters struct { - MessageID int `json:"message_id"` - ChatID int `json:"chat_id,omitempty"` + MessageID int `json:"message_id"` + ChatID int `json:"chat_id,omitempty"` + AllowSendingWithoutReply bool `json:"allow_sending_without_reply,omitempty"` Quote string `json:"quote,omitempty"` QuoteParsingMode string `json:"quote_parsing_mode,omitempty"` QuoteEntities []*MessageEntity `json:"quote_entities,omitempty"` - QuotePosition int `json:"quote_postigin,omitempty"` + QuotePosition int `json:"quote_position,omitempty"` + ChecklistTaskID int `json:"checklist_task_id,omitempty"` } type PhotoSize struct { @@ -108,6 +110,20 @@ type LinkPreviewOptions struct { ShowAboveText bool `json:"show_above_text,omitempty"` } +type ReplyMarkup struct { + InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard,omitempty"` + + Keyboard [][]int `json:"keyboard,omitempty"` + IsPersistent bool `json:"is_persistent,omitempty"` + ResizeKeyboard bool `json:"resize_keyboard,omitempty"` + OneTimeKeyboard bool `json:"one_time_keyboard,omitempty"` + InputFieldPlaceholder string `json:"input_field_placeholder,omitempty"` + Selective bool `json:"selective,omitempty"` + + RemoveKeyboard bool `json:"remove_keyboard,omitempty"` + + ForceReply bool `json:"force_reply,omitempty"` +} type InlineKeyboardMarkup struct { InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard,omitempty"` } @@ -194,3 +210,17 @@ const ( ChatActionFindLocation ChatActions = "find_location" ChatActionUploadVideoNone ChatActions = "upload_video_none" ) + +type SuggestedPostPrice struct { + Currency string `json:"currency"` + Amount int `json:"amount"` +} +type SuggestedPostInfo struct { + State string `json:"state"` //State of the suggested post. Currently, it can be one of “pending”, “approved”, “declined”. + Price SuggestedPostPrice `json:"price"` + SendDate int `json:"send_date"` +} +type SuggestedPostParameters struct { + Price SuggestedPostPrice `json:"price"` + SendDate int `json:"send_date"` +} diff --git a/uploader.go b/uploader.go index def36ce..087a4f2 100644 --- a/uploader.go +++ b/uploader.go @@ -8,14 +8,22 @@ import ( "mime/multipart" "net/http" "path/filepath" + + "git.nix13.pw/scuroneko/slog" ) type Uploader struct { - bot *Bot + api *Api + logger *slog.Logger } -func NewUploader(bot *Bot) *Uploader { - return &Uploader{bot: bot} +func NewUploader(api *Api) *Uploader { + logger := slog.CreateLogger().Level(GetLoggerLevel()).Prefix("UPLOADER") + logger.AddWriter(logger.CreateJsonStdoutWriter()) + return &Uploader{api, logger} +} +func (u *Uploader) Close() { + u.logger.Close() } type UploaderFileType string @@ -56,8 +64,8 @@ func NewUploaderRequest[R, P any](method string, file UploaderFile, params P) Up return UploaderRequest[R, P]{method, file, params} } -func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) { - url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", bot.token, u.method) +func (u UploaderRequest[R, P]) Do(up *Uploader) (*R, error) { + url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", up.api.token, u.method) buf := bytes.NewBuffer(nil) w := multipart.NewWriter(buf) @@ -87,7 +95,7 @@ func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) { return nil, err } req.Header.Set("Content-Type", w.FormDataContentType()) - bot.logger.Debugln("UPLOADER REQ", u.method) + up.logger.Debugln("UPLOADER REQ", u.method) res, err := http.DefaultClient.Do(req) if err != nil { return nil, err @@ -98,7 +106,7 @@ func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) { if err != nil { return nil, err } - bot.logger.Debugln("UPLOADER RES", u.method, string(body)) + up.logger.Debugln("UPLOADER RES", u.method, string(body)) if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("[%d] %s", res.StatusCode, string(body)) } @@ -116,7 +124,7 @@ func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) { func (u *Uploader) UploadPhoto(file UploaderFile, params SendPhotoBaseP) (*Message, error) { req := NewUploaderRequest[Message]("sendPhoto", file, params) - return req.Do(u.bot) + return req.Do(u) } func uploaderTypeByExt(filename string) UploaderFileType { diff --git a/utils.go b/utils.go index 5bfad8d..5b0f372 100644 --- a/utils.go +++ b/utils.go @@ -3,9 +3,20 @@ package laniakea import ( "encoding/json" "fmt" + "os" "strings" + + "git.nix13.pw/scuroneko/slog" ) +func GetLoggerLevel() slog.LogLevel { + level := slog.FATAL + if os.Getenv("DEBUG") == "true" { + level = slog.DEBUG + } + return level +} + // MapToStruct unsafe function func MapToStruct(m map[string]any, s any) error { data, err := json.Marshal(m) diff --git a/version.go b/version.go index 2661f98..8d2c2b6 100644 --- a/version.go +++ b/version.go @@ -1,8 +1,8 @@ package laniakea const ( - VersionString = "0.3.9" + VersionString = "0.4.0" VersionMajor = 0 - VersionMinor = 3 - VersionPatch = 9 + VersionMinor = 4 + VersionPatch = 0 )