Skip to content

Commit

Permalink
fix: added ChosenInlineResultAction & InlineQueryAction to type Command
Browse files Browse the repository at this point in the history
  • Loading branch information
trakhimenok committed Feb 12, 2025
1 parent 3b28147 commit 14ea29d
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 38 deletions.
29 changes: 18 additions & 11 deletions botsfw/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ type CommandAction func(whc WebhookContext) (m MessageFromBot, err error)
// CallbackAction defines a callback action bot can perform in response to a callback command
type CallbackAction func(whc WebhookContext, callbackUrl *url.URL) (m MessageFromBot, err error)

type InlineQueryAction func(whc WebhookContext, inlineQuery botinput.WebhookInlineQuery, queryUrl *url.URL) (m MessageFromBot, err error)

type ChosenInlineResultAction func(whc WebhookContext, chosenResult botinput.WebhookChosenInlineResult, queryUrl *url.URL) (m MessageFromBot, err error)

// CommandMatcher returns true if action is matched to user input
type CommandMatcher func(Command, WebhookContext) bool

Expand All @@ -27,17 +31,20 @@ type CommandCode string

// Command defines command metadata and action
type Command struct {
InputTypes []botinput.WebhookInputType // Instant match if != WebhookInputUnknown && == whc.InputTypes()
Icon string
Replies []Command
Code CommandCode
Title string
Titles map[string]string
ExactMatch string
Commands []string
Matcher CommandMatcher
Action CommandAction
CallbackAction CallbackAction
Code CommandCode
InputTypes []botinput.WebhookInputType // Instant match if != WebhookInputUnknown && == whc.InputTypes()
Icon string
Replies []Command
Title string
Titles map[string]string
ExactMatch string
Commands []string
Matcher CommandMatcher
//
Action CommandAction
CallbackAction CallbackAction
InlineQueryAction InlineQueryAction
ChosenInlineResultAction ChosenInlineResultAction
}

//goland:noinspection GoUnusedExportedFunction
Expand Down
115 changes: 88 additions & 27 deletions botsfw/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,49 +151,90 @@ func (whRouter *webhooksRouter) RegisterCommands(commands ...Command) {
if command.CallbackAction != nil {
addCommand(botinput.WebhookInputCallbackQuery, command)
}
if command.ChosenInlineResultAction != nil {
addCommand(botinput.WebhookInputChosenInlineResult, command)
}
} else {
callbackAdded := false
var callbackAdded, inlineQueryAdded, chosenInlineResultAdded bool
for _, t := range command.InputTypes {
addCommand(t, command)
if t == botinput.WebhookInputCallbackQuery {
switch t {
case botinput.WebhookInputCallbackQuery:
callbackAdded = true
case botinput.WebhookInputInlineQuery:
inlineQueryAdded = true
case botinput.WebhookInputChosenInlineResult:
chosenInlineResultAdded = true
default:
// OK
}
}
if command.CallbackAction != nil && !callbackAdded {
addCommand(botinput.WebhookInputCallbackQuery, command)
}
if command.InlineQueryAction != nil && !inlineQueryAdded {
addCommand(botinput.WebhookInputInlineQuery, command)
}
if command.ChosenInlineResultAction != nil && !chosenInlineResultAdded {
addCommand(botinput.WebhookInputChosenInlineResult, command)
}
}
}
}

var ErrNoCommandsMatched = errors.New("no commands matched")

func matchCallbackCommands(whc WebhookContext, input botinput.WebhookCallbackQuery, typeCommands *TypeCommands) (matchedCommand *Command, callbackURL *url.URL, err error) {
if len(typeCommands.all) > 0 {
callbackData := input.GetData()
callbackURL, err = url.Parse(callbackData)
if err != nil {
log.Errorf(whc.Context(), "Failed to parse callback data to URL: %v", err.Error())
} else {
for _, c := range typeCommands.all {
if c.Matcher != nil {
if c.Matcher(c, whc) {
return &c, callbackURL, nil
}
func matchByQuery(whc WebhookContext, input interface{ GetQuery() string }, commands map[CommandCode]Command) (matchedCommand *Command, queryURL *url.URL, err error) {
query := input.GetQuery()
checkMatchers := func() {
for _, command := range commands {
if command.Matcher != nil {
if command.Matcher(command, whc) {
matchedCommand = &command
break
}
}
callbackPath := callbackURL.Path
if command, ok := typeCommands.byCode[CommandCode(callbackPath)]; ok {
return &command, callbackURL, nil
}
}
//if matchedCommand == nil {
log.Errorf(whc.Context(), fmt.Errorf("%w: %s", ErrNoCommandsMatched, fmt.Sprintf("callbackData=[%v]", callbackData)).Error())
whc.Input().LogRequest() // TODO: LogRequest() should not be part of Input?
//}
}
if query != "" {
checkMatchers()
return
}
if queryURL, err = url.Parse(query); err != nil {
err = nil
return
}
command := commands[CommandCode(queryURL.Path)]
if command.ChosenInlineResultAction != nil {
matchedCommand = &command
return
}
checkMatchers()
return
}

func matchCallbackCommands(whc WebhookContext, input botinput.WebhookCallbackQuery, commands map[CommandCode]Command) (matchedCommand *Command, callbackURL *url.URL, err error) {

callbackData := input.GetData()
callbackURL, err = url.Parse(callbackData)
if err != nil {
log.Debugf(whc.Context(), "Failed to parse callback data to URL: %v", err.Error())
} else {
panic("len(typeCommands.all) == 0")
for _, c := range commands {
if c.Matcher != nil && c.Matcher(c, whc) {
return &c, callbackURL, nil
}
}
callbackPath := callbackURL.Path
if command, ok := commands[CommandCode(callbackPath)]; ok {
return &command, callbackURL, nil
}
}
//if matchedCommand == nil {
log.Errorf(whc.Context(), fmt.Errorf("%w: %s", ErrNoCommandsMatched, fmt.Sprintf("callbackData=[%v]", callbackData)).Error())
whc.Input().LogRequest() // TODO: LogRequest() should not be part of Input?
//}

return nil, callbackURL, err
}

Expand Down Expand Up @@ -375,12 +416,16 @@ func (whRouter *webhooksRouter) Dispatch(webhookHandler WebhookHandler, responde
commandAction CommandAction
m MessageFromBot
)
input := whc.Input()

if len(typeCommands.all) == 0 {
panic("len(typeCommands.all) == 0")
}

var isCommandText bool
switch input := input.(type) {
switch input := whc.Input().(type) {
case botinput.WebhookCallbackQuery:
var callbackURL *url.URL
matchedCommand, callbackURL, err = matchCallbackCommands(whc, input, typeCommands)
matchedCommand, callbackURL, err = matchCallbackCommands(whc, input, typeCommands.byCode)
if err == nil && matchedCommand != nil {
if matchedCommand.Code == "" {
err = fmt.Errorf("matchedCommand(%T: %v).ByCode is empty string", matchedCommand, matchedCommand)
Expand All @@ -396,6 +441,22 @@ func (whRouter *webhooksRouter) Dispatch(webhookHandler WebhookHandler, responde
}
}
}
case botinput.WebhookInlineQuery:
var queryURL *url.URL
matchedCommand, queryURL, err = matchByQuery(whc, input, typeCommands.byCode)
if err == nil && matchedCommand != nil {
commandAction = func(whc WebhookContext) (m MessageFromBot, err error) {
return matchedCommand.InlineQueryAction(whc, input, queryURL)
}
}
case botinput.WebhookChosenInlineResult:
var queryURL *url.URL
matchedCommand, queryURL, err = matchByQuery(whc, input, typeCommands.byCode)
if err == nil && matchedCommand != nil {
commandAction = func(whc WebhookContext) (m MessageFromBot, err error) {
return matchedCommand.ChosenInlineResultAction(whc, input, queryURL)
}
}
case botinput.WebhookMessage:
if len(typeCommands.all) == 1 {
matchedCommand = &typeCommands.all[0]
Expand Down Expand Up @@ -444,7 +505,7 @@ func (whRouter *webhooksRouter) Dispatch(webhookHandler WebhookHandler, responde
m.Text += fmt.Sprintf("\n\n<i>AwaitingReplyTo: %s</i>", awaitingReplyTo)
}
}
log.Debugf(c, "No command found for the message: %v", input)
log.Debugf(c, "No command found for the input message: %v", whc.Input().InputType())
whRouter.processCommandResponse(matchedCommand, responder, whc, m, nil)
}
} else { // matchedCommand != nil
Expand Down

0 comments on commit 14ea29d

Please sign in to comment.