Compare commits
23 Commits
af8982be2d
...
master
Author | SHA1 | Date | |
---|---|---|---|
a49827afc2 | |||
9e122d1a12 | |||
57d11c7671 | |||
b04a779236 | |||
9298c6402b | |||
01d04199fd | |||
f4346d8859 | |||
dd0307e382 | |||
b7f1e3e9ed | |||
c6ce1913dc | |||
1377e03b5e | |||
c0143707e9 | |||
d035524ebc | |||
e396d6a885 | |||
906c769453 | |||
d797a52029 | |||
599584ea58 | |||
b074189d31 | |||
e2ba9565d5 | |||
677f28182a | |||
3a06ae5f0e | |||
1a8decf4d4 | |||
5842815c95 |
31
bot.go
31
bot.go
@ -2,6 +2,7 @@ package nechotron
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
echo "github.com/NicoNex/echotron/v3"
|
echo "github.com/NicoNex/echotron/v3"
|
||||||
@ -9,10 +10,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type bot struct {
|
type bot struct {
|
||||||
chatID int64
|
|
||||||
me *echo.User
|
|
||||||
echo.API
|
echo.API
|
||||||
state *State
|
chatID int64
|
||||||
|
Me *echo.User
|
||||||
|
data StateData
|
||||||
|
lock sync.Mutex
|
||||||
|
State Runnable
|
||||||
|
handler UpdateHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultHandler(u *Update) error {
|
||||||
|
err := u.Bot.State.Call(u)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bot) Update(u *echo.Update) {
|
func (b *bot) Update(u *echo.Update) {
|
||||||
@ -25,11 +34,13 @@ func (b *bot) Update(u *echo.Update) {
|
|||||||
Ctx: ctx,
|
Ctx: ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
newState, err := b.state.Fn(upd)
|
b.lock.Lock()
|
||||||
if err != nil {
|
defer b.lock.Unlock()
|
||||||
upd.LogError("", err, true)
|
// defer func() {
|
||||||
}
|
// if r := recover(); r != nil {
|
||||||
if newState != nil {
|
// log.Printf("[%s] Recovered. Error: %s\n", upd.UpdateID.String(), r)
|
||||||
b.state = newState
|
// }
|
||||||
}
|
// }()
|
||||||
|
|
||||||
|
b.handler(upd)
|
||||||
}
|
}
|
||||||
|
25
callbacks.go
Normal file
25
callbacks.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package nechotron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CallbackFilter func(u *Update) bool
|
||||||
|
|
||||||
|
func CallbackExact(text string) CallbackFilter {
|
||||||
|
return func(u *Update) bool {
|
||||||
|
data := u.Callback()
|
||||||
|
return text == data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CallbackPrefix(text string) CallbackFilter {
|
||||||
|
return func(u *Update) bool {
|
||||||
|
data := u.Callback()
|
||||||
|
if strings.HasPrefix(data, text) {
|
||||||
|
u.Ctx = context.WithValue(u.Ctx, FilteredValue("cb_"+text), strings.TrimPrefix(data, text+":"))
|
||||||
|
}
|
||||||
|
return strings.HasPrefix(data, text)
|
||||||
|
}
|
||||||
|
}
|
61
command.go
Normal file
61
command.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package nechotron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/NicoNex/echotron/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
Body string
|
||||||
|
IsAdminOnly bool
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCommand(body string, desc string, isAdminOnly bool) *Command {
|
||||||
|
return &Command{
|
||||||
|
Body: body,
|
||||||
|
IsAdminOnly: isAdminOnly,
|
||||||
|
Description: desc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (c *Command) String() string {
|
||||||
|
return "/" + c.Body
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) Param(text string) string {
|
||||||
|
strs := strings.SplitN(text, " ", 2)
|
||||||
|
if len(strs) > 1 {
|
||||||
|
return strs[1]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeCommandList(format string, commands ...*Command) string {
|
||||||
|
result := ""
|
||||||
|
for _, command := range commands {
|
||||||
|
result += fmt.Sprintf(format, command.String(), EscapeMd2(command.Description))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func botCommands(commands ...*Command) []echotron.BotCommand {
|
||||||
|
cmds := []echotron.BotCommand{}
|
||||||
|
for _, c := range commands {
|
||||||
|
cmds = append(cmds, echotron.BotCommand{Command: c.Body, Description: c.Description})
|
||||||
|
}
|
||||||
|
return cmds
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetMyCommands(api echotron.API, langCode string, scope echotron.BotCommandScope, commands ...*Command) error {
|
||||||
|
_, err := api.SetMyCommands(&echotron.CommandOptions{LanguageCode: "", Scope: scope}, botCommands(commands...)...)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// func HandleCommand(command *Command, handler cmdFunc) (bool, error)
|
104
dispatcher.go
Normal file
104
dispatcher.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package nechotron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/NicoNex/echotron/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateHandler func(u *Update) error
|
||||||
|
type CommandHandler func(u *Update, arg string) error
|
||||||
|
type CallbackHandler func(u *Update, data string) error
|
||||||
|
|
||||||
|
type dispatchHandler func(u *Update) (bool, error)
|
||||||
|
|
||||||
|
type Dispatcher struct {
|
||||||
|
handlers []dispatchHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDispatcher() *Dispatcher {
|
||||||
|
return &Dispatcher{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dispatcher) Run(u *Update) error {
|
||||||
|
for _, h := range d.handlers {
|
||||||
|
executed, err := h(u)
|
||||||
|
if executed {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dispatcher) Handle(handler func(u *Update) (bool, error)) *Dispatcher {
|
||||||
|
d.handlers = append(d.handlers, handler)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dispatcher) HandleCommand(command *Command, handler CommandHandler) *Dispatcher {
|
||||||
|
newHandler := func(u *Update) (bool, error) {
|
||||||
|
if !strings.HasPrefix(u.Text(), command.String()) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if command.IsAdminOnly && !IsUserAdmin(u) && u.ChatID() < 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
err := handler(u, command.Param(u.Text()))
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
d.handlers = append(d.handlers, newHandler)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dispatcher) HandleFilter(filter FilterFn, handler UpdateHandler) *Dispatcher {
|
||||||
|
newHandler := func(u *Update) (bool, error) {
|
||||||
|
if !filter(u) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
err := handler(u)
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
d.handlers = append(d.handlers, newHandler)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dispatcher) HandleCallback(filter CallbackFilter, handler UpdateHandler) *Dispatcher {
|
||||||
|
newHandler := func(u *Update) (bool, error) {
|
||||||
|
if !u.IsCallback() {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
defer u.Bot.AnswerCallbackQuery(u.CallbackQuery.ID, &echotron.CallbackQueryOptions{})
|
||||||
|
if !filter(u) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
err := handler(u)
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
d.handlers = append(d.handlers, newHandler)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dispatcher) HandleReply(handler UpdateHandler) *Dispatcher {
|
||||||
|
newHandler := func(u *Update) (bool, error) {
|
||||||
|
if !u.IsMessage() {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if u.Message.ReplyToMessage == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
err := handler(u)
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
d.handlers = append(d.handlers, newHandler)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs each dispatcher or handled listed here until error is returned from any
|
||||||
|
func RunEach(u *Update, disps ...*Dispatcher) error {
|
||||||
|
for _, d := range disps {
|
||||||
|
if err := d.Run(u); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
71
filters.go
Normal file
71
filters.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package nechotron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FilterFn func(u *Update) bool
|
||||||
|
type FilteredValue interface{}
|
||||||
|
|
||||||
|
func TextStartsWith(text string) FilterFn {
|
||||||
|
return func(u *Update) bool {
|
||||||
|
return strings.HasPrefix(u.Text(), text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TextStartsWithAny(subs ...string) FilterFn {
|
||||||
|
return func(u *Update) bool {
|
||||||
|
text := u.Text()
|
||||||
|
for _, sub := range subs {
|
||||||
|
if strings.HasPrefix(text, sub) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TextHas(text string) FilterFn {
|
||||||
|
return func(u *Update) bool {
|
||||||
|
return strings.Contains(u.Text(), text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TextHasAny(subs ...string) FilterFn {
|
||||||
|
return func(u *Update) bool {
|
||||||
|
text := u.Text()
|
||||||
|
for _, sub := range subs {
|
||||||
|
if strings.Contains(text, sub) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsPrivate(u *Update) bool {
|
||||||
|
return u.ChatID() > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsForum(u *Update) bool {
|
||||||
|
return u.Chat().IsForum
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsReply(u *Update) bool {
|
||||||
|
return u.IsReply()
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsCallback(u *Update) bool {
|
||||||
|
return u.IsCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsUserAdmin(u *Update) bool {
|
||||||
|
if IsPrivate(u) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
member, err := u.Bot.GetChatMember(u.ChatID(), u.From().ID)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return member.Result.Status == "administrator" || member.Result.Status == "creator"
|
||||||
|
}
|
8
go.mod
Normal file
8
go.mod
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module git.nefrace.ru/nefrace/nechotron
|
||||||
|
|
||||||
|
go 1.21
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/NicoNex/echotron/v3 v3.27.0
|
||||||
|
github.com/google/uuid v1.4.0
|
||||||
|
)
|
8
go.sum
Normal file
8
go.sum
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
github.com/NicoNex/echotron/v3 v3.26.0 h1:kNO9AD0CNXAlbd96Z4jT8NHcn2OPD3wTXs6HnjXHXU0=
|
||||||
|
github.com/NicoNex/echotron/v3 v3.26.0/go.mod h1:LpP5IyHw0y+DZUZMBgXEDAF9O8feXrQu7w7nlJzzoZI=
|
||||||
|
github.com/NicoNex/echotron/v3 v3.27.0 h1:iq4BLPO+Dz1JHjh2HPk0D0NldAZSYcAjaOicgYEhUzw=
|
||||||
|
github.com/NicoNex/echotron/v3 v3.27.0/go.mod h1:LpP5IyHw0y+DZUZMBgXEDAF9O8feXrQu7w7nlJzzoZI=
|
||||||
|
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||||
|
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||||
|
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
@ -6,6 +6,10 @@ type InKeyboard struct {
|
|||||||
Buttons [][]echotron.InlineKeyboardButton
|
Buttons [][]echotron.InlineKeyboardButton
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewInlineKeyboard() *InKeyboard {
|
||||||
|
return &InKeyboard{}
|
||||||
|
}
|
||||||
|
|
||||||
func (i *InKeyboard) Row(buttons ...echotron.InlineKeyboardButton) *InKeyboard {
|
func (i *InKeyboard) Row(buttons ...echotron.InlineKeyboardButton) *InKeyboard {
|
||||||
i.Buttons = append(i.Buttons, buttons)
|
i.Buttons = append(i.Buttons, buttons)
|
||||||
return i
|
return i
|
||||||
|
21
markdown.go
Normal file
21
markdown.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package nechotron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/NicoNex/echotron/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var chars = []string{"_", "\\*", "\\[", "\\]", "\\(", "\\)", "~", "`", ">", "#", "\\+", "\\-", "=", "|", "{", "}", "\\.", "!"}
|
||||||
|
var r = strings.Join(chars, "")
|
||||||
|
var reg = regexp.MustCompile("[" + r + "]+")
|
||||||
|
|
||||||
|
func EscapeMd2(s string) string {
|
||||||
|
return reg.ReplaceAllString(s, "\\$0")
|
||||||
|
}
|
||||||
|
|
||||||
|
func UserMention(u *echotron.User) string {
|
||||||
|
return fmt.Sprintf("[%s](tg://user?id=%d)", EscapeMd2(u.FirstName), u.ID)
|
||||||
|
}
|
3
middleware.go
Normal file
3
middleware.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package nechotron
|
||||||
|
|
||||||
|
type Middleware func(next UpdateHandler) UpdateHandler
|
23
nechotron.go
23
nechotron.go
@ -8,7 +8,9 @@ import (
|
|||||||
|
|
||||||
type Nechotron struct {
|
type Nechotron struct {
|
||||||
Token string
|
Token string
|
||||||
DefaultState *State
|
DefaultState Runnable
|
||||||
|
ApiServer string
|
||||||
|
Handler UpdateHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTron(token string, defaultState *State) *Nechotron {
|
func NewTron(token string, defaultState *State) *Nechotron {
|
||||||
@ -19,20 +21,24 @@ func NewTron(token string, defaultState *State) *Nechotron {
|
|||||||
return &Nechotron{
|
return &Nechotron{
|
||||||
Token: token,
|
Token: token,
|
||||||
DefaultState: state,
|
DefaultState: state,
|
||||||
|
Handler: DefaultHandler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Nechotron) newBot(chatID int64) echo.Bot {
|
func (n *Nechotron) newBot(chatID int64) echo.Bot {
|
||||||
a := echo.NewAPI(n.Token)
|
a := echo.NewAPI(n.Token)
|
||||||
|
// a := echo.NewAPI(n.Token)
|
||||||
me, _ := a.GetMe()
|
me, _ := a.GetMe()
|
||||||
// log.Println("New bot active: ", chatID, me.Result)
|
// log.Println("New bot active: ", chatID, me.Result)
|
||||||
b := &bot{
|
b := &bot{
|
||||||
chatID: chatID,
|
chatID: chatID,
|
||||||
me: me.Result,
|
Me: me.Result,
|
||||||
API: a,
|
API: a,
|
||||||
state: n.DefaultState,
|
State: n.DefaultState,
|
||||||
|
data: make(StateData),
|
||||||
|
handler: n.Handler,
|
||||||
}
|
}
|
||||||
b.state = n.DefaultState
|
b.State = n.DefaultState
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,3 +47,8 @@ func (n *Nechotron) DispatchPoll() error {
|
|||||||
log.Println("Nechotron poll dispatcher started")
|
log.Println("Nechotron poll dispatcher started")
|
||||||
return dispatcher.Poll()
|
return dispatcher.Poll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Nechotron) Use(mid Middleware) *Nechotron {
|
||||||
|
n.Handler = mid(n.Handler)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
130
options.go
Normal file
130
options.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package nechotron
|
||||||
|
|
||||||
|
import "github.com/NicoNex/echotron/v3"
|
||||||
|
|
||||||
|
type OptionsBuilder struct {
|
||||||
|
caption string
|
||||||
|
replyMarkup echotron.ReplyMarkup
|
||||||
|
parseMode echotron.ParseMode
|
||||||
|
entities []echotron.MessageEntity
|
||||||
|
messageThreadID int64
|
||||||
|
replyToMessageID int
|
||||||
|
disableWebPagePreview bool
|
||||||
|
disableNotification bool
|
||||||
|
protectContent bool
|
||||||
|
allowSendingWithoutReply bool
|
||||||
|
hasSpoiler bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOptions() *OptionsBuilder {
|
||||||
|
return &OptionsBuilder{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) Caption(text string) *OptionsBuilder {
|
||||||
|
o.caption = text
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) ReplyMarkup(markup echotron.ReplyMarkup) *OptionsBuilder {
|
||||||
|
o.replyMarkup = markup
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) MarkdownV2() *OptionsBuilder {
|
||||||
|
o.parseMode = echotron.MarkdownV2
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) Spoiler() *OptionsBuilder {
|
||||||
|
o.hasSpoiler = true
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) Entities(entities []echotron.MessageEntity) *OptionsBuilder {
|
||||||
|
o.entities = entities
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) Thread(id int64) *OptionsBuilder {
|
||||||
|
o.messageThreadID = id
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) ReplyTo(id int) *OptionsBuilder {
|
||||||
|
o.replyToMessageID = id
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) DisableNotification() *OptionsBuilder {
|
||||||
|
o.disableNotification = true
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) ProtectContent() *OptionsBuilder {
|
||||||
|
o.protectContent = true
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) DisableWebPagePreview() *OptionsBuilder {
|
||||||
|
o.disableWebPagePreview = true
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) AllowSendingWithoutReply() *OptionsBuilder {
|
||||||
|
o.allowSendingWithoutReply = true
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) MessageOptions() *echotron.MessageOptions {
|
||||||
|
return &echotron.MessageOptions{
|
||||||
|
ReplyMarkup: o.replyMarkup,
|
||||||
|
ParseMode: o.parseMode,
|
||||||
|
Entities: o.entities,
|
||||||
|
MessageThreadID: o.messageThreadID,
|
||||||
|
ReplyToMessageID: o.replyToMessageID,
|
||||||
|
DisableWebPagePreview: o.allowSendingWithoutReply,
|
||||||
|
DisableNotification: o.disableNotification,
|
||||||
|
ProtectContent: o.protectContent,
|
||||||
|
AllowSendingWithoutReply: o.allowSendingWithoutReply,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) MessageTextOptions() *echotron.MessageTextOptions {
|
||||||
|
return &echotron.MessageTextOptions{
|
||||||
|
ReplyMarkup: o.replyMarkup.(echotron.InlineKeyboardMarkup),
|
||||||
|
ParseMode: o.parseMode,
|
||||||
|
Entities: o.entities,
|
||||||
|
DisableWebPagePreview: o.allowSendingWithoutReply,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) PhotoOptions() *echotron.PhotoOptions {
|
||||||
|
return &echotron.PhotoOptions{
|
||||||
|
ReplyMarkup: o.replyMarkup,
|
||||||
|
ParseMode: o.parseMode,
|
||||||
|
Caption: o.caption,
|
||||||
|
CaptionEntities: o.entities,
|
||||||
|
MessageThreadID: int(o.messageThreadID),
|
||||||
|
ReplyToMessageID: o.replyToMessageID,
|
||||||
|
HasSpoiler: o.hasSpoiler,
|
||||||
|
DisableNotification: o.disableNotification,
|
||||||
|
ProtectContent: o.protectContent,
|
||||||
|
AllowSendingWithoutReply: o.allowSendingWithoutReply,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionsBuilder) VideoOptions() *echotron.VideoOptions {
|
||||||
|
return &echotron.VideoOptions{
|
||||||
|
ReplyMarkup: o.replyMarkup,
|
||||||
|
ParseMode: o.parseMode,
|
||||||
|
Caption: o.caption,
|
||||||
|
CaptionEntities: o.entities,
|
||||||
|
SupportsStreaming: true,
|
||||||
|
MessageThreadID: int(o.messageThreadID),
|
||||||
|
ReplyToMessageID: o.replyToMessageID,
|
||||||
|
HasSpoiler: o.hasSpoiler,
|
||||||
|
DisableNotification: o.disableNotification,
|
||||||
|
ProtectContent: o.protectContent,
|
||||||
|
AllowSendingWithoutReply: o.allowSendingWithoutReply,
|
||||||
|
}
|
||||||
|
}
|
46
state.go
46
state.go
@ -1,23 +1,55 @@
|
|||||||
package nechotron
|
package nechotron
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"errors"
|
||||||
|
|
||||||
"github.com/NicoNex/echotron/v3"
|
"github.com/NicoNex/echotron/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type State struct {
|
type StateData map[string]interface{}
|
||||||
Fn stateFn
|
|
||||||
Data context.Context
|
type Runnable interface {
|
||||||
|
Call(*Update) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type stateFn func(*Update) (*State, error)
|
type State struct {
|
||||||
|
Fn stateFn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) Call(u *Update) error {
|
||||||
|
return s.Fn(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
type stateFn func(*Update) error
|
||||||
|
|
||||||
|
func (d StateData) Set(name string, data interface{}) {
|
||||||
|
d[name] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d StateData) Get(name string) (interface{}, error) {
|
||||||
|
data, ok := d[name]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("can't get data from statedata")
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d StateData) Has(name string) bool {
|
||||||
|
_, ok := d[name]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d StateData) Clear() {
|
||||||
|
for k := range d {
|
||||||
|
delete(d, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var EchoState = State{
|
var EchoState = State{
|
||||||
Fn: EchoFunc,
|
Fn: EchoFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
func EchoFunc(u *Update) (*State, error) {
|
func EchoFunc(u *Update) error {
|
||||||
u.AnswerText(u.Text(), &echotron.MessageOptions{})
|
u.AnswerText(u.Text(), &echotron.MessageOptions{})
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
98
update.go
98
update.go
@ -13,6 +13,10 @@ type U echotron.Update
|
|||||||
|
|
||||||
var emptyOpts = echotron.MessageOptions{}
|
var emptyOpts = echotron.MessageOptions{}
|
||||||
|
|
||||||
|
type Event interface {
|
||||||
|
Upd() *echotron.Update
|
||||||
|
}
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
U
|
U
|
||||||
Bot *bot
|
Bot *bot
|
||||||
@ -20,10 +24,35 @@ type Update struct {
|
|||||||
Ctx context.Context
|
Ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateCommand struct {
|
||||||
|
Update
|
||||||
|
Param string
|
||||||
|
}
|
||||||
|
|
||||||
func (u *Update) Upd() *echotron.Update {
|
func (u *Update) Upd() *echotron.Update {
|
||||||
return (*echotron.Update)(&u.U)
|
return (*echotron.Update)(&u.U)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *Update) Chat() echotron.Chat {
|
||||||
|
if u.IsMessage() {
|
||||||
|
return u.Message.Chat
|
||||||
|
}
|
||||||
|
if u.IsCallback() {
|
||||||
|
return u.CallbackQuery.Message.Chat
|
||||||
|
}
|
||||||
|
if u.EditedMessage != nil {
|
||||||
|
return u.EditedMessage.Chat
|
||||||
|
}
|
||||||
|
if u.ChatMember != nil {
|
||||||
|
return u.ChatMember.Chat
|
||||||
|
}
|
||||||
|
if u.MyChatMember != nil {
|
||||||
|
return u.MyChatMember.Chat
|
||||||
|
}
|
||||||
|
log.Fatalf("[%s] Can't get ChatID of update %v+", u.UpdateID, u.U)
|
||||||
|
return echotron.Chat{}
|
||||||
|
}
|
||||||
|
|
||||||
func (u *Update) ChatID() int64 {
|
func (u *Update) ChatID() int64 {
|
||||||
if u.IsMessage() {
|
if u.IsMessage() {
|
||||||
return u.Message.Chat.ID
|
return u.Message.Chat.ID
|
||||||
@ -44,6 +73,18 @@ func (u *Update) MessageID() int {
|
|||||||
log.Fatalf("[%s] Can't get ChatID of update %v+", u.UpdateID, u.U)
|
log.Fatalf("[%s] Can't get ChatID of update %v+", u.UpdateID, u.U)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
func (u *Update) ThreadID() int64 {
|
||||||
|
if !u.Chat().IsForum {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if u.IsMessage() {
|
||||||
|
return int64(u.Message.ThreadID)
|
||||||
|
}
|
||||||
|
if u.IsCallback() {
|
||||||
|
return int64(u.CallbackQuery.Message.ThreadID)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func (u *Update) AnswerText(text string, options *echotron.MessageOptions) (echotron.APIResponseMessage, error) {
|
func (u *Update) AnswerText(text string, options *echotron.MessageOptions) (echotron.APIResponseMessage, error) {
|
||||||
return u.Bot.SendMessage(text, u.ChatID(), options)
|
return u.Bot.SendMessage(text, u.ChatID(), options)
|
||||||
@ -54,12 +95,15 @@ func (u *Update) EditText(text string, options *echotron.MessageTextOptions) (ec
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *Update) AnswerPlain(text string) (echotron.APIResponseMessage, error) {
|
func (u *Update) AnswerPlain(text string) (echotron.APIResponseMessage, error) {
|
||||||
return u.Bot.SendMessage(text, u.ChatID(), &emptyOpts)
|
return u.Bot.SendMessage(text, u.ChatID(), &echotron.MessageOptions{
|
||||||
|
MessageThreadID: u.ThreadID(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Update) AnswerMarkdown(text string) (echotron.APIResponseMessage, error) {
|
func (u *Update) AnswerMarkdown(text string) (echotron.APIResponseMessage, error) {
|
||||||
return u.Bot.SendMessage(text, u.ChatID(), &echotron.MessageOptions{
|
return u.Bot.SendMessage(text, u.ChatID(), &echotron.MessageOptions{
|
||||||
ParseMode: echotron.MarkdownV2,
|
ParseMode: echotron.MarkdownV2,
|
||||||
|
MessageThreadID: u.ThreadID(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +131,9 @@ func (u *Update) IsMessage() bool {
|
|||||||
func (u *Update) IsCallback() bool {
|
func (u *Update) IsCallback() bool {
|
||||||
return u.CallbackQuery != nil
|
return u.CallbackQuery != nil
|
||||||
}
|
}
|
||||||
|
func (u *Update) IsReply() bool {
|
||||||
|
return u.IsMessage() && u.Message.ReplyToMessage != nil
|
||||||
|
}
|
||||||
func (u *Update) IsButton(b *Button) bool {
|
func (u *Update) IsButton(b *Button) bool {
|
||||||
if u.IsText() && u.Text() == b.text {
|
if u.IsText() && u.Text() == b.text {
|
||||||
return true
|
return true
|
||||||
@ -151,14 +198,43 @@ func (u *Update) From() *echotron.User {
|
|||||||
if u.IsMessage() {
|
if u.IsMessage() {
|
||||||
return u.Message.From
|
return u.Message.From
|
||||||
}
|
}
|
||||||
|
if u.EditedMessage != nil {
|
||||||
|
return u.EditedMessage.From
|
||||||
|
}
|
||||||
|
if u.ChatMember != nil {
|
||||||
|
return &u.ChatMember.From
|
||||||
|
}
|
||||||
|
if u.MyChatMember != nil {
|
||||||
|
return &u.MyChatMember.From
|
||||||
|
}
|
||||||
return u.CallbackQuery.From
|
return u.CallbackQuery.From
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetText(u *echotron.Message) string {
|
||||||
|
if u.Text != "" {
|
||||||
|
return u.Text
|
||||||
|
}
|
||||||
|
if u.Caption != "" {
|
||||||
|
return u.Caption
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (u *Update) Text() string {
|
func (u *Update) Text() string {
|
||||||
if u.IsText() {
|
if u.IsText() {
|
||||||
return u.Message.Text
|
return u.Message.Text
|
||||||
}
|
}
|
||||||
return u.Message.Caption
|
if u.IsMessage() {
|
||||||
|
return u.Message.Caption
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Update) Callback() string {
|
||||||
|
if u.IsCallback() {
|
||||||
|
return u.CallbackQuery.Data
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Update) Entities() []*echotron.MessageEntity {
|
func (u *Update) Entities() []*echotron.MessageEntity {
|
||||||
@ -168,27 +244,13 @@ func (u *Update) Entities() []*echotron.MessageEntity {
|
|||||||
return u.Message.CaptionEntities
|
return u.Message.CaptionEntities
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Update) IsUserAdmin() bool {
|
|
||||||
ids := []int64{
|
|
||||||
60441930, // v.rud
|
|
||||||
327487258, // vika shet
|
|
||||||
}
|
|
||||||
from := u.From()
|
|
||||||
for i := range ids {
|
|
||||||
if from.ID == ids[i] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *Update) LogError(text string, e error, send bool) {
|
func (u *Update) LogError(text string, e error, send bool) {
|
||||||
if text != "" {
|
if text != "" {
|
||||||
text = "Ошибка: " + text
|
text = "Ошибка: " + text
|
||||||
} else {
|
} else {
|
||||||
text = "Произошла внутренняя ошибка"
|
text = "Произошла внутренняя ошибка"
|
||||||
}
|
}
|
||||||
log.Printf("[%s] %s: %v", u.UpdateID.String(), text, e)
|
log.Printf("ERROR :: [%s] :: %s: %v", u.UpdateID.String(), text, e)
|
||||||
if send {
|
if send {
|
||||||
u.AnswerMarkdown(fmt.Sprintf("%s\nКод запроса: `%s`", text, u.UpdateID.String()))
|
u.AnswerMarkdown(fmt.Sprintf("%s\nКод запроса: `%s`", text, u.UpdateID.String()))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user