Skip to content

Reading input ​

Every handler receives a *goroku.Message. These helpers cover almost all argument parsing.

Args ​

Everything after the command word, trimmed:

go
// .say hello there
msg.Args() // "hello there"

// .say
msg.Args() // ""

Inner spacing is preserved — .say a b gives "a b" — so it is safe for text you intend to echo verbatim.

ArgsList and Arg ​

Split on whitespace:

go
// .ban 42 spam here
msg.ArgsList() // []string{"42", "spam", "here"}
msg.Arg(0)     // "42"
msg.Arg(1)     // "spam"
msg.Arg(9)     // "" — no panic

Arg is bounds-safe. You never need to check the length first:

go
func (m *Mod) BanCmd(msg *goroku.Message) error {
	id := msg.Arg(0)
	if id == "" {
		return msg.Answer(m.T("no_id", "❌ <b>Who?</b>"))
	}
	reason := msg.Arg(1) // "" when omitted, which is fine
	return m.ban(id, reason)
}

ArgsOrReply ​

The pattern most commands want: use the typed arguments, or fall back to the message the user replied to.

go
func (m *HTML) HTMLCmd(msg *goroku.Message) error {
	code := msg.ArgsOrReply()
	if code == "" {
		return msg.Answer(m.T("no_args", "❌ <b>Send text or reply</b>"))
	}
	return msg.Answer(code)
}

Both of these now work:

.html <b>hi</b>          → renders the typed markup
.html  (as a reply)      → renders the replied-to message

An empty result means there was neither — treat it as "nothing to do".

The replied-to message ​

For anything beyond its text, fetch it:

go
reply, err := msg.GetReplyMessage()
if err != nil || reply == nil {
	return msg.Answer(m.T("reply_needed", "❌ <b>Reply to a message</b>"))
}

if reply.Media != nil {
	// handle the attachment
}

To require a reply, prefer the declarative form — the dispatcher filters before your handler runs:

go
"mycmd": { OnlyReply: true },

Message fields ​

FieldTypeMeaning
IDint64Message ID
ChatIDint64Where it was sent
SenderIDint64Who sent it
TextstringText, formatting applied
RawTextstringText as typed
OutboolSent by you
IsPrivate, IsGroup, IsChannelboolChat type
Mediatg.MessageMediaClassAttachment, nil when absent
ReplyToMsgIDint640 when not a reply
IsForwardedboolForwarded from elsewhere

Cancellation ​

msg.Context() is cancelled when the bot shuts down. Pass it to anything slow:

go
req, err := http.NewRequestWithContext(msg.Context(), http.MethodGet, url, nil)
if err != nil {
	return err
}
resp, err := http.DefaultClient.Do(req)

Handlers that ignore it still work — shutdown just waits for them.

Released under the GNU AGPL v3 License.