1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package bot
import "strings"
// Command is a parsed "/name@target argument" line.
type Command struct {
// Name is the command without the leading slash, lowercased.
Name string
// Target is the bot username the command was addressed to, without the
// "@", or "" when the user did not address anyone.
Target string
// Argument is everything after the command, trimmed.
Argument string
}
// ParseCommand splits a message that starts with a slash.
//
// The "@username" suffix is not optional to handle. Telegram appends it
// automatically whenever more than one bot is in a chat, so in exactly the busy
// groups where the bot is most visible, every command arrives as
// "/cep@thebotname 01001000". A bot that only matches the bare form looks broken
// there.
//
// ok is false when the text is not a command at all.
func ParseCommand(text string) (Command, bool) {
trimmed := strings.TrimSpace(text)
if !strings.HasPrefix(trimmed, "/") || len(trimmed) == 1 {
return Command{}, false
}
head, argument, _ := strings.Cut(trimmed[1:], " ")
name, target, _ := strings.Cut(head, "@")
if name == "" {
return Command{}, false
}
return Command{
Name: strings.ToLower(name),
Target: target,
Argument: strings.TrimSpace(argument),
}, true
}
// AddressedTo reports whether the command is for the bot with this username.
//
// An unaddressed command counts as addressed: in a private chat nobody types
// the suffix, and in a group with a single bot Telegram does not add it either.
// A command addressed to some other bot is not ours, and answering it would put
// two replies under one message.
func (c Command) AddressedTo(username string) bool {
return c.Target == "" || strings.EqualFold(c.Target, username)
}
|