bot icon indicating copy to clipboard operation
bot copied to clipboard

Group-like syntax commands

Open marcantoinegodde opened this issue 10 months ago • 1 comments

Hello :)

Following issue #157 and PR #168, we don't properly handle group-like syntax command (/command@botname), right?

It seems that even with MatchTypeCommand and MatchTypeCommandStartOnly we can't recognise the command because it's considered as a different one by data[e.Offset+1:e.Offset+e.Length] == h.pattern.

How would you do things differently? Search for pattern inclusion?

Best

marcantoinegodde avatar Apr 28 '25 00:04 marcantoinegodde

I use this for the time being:

func (s *TelegramService) registerCommandHandler(command string, handler bot.HandlerFunc) {
	commandText := "/" + command
	commandTextPrefix := commandText + "@"
	matchFunc := func(update *models.Update) bool {
		if update.Message != nil {
			for _, e := range update.Message.Entities {
				if e.Offset == 0 {
					part := update.Message.Text[e.Offset : e.Offset+e.Length]
					if part == commandText || strings.HasPrefix(part, commandTextPrefix) {
						return true
					}
				}
			}
		}
		return false
	}
	s.bot.RegisterHandlerMatchFunc(matchFunc, handler)
}

(Note that it's somewhat sub optimal as we should really be checking only the first entity instead of checking every and compare offset to 0).

IlyaSemenov avatar Jul 21 '25 11:07 IlyaSemenov

Yes, currently matching command in this format is not built into the library. But this can be easily implemented by creating your own matching function (MatchFunc) and registering a handler with this function via RegisterHandlerMatchFunc(matchFunc MatchFunc, f HandlerFunc, m ...Middleware).

For example:

...
b, err := bot.New(cfg.Token, opts...)
if err != nil {
    return nil, err
}

b.RegisterHandlerMatchFunc(MatchCommandTestWithParams, CommandTest)
...


func MatchCommandTestWithParams(update *models.Update) bool {
	if update.Message == nil {
		return false
	}

	return strings.HasPrefix(update.Message.Text, "/test@")
}

func CommandTest(ctx context.Context, b *bot.Bot, update *models.Update) {
	if update.Message == nil {
		return
	}

	parts := strings.SplitAfter(update.Message.Text, "@")
	commandPart := parts[0]
	paramPart := parts[1]

	partsText := fmt.Sprintf("Command: %s\nParameter: %s", commandPart, paramPart)

	b.SendMessage(ctx, &bot.SendMessageParams{
		ChatID: update.Message.Chat.ID,
		Text:   fmt.Sprintf("`%s` command received!\n\n%s", update.Message.Text, partsText),
	})
}

Result: Image


To simplify, the /test command was hardcoded and the @ character was not dropped when dividing into a command and its parameters. It can be done, but that's not the goal. The goal is to demonstrate the general idea. That is not so difficult to make your own MatchFunc, which will be able to process commands in the format /command@param and any others.

steindvart avatar Nov 21 '25 07:11 steindvart

And I think that a similar MatchFunc for commands with parameters would be very useful as part of the library.

@negasus

steindvart avatar Nov 21 '25 07:11 steindvart