diff --git a/helpers_bot.go b/helpers_bot.go index c8ae183..302b11a 100644 --- a/helpers_bot.go +++ b/helpers_bot.go @@ -1,17 +1,35 @@ package telegram -import ( - "fmt" - "strings" -) +import "strings" func (bot *Bot) IsMessageFromMe(msg *Message) bool { + if msg == nil || + bot == nil { + return false + } + + if msg.From == nil || + bot.Self == nil { + return false + } + return msg.From.ID == bot.Self.ID } func (bot *Bot) IsForwardFromMe(msg *Message) bool { - return msg.IsForward() && - msg.ForwardFrom.ID == bot.Self.ID + if !msg.IsForward() { + return false + } + + if bot == nil { + return false + } + + if bot.Self == nil { + return false + } + + return msg.ForwardFrom.ID == bot.Self.ID } func (bot *Bot) IsReplyToMe(msg *Message) bool { @@ -19,36 +37,57 @@ func (bot *Bot) IsReplyToMe(msg *Message) bool { return true } - return msg.IsReply() && - bot.IsMessageFromMe(msg.ReplyToMessage) -} - -func (bot *Bot) IsCommandToMe(msg *Message) bool { - if msg.Chat.IsPrivate() { - return msg.IsCommand() - } - - return msg.IsCommand() && - strings.HasSuffix( - strings.ToLower(msg.Command()), - strings.ToLower(fmt.Sprint("@", bot.Self.Username)), - ) -} - -func (bot *Bot) IsMessageMentionsMe(msg *Message) bool { - if msg.Entities == nil || - len(msg.Entities) <= 0 { + if !msg.IsReply() { return false } - for _, entity := range msg.Entities { - if entity.Type != EntityMention || - entity.User == nil { - continue - } + return bot.IsMessageFromMe(msg.ReplyToMessage) +} - if entity.User.ID == bot.Self.ID { - return true +func (bot *Bot) IsCommandToMe(msg *Message) bool { + if !msg.IsCommand() { + return false + } + + if msg.Chat.IsPrivate() { + return true + } + + parts := strings.Split(msg.RawCommand(), "@") + if len(parts) <= 1 { + return false + } + + return strings.ToLower(parts[1]) == strings.ToLower(bot.Self.Username) +} + +func (bot *Bot) IsMessageMentionsMe(msg *Message) bool { + if msg == nil || + bot == nil { + return false + } + + if bot.Self == nil { + return false + } + + if bot.IsCommandToMe(msg) { + return true + } + + var entities []MessageEntity + switch { + case msg.HasMentions(): + entities = msg.Entities + case msg.HasCaptionMentions(): + entities = msg.CaptionEntities + } + + for _, entity := range entities { + if entity.IsMention() { + if bot.Self.ID == entity.User.ID { + return true + } } } @@ -66,13 +105,20 @@ func (bot *Bot) IsReplyMentionsMe(msg *Message) bool { } func (bot *Bot) IsMessageToMe(msg *Message) bool { - switch { - case msg.Chat.IsPrivate(), - bot.IsCommandToMe(msg), - bot.IsReplyToMe(msg), - bot.IsMessageMentionsMe(msg): - return true - default: + if msg == nil { return false } + + if msg.Chat == nil { + return false + } + + if msg.Chat.IsPrivate() || + bot.IsCommandToMe(msg) || + bot.IsReplyToMe(msg) || + bot.IsMessageMentionsMe(msg) { + return true + } + + return false } diff --git a/helpers_chat.go b/helpers_chat.go index 7a24982..4d556db 100644 --- a/helpers_chat.go +++ b/helpers_chat.go @@ -1,17 +1,37 @@ package telegram func (chat *Chat) IsPrivate() bool { + if chat == nil { + return false + } + return chat.Type == ChatPrivate } func (chat *Chat) IsGroup() bool { + if chat == nil { + return false + } + return chat.Type == ChatGroup } func (chat *Chat) IsSuperGroup() bool { + if chat == nil { + return false + } + return chat.Type == ChatSuperGroup } func (chat *Chat) IsChannel() bool { + if chat == nil { + return false + } + return chat.Type == ChatChannel } + +func (chat *Chat) HasPinnedMessage() bool { + return chat.PinnedMessage != nil +} diff --git a/helpers_entity.go b/helpers_entity.go index f0fbab1..bb05f73 100644 --- a/helpers_entity.go +++ b/helpers_entity.go @@ -3,9 +3,101 @@ package telegram import "net/url" func (entity *MessageEntity) ParseURL() (*url.URL, error) { - if entity.Type == EntityTextLink { + if entity != nil { + return nil, nil + } + + if entity.IsTextLink() { return url.Parse(entity.URL) } return nil, nil } + +func (entity *MessageEntity) IsBold() bool { + if entity != nil { + return false + } + + return entity.Type == EntityBold +} + +func (entity *MessageEntity) IsBotCommand() bool { + if entity != nil { + return false + } + + return entity.Type == EntityBotCommand +} + +func (entity *MessageEntity) IsCode() bool { + if entity != nil { + return false + } + + return entity.Type == EntityCode +} + +func (entity *MessageEntity) IsEmail() bool { + if entity != nil { + return false + } + + return entity.Type == EntityEmail +} + +func (entity *MessageEntity) IsHashTag() bool { + if entity != nil { + return false + } + + return entity.Type == EntityHashtag +} + +func (entity *MessageEntity) IsItalic() bool { + if entity != nil { + return false + } + + return entity.Type == EntityItalic +} + +func (entity *MessageEntity) IsMention() bool { + if entity != nil { + return false + } + + return entity.Type == EntityMention +} + +func (entity *MessageEntity) IsPre() bool { + if entity != nil { + return false + } + + return entity.Type == EntityPre +} + +func (entity *MessageEntity) IsTextLink() bool { + if entity != nil { + return false + } + + return entity.Type == EntityTextLink +} + +func (entity *MessageEntity) IsTextMention() bool { + if entity != nil { + return false + } + + return entity.Type == EntityTextMention +} + +func (entity *MessageEntity) IsURL() bool { + if entity != nil { + return false + } + + return entity.Type == EntityURL +} diff --git a/helpers_inline_query_result.go b/helpers_inline_query_result.go index 5be45b6..067e710 100644 --- a/helpers_inline_query_result.go +++ b/helpers_inline_query_result.go @@ -1,8 +1,6 @@ package telegram -func NewInlineQueryResultCachedAudio( - resultID, fileID string, -) *InlineQueryResultCachedAudio { +func NewInlineQueryResultCachedAudio(resultID, fileID string) *InlineQueryResultCachedAudio { return &InlineQueryResultCachedAudio{ Type: TypeAudio, ID: resultID, @@ -10,9 +8,7 @@ func NewInlineQueryResultCachedAudio( } } -func NewInlineQueryResultCachedDocument( - resultID, fileID, title string, -) *InlineQueryResultCachedDocument { +func NewInlineQueryResultCachedDocument(resultID, fileID, title string) *InlineQueryResultCachedDocument { return &InlineQueryResultCachedDocument{ Type: TypeDocument, ID: resultID, @@ -21,9 +17,7 @@ func NewInlineQueryResultCachedDocument( } } -func NewInlineQueryResultCachedGif( - resultID, fileID string, -) *InlineQueryResultCachedGif { +func NewInlineQueryResultCachedGif(resultID, fileID string) *InlineQueryResultCachedGif { return &InlineQueryResultCachedGif{ Type: TypeGIF, ID: resultID, @@ -31,9 +25,7 @@ func NewInlineQueryResultCachedGif( } } -func NewInlineQueryResultCachedMpeg4Gif( - resultID, fileID string, -) *InlineQueryResultCachedMpeg4Gif { +func NewInlineQueryResultCachedMpeg4Gif(resultID, fileID string) *InlineQueryResultCachedMpeg4Gif { return &InlineQueryResultCachedMpeg4Gif{ Type: TypeMpeg4Gif, ID: resultID, @@ -41,9 +33,7 @@ func NewInlineQueryResultCachedMpeg4Gif( } } -func NewInlineQueryResultCachedPhoto( - resultID, fileID string, -) *InlineQueryResultCachedPhoto { +func NewInlineQueryResultCachedPhoto(resultID, fileID string) *InlineQueryResultCachedPhoto { return &InlineQueryResultCachedPhoto{ Type: TypePhoto, ID: resultID, @@ -51,9 +41,7 @@ func NewInlineQueryResultCachedPhoto( } } -func NewInlineQueryResultCachedSticker( - resultID, fileID string, -) *InlineQueryResultCachedSticker { +func NewInlineQueryResultCachedSticker(resultID, fileID string) *InlineQueryResultCachedSticker { return &InlineQueryResultCachedSticker{ Type: TypeSticker, ID: resultID, @@ -61,9 +49,7 @@ func NewInlineQueryResultCachedSticker( } } -func NewInlineQueryResultCachedVideo( - resultID, fileID, title string, -) *InlineQueryResultCachedVideo { +func NewInlineQueryResultCachedVideo(resultID, fileID, title string) *InlineQueryResultCachedVideo { return &InlineQueryResultCachedVideo{ Type: TypeVideo, ID: resultID, @@ -72,9 +58,7 @@ func NewInlineQueryResultCachedVideo( } } -func NewInlineQueryResultCachedVoice( - resultID, fileID, title string, -) *InlineQueryResultCachedVoice { +func NewInlineQueryResultCachedVoice(resultID, fileID, title string) *InlineQueryResultCachedVoice { return &InlineQueryResultCachedVoice{ Type: TypeVoice, ID: resultID, @@ -83,10 +67,7 @@ func NewInlineQueryResultCachedVoice( } } -func NewInlineQueryResultArticle( - resultID, title string, - content *InputMessageContent, -) *InlineQueryResultArticle { +func NewInlineQueryResultArticle(resultID, title string, content *InputMessageContent) *InlineQueryResultArticle { return &InlineQueryResultArticle{ Type: TypeArticle, ID: resultID, @@ -95,9 +76,7 @@ func NewInlineQueryResultArticle( } } -func NewInlineQueryResultAudio( - resultID, audioURL, title string, -) *InlineQueryResultAudio { +func NewInlineQueryResultAudio(resultID, audioURL, title string) *InlineQueryResultAudio { return &InlineQueryResultAudio{ Type: TypeAudio, ID: resultID, @@ -106,9 +85,7 @@ func NewInlineQueryResultAudio( } } -func NewInlineQueryResultContact( - resultID, phoneNumber, firstName string, -) *InlineQueryResultContact { +func NewInlineQueryResultContact(resultID, phoneNumber, firstName string) *InlineQueryResultContact { return &InlineQueryResultContact{ Type: TypeContact, ID: resultID, @@ -117,9 +94,7 @@ func NewInlineQueryResultContact( } } -func NewInlineQueryResultGame( - resultID, gameShortName string, -) *InlineQueryResultGame { +func NewInlineQueryResultGame(resultID, gameShortName string) *InlineQueryResultGame { return &InlineQueryResultGame{ Type: TypeGame, ID: resultID, @@ -127,9 +102,7 @@ func NewInlineQueryResultGame( } } -func NewInlineQueryResultDocument( - resultID, title, documentURL, mimeType string, -) *InlineQueryResultDocument { +func NewInlineQueryResultDocument(resultID, title, documentURL, mimeType string) *InlineQueryResultDocument { return &InlineQueryResultDocument{ Type: TypeDocument, ID: resultID, @@ -139,9 +112,7 @@ func NewInlineQueryResultDocument( } } -func NewInlineQueryResultGif( - resultID, gifURL, thumbURL string, -) *InlineQueryResultGif { +func NewInlineQueryResultGif(resultID, gifURL, thumbURL string) *InlineQueryResultGif { return &InlineQueryResultGif{ Type: TypeGIF, ID: resultID, @@ -150,10 +121,7 @@ func NewInlineQueryResultGif( } } -func NewInlineQueryResultLocation( - resultID, title string, - latitude, longitude float32, -) *InlineQueryResultLocation { +func NewInlineQueryResultLocation(resultID, title string, latitude, longitude float32) *InlineQueryResultLocation { return &InlineQueryResultLocation{ Type: TypeLocation, ID: resultID, @@ -163,9 +131,7 @@ func NewInlineQueryResultLocation( } } -func NewInlineQueryResultMpeg4Gif( - resultID, mpeg4URL, thumbURL string, -) *InlineQueryResultMpeg4Gif { +func NewInlineQueryResultMpeg4Gif(resultID, mpeg4URL, thumbURL string) *InlineQueryResultMpeg4Gif { return &InlineQueryResultMpeg4Gif{ Type: TypeMpeg4Gif, ID: resultID, @@ -174,9 +140,7 @@ func NewInlineQueryResultMpeg4Gif( } } -func NewInlineQueryResultPhoto( - resultID, photoURL, thumbURL string, -) *InlineQueryResultPhoto { +func NewInlineQueryResultPhoto(resultID, photoURL, thumbURL string) *InlineQueryResultPhoto { return &InlineQueryResultPhoto{ Type: TypePhoto, ID: resultID, @@ -185,10 +149,7 @@ func NewInlineQueryResultPhoto( } } -func NewInlineQueryResultVenue( - resultID, title, address string, - latitude, longitude float32, -) *InlineQueryResultVenue { +func NewInlineQueryResultVenue(resultID, title, address string, latitude, longitude float32) *InlineQueryResultVenue { return &InlineQueryResultVenue{ Type: TypeVenue, ID: resultID, @@ -199,9 +160,7 @@ func NewInlineQueryResultVenue( } } -func NewInlineQueryResultVideo( - resultID, videoURL, mimeType, thumbURL, title string, -) *InlineQueryResultVideo { +func NewInlineQueryResultVideo(resultID, videoURL, mimeType, thumbURL, title string) *InlineQueryResultVideo { return &InlineQueryResultVideo{ Type: TypeVideo, ID: resultID, @@ -212,9 +171,7 @@ func NewInlineQueryResultVideo( } } -func NewInlineQueryResultVoice( - resultID, voiceURL, title string, -) *InlineQueryResultVoice { +func NewInlineQueryResultVoice(resultID, voiceURL, title string) *InlineQueryResultVoice { return &InlineQueryResultVoice{ Type: TypeVoice, ID: resultID, diff --git a/helpers_member.go b/helpers_member.go new file mode 100644 index 0000000..dae9dd8 --- /dev/null +++ b/helpers_member.go @@ -0,0 +1,59 @@ +package telegram + +import "time" + +func (member *ChatMember) IsCreator() bool { + if member == nil { + return false + } + + return member.Status == StatusCreator +} + +func (member *ChatMember) IsAdministrator() bool { + if member == nil { + return false + } + + return member.Status == StatusAdministrator +} + +func (member *ChatMember) IsMember() bool { + if member == nil { + return false + } + + return member.Status == StatusMember +} + +func (member *ChatMember) IsRestricted() bool { + if member == nil { + return false + } + + return member.Status == StatusRestricted +} + +func (member *ChatMember) IsLeft() bool { + if member == nil { + return false + } + + return member.Status == StatusLeft +} + +func (member *ChatMember) IsKicked() bool { + if member == nil { + return false + } + + return member.Status == StatusKicked +} + +func (member *ChatMember) UntilTime() time.Time { + if member == nil { + return time.Time{} + } + + return time.Unix(member.UntilDate, 0) +} diff --git a/helpers_message.go b/helpers_message.go index 8c7e441..a7dd042 100644 --- a/helpers_message.go +++ b/helpers_message.go @@ -1,15 +1,21 @@ package telegram -import "time" +import ( + "strings" + "time" +) func (msg *Message) IsCommand() bool { - if msg.Entities == nil || - len(msg.Entities) <= 0 { + if !msg.IsText() { return false } - return msg.Entities[0].Offset == 0 && - msg.Entities[0].Type == EntityBotCommand + if !msg.HasEntities() { + return false + } + + entity := msg.Entities[0] + return entity.IsBotCommand() && entity.Offset == 0 } func (msg *Message) Command() string { @@ -17,37 +23,205 @@ func (msg *Message) Command() string { return "" } + return strings.Split(msg.RawCommand(), "@")[0] +} + +func (msg *Message) RawCommand() string { + if !msg.IsCommand() { + return "" + } + return string([]rune(msg.Text)[1:msg.Entities[0].Length]) } -func (msg *Message) HasArgument() bool { - switch { - case msg.IsCommand(), - len(msg.CommandArgument()) > 0: - return true - default: +func (msg *Message) HasCommandArgument() bool { + if !msg.IsCommand() { return false } + + entity := msg.Entities[0] + if !entity.IsBotCommand() { + return false + } + + return len([]rune(msg.Text)) != entity.Length } func (msg *Message) CommandArgument() string { - switch { - case !msg.IsCommand(), - len([]rune(msg.Text)) == msg.Entities[0].Length: + if !msg.HasCommandArgument() { return "" - default: - return string([]rune(msg.Text)[msg.Entities[0].Length+1:]) } + + return string([]rune(msg.Text)[msg.Entities[0].Length+1:]) } func (msg *Message) IsReply() bool { + if msg == nil { + return false + } + return msg.ReplyToMessage != nil } func (msg *Message) IsForward() bool { + if msg == nil { + return false + } + return msg.ForwardFrom != nil } func (msg *Message) Time() time.Time { + if msg == nil { + return time.Time{} + } + return time.Unix(msg.Date, 0) } + +func (msg *Message) ForwardTime() time.Time { + if msg == nil { + return time.Time{} + } + + return time.Unix(msg.ForwardDate, 0) +} + +func (msg *Message) EditTime() time.Time { + if msg == nil { + return time.Time{} + } + + return time.Unix(msg.EditDate, 0) +} + +func (msg *Message) IsText() bool { + if msg == nil { + return false + } + + return msg.Text != "" +} + +func (msg *Message) IsAudio() bool { + return !msg.IsText() && msg.Audio != nil +} + +func (msg *Message) IsDocument() bool { + return !msg.IsText() && msg.Document != nil +} + +func (msg *Message) IsGame() bool { + return !msg.IsText() && msg.Game != nil +} + +func (msg *Message) IsPhoto() bool { + return !msg.IsText() && len(msg.Photo) > 0 +} + +func (msg *Message) IsSticker() bool { + return !msg.IsText() && msg.Sticker != nil +} + +func (msg *Message) IsVideo() bool { + return !msg.IsText() && msg.Video != nil +} +func (msg *Message) IsVoice() bool { + return !msg.IsText() && msg.Voice != nil +} + +func (msg *Message) IsVideoNote() bool { + return !msg.IsText() && msg.VideoNote != nil +} + +func (msg *Message) IsContact() bool { + return !msg.IsText() && msg.Contact != nil +} + +func (msg *Message) IsLocation() bool { + return !msg.IsText() && msg.Location != nil +} + +func (msg *Message) IsVenue() bool { + return !msg.IsText() && msg.Venue != nil +} + +func (msg *Message) IsNewChatMembersEvent() bool { + return !msg.IsText() && len(msg.NewChatMembers) > 0 +} + +func (msg *Message) IsLeftChatMemberEvent() bool { + return !msg.IsText() && msg.LeftChatMember != nil +} + +func (msg *Message) IsNewChatTitleEvent() bool { + return !msg.IsText() && msg.NewChatTitle != "" +} + +func (msg *Message) IsNewChatPhotoEvent() bool { + return !msg.IsText() && len(msg.NewChatPhoto) > 0 +} + +func (msg *Message) IsDeleteChatPhotoEvent() bool { + return !msg.IsText() && msg.DeleteChatPhoto +} + +func (msg *Message) IsGroupChatCreatedEvent() bool { + return !msg.IsText() && msg.GroupChatCreated +} + +func (msg *Message) IsSupergroupChatCreatedEvent() bool { + return !msg.IsText() && msg.SupergroupChatCreated +} + +func (msg *Message) IsChannelChatCreatedEvent() bool { + return !msg.IsText() && msg.ChannelChatCreated +} + +func (msg *Message) IsPinnedMessage() bool { + return !msg.IsText() && msg.PinnedMessage != nil +} + +func (msg *Message) IsInvoice() bool { + return !msg.IsText() && msg.Invoice != nil +} + +func (msg *Message) IsSuccessfulPayment() bool { + return !msg.IsText() && msg.SuccessfulPayment != nil +} + +func (msg *Message) HasEntities() bool { + return msg.IsText() && len(msg.Entities) > 0 +} + +func (msg *Message) HasCaptionEntities() bool { + return !msg.IsText() && len(msg.CaptionEntities) > 0 +} + +func (msg *Message) HasMentions() bool { + if !msg.HasEntities() { + return false + } + + for _, entity := range msg.Entities { + if entity.IsMention() || entity.IsTextMention() { + return true + } + } + + return false +} + +func (msg *Message) HasCaptionMentions() bool { + if !msg.HasCaptionEntities() { + return false + } + + for _, entity := range msg.CaptionEntities { + if entity.IsMention() || entity.IsTextMention() { + return true + } + } + + return false +} diff --git a/helpers_update.go b/helpers_update.go new file mode 100644 index 0000000..a236a0c --- /dev/null +++ b/helpers_update.go @@ -0,0 +1,129 @@ +package telegram + +import ( + "bytes" + "log" + "time" + + "github.com/kirillDanshin/dlog" + json "github.com/pquerna/ffjson/ffjson" + http "github.com/valyala/fasthttp" +) + +type UpdatesChannel <-chan Update + +func (bot *Bot) NewLongPollingChannel(params *GetUpdatesParameters) UpdatesChannel { + if params == nil { + params = &GetUpdatesParameters{ + Offset: 0, + Limit: 100, + Timeout: 60, + } + } + + channel := make(chan Update, params.Limit) + go func() { + for { + updates, err := bot.GetUpdates(params) + if err != nil { + dlog.Ln(err.Error()) + dlog.Ln("Failed to get updates, retrying in 3 seconds...") + time.Sleep(time.Second * 3) + continue + } + + for _, update := range updates { + if update.ID >= params.Offset { + params.Offset = update.ID + 1 + channel <- update + } + } + } + }() + + return channel +} + +func (bot *Bot) NewWebhookChannel(params *SetWebhookParameters, certFile, keyFile, set, listen, serve string) (updates UpdatesChannel) { + if params == nil { + params = &SetWebhookParameters{ + URL: set, + MaxConnections: 40, + } + } + + var err error + channel := make(chan Update, 100) + requiredPath := []byte(listen) + dlog.Ln("requiredPath:", string(requiredPath)) + handleFunc := func(ctx *http.RequestCtx) { + dlog.Ln("Request path:", string(ctx.Path())) + if !bytes.HasPrefix(ctx.Path(), requiredPath) { + dlog.Ln("Unsupported request path:", string(ctx.Path())) + return + } + dlog.Ln("Catched supported request path:", string(ctx.Path())) + + var update Update + if err = json.Unmarshal(ctx.Request.Body(), &update); err != nil { + return + } + + channel <- update + } + + go func() { + if certFile != "" && keyFile != "" { + dlog.Ln("Creating TLS router...") + err = http.ListenAndServeTLS(serve, certFile, keyFile, handleFunc) + } else { + dlog.Ln("Creating simple router...") + err = http.ListenAndServe(serve, handleFunc) + } + if err != nil { + log.Fatalln(err.Error()) + } + }() + + if _, err = bot.SetWebhook(params); err != nil { + log.Fatalln(err.Error()) + } + + return channel +} + +func (upd *Update) IsMessage() bool { + return upd.Message != nil +} + +func (upd *Update) IsEditedMessage() bool { + return upd.EditedMessage != nil +} + +func (upd *Update) IsChannelPost() bool { + return upd.ChannelPost != nil +} + +func (upd *Update) IsEditedChannelPost() bool { + return upd.EditedChannelPost != nil +} + +func (upd *Update) IsInlineQuery() bool { + return upd.InlineQuery != nil +} + +func (upd *Update) IsChosenInlineResult() bool { + return upd.ChosenInlineResult != nil +} + +func (upd *Update) IsCallbackQuery() bool { + return upd.CallbackQuery != nil +} + +func (upd *Update) IsShippingQuery() bool { + return upd.ShippingQuery != nil +} + +func (upd *Update) IsPreCheckoutQuery() bool { + return upd.PreCheckoutQuery != nil +} diff --git a/helpers_updates.go b/helpers_updates.go deleted file mode 100644 index 0177ee1..0000000 --- a/helpers_updates.go +++ /dev/null @@ -1,92 +0,0 @@ -package telegram - -import ( - "bytes" - "log" - "time" - - "github.com/kirillDanshin/dlog" - json "github.com/pquerna/ffjson/ffjson" - http "github.com/valyala/fasthttp" -) - -type UpdatesChannel <-chan Update - -func (bot *Bot) NewLongPollingChannel(params *GetUpdatesParameters) UpdatesChannel { - if params == nil { - params = &GetUpdatesParameters{ - Offset: 0, - Limit: 100, - Timeout: 60, - } - } - - channel := make(chan Update, params.Limit) - go func() { - for { - updates, err := bot.GetUpdates(params) - if err != nil { - dlog.Ln(err.Error()) - dlog.Ln("Failed to get updates, retrying in 3 seconds...") - time.Sleep(time.Second * 3) - continue - } - - for _, update := range updates { - if update.ID >= params.Offset { - params.Offset = update.ID + 1 - channel <- update - } - } - } - }() - - return channel -} - -func (bot *Bot) NewWebhookChannel( - params *SetWebhookParameters, - certFile, keyFile, set, listen, serve string, -) (updates UpdatesChannel) { - if params == nil { - params = &SetWebhookParameters{ - URL: set, - MaxConnections: 40, - } - } - - channel := make(chan Update, 100) - go func() { - requiredPath := []byte(listen) - dlog.Ln("requiredPath:", string(requiredPath)) - handleFunc := func(ctx *http.RequestCtx) { - dlog.Ln("Request path:", string(ctx.Path())) - if !bytes.HasPrefix(ctx.Path(), requiredPath) { - dlog.Ln("Unsupported request path:", string(ctx.Path())) - return - } - dlog.Ln("Catched supported request path:", string(ctx.Path())) - - var update Update - if err := json.Unmarshal(ctx.Request.Body(), &update); err != nil { - return - } - - channel <- update - } - - if certFile != "" && keyFile != "" { - dlog.Ln("Creating TLS router...") - log.Fatal(http.ListenAndServeTLS(serve, certFile, keyFile, handleFunc)) - } else { - dlog.Ln("Creating simple router...") - log.Fatal(http.ListenAndServe(serve, handleFunc)) - } - }() - - if _, err := bot.SetWebhook(params); err != nil { - log.Fatalln(err.Error()) - } - - return channel -} diff --git a/helpers_user.go b/helpers_user.go new file mode 100644 index 0000000..60cc8cb --- /dev/null +++ b/helpers_user.go @@ -0,0 +1,32 @@ +package telegram + +import ( + "fmt" + + "golang.org/x/text/language" +) + +func (user *User) Language() *language.Tag { + if user == nil { + return nil + } + + tag, err := language.Parse(user.LanguageCode) + if err != nil { + return nil + } + + return &tag +} + +func (user *User) FullName() string { + if user == nil { + return "" + } + + if user.LastName != "" { + return fmt.Sprint(user.FirstName, " ", user.LastName) + } + + return user.FirstName +}