(new): rich message support
(fix): runtime reliability (tests): regression coverage (doc): v1.1 release notes
This commit is contained in:
+32
-38
@@ -1,6 +1,7 @@
|
||||
package laniakea
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
@@ -10,7 +11,6 @@ import (
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
)
|
||||
|
||||
// cmdRegexp matches command names allowed for Telegram command registration.
|
||||
var cmdRegexp = regexp.MustCompile("^[_a-z0-9]{1,32}$")
|
||||
|
||||
// ErrTooManyCommands is returned when the total number of registered commands
|
||||
@@ -39,9 +39,9 @@ func generateBotCommand[T any](cmd *Command[T]) tgapi.BotCommand {
|
||||
usage := fmt.Sprintf("Usage: /%s %s", cmd.command, strings.Join(descArgs, " "))
|
||||
if desc != "" {
|
||||
desc = fmt.Sprintf("%s. %s", desc, usage)
|
||||
return tgapi.BotCommand{Command: cmd.command, Description: desc}
|
||||
return tgapi.BotCommand{Command: cmd.command, Description: desc, IsEphemeral: cmd.isEphemeral}
|
||||
}
|
||||
return tgapi.BotCommand{Command: cmd.command, Description: usage}
|
||||
return tgapi.BotCommand{Command: cmd.command, Description: usage, IsEphemeral: cmd.isEphemeral}
|
||||
}
|
||||
|
||||
func checkCmdRegex(cmd string) bool { return cmdRegexp.MatchString(cmd) }
|
||||
@@ -79,15 +79,8 @@ func gatherCommands[T any](bot *Bot[T]) []tgapi.BotCommand {
|
||||
return commands
|
||||
}
|
||||
|
||||
// AutoGenerateCommands registers all plugin-defined commands with Telegram's Bot API
|
||||
// across three scopes:
|
||||
// - Private chats (users)
|
||||
// - Group chats
|
||||
// - Group administrators
|
||||
//
|
||||
// It first deletes existing commands to ensure a clean state, then sets the new
|
||||
// set of commands for all scopes. This ensures consistency even if commands were
|
||||
// previously modified manually via @BotFather.
|
||||
// AutoGenerateCommands replaces plugin-defined commands in the private-chat,
|
||||
// group-chat, and all-chat-administrators scopes.
|
||||
//
|
||||
// Returns ErrTooManyCommands if the total number of commands exceeds 100.
|
||||
// Returns any API error from Telegram (e.g., network issues, invalid scope).
|
||||
@@ -102,40 +95,33 @@ func gatherCommands[T any](bot *Bot[T]) []tgapi.BotCommand {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
func (bot *Bot[T]) AutoGenerateCommands() error {
|
||||
return bot.AutoGenerateCommandsWithContext(context.Background())
|
||||
}
|
||||
|
||||
// AutoGenerateCommandsWithContext is the context-aware variant of AutoGenerateCommands.
|
||||
func (bot *Bot[T]) AutoGenerateCommandsWithContext(ctx context.Context) error {
|
||||
commands := gatherCommands(bot)
|
||||
if len(commands) > 100 {
|
||||
return ErrTooManyCommands
|
||||
}
|
||||
|
||||
// Clear existing commands to avoid duplication or stale entries
|
||||
_, err := bot.api.DeleteMyCommands(tgapi.DeleteMyCommands{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete existing commands: %w", err)
|
||||
}
|
||||
|
||||
// Register commands for each scope
|
||||
scopes := []*tgapi.BotCommandScope{
|
||||
scopes := []tgapi.BotCommandScope{
|
||||
{Type: tgapi.BotCommandScopePrivateType},
|
||||
{Type: tgapi.BotCommandScopeGroupType},
|
||||
{Type: tgapi.BotCommandScopeAllChatAdministratorsType},
|
||||
}
|
||||
|
||||
for _, scope := range scopes {
|
||||
_, err = bot.api.SetMyCommands(tgapi.SetMyCommands{
|
||||
Commands: commands,
|
||||
Scope: scope,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set commands for scope %q: %w", scope.Type, err)
|
||||
for i := range scopes {
|
||||
if err := bot.setCommandsForScope(ctx, &scopes[i], commands); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AutoGenerateCommandsForScope registers all plugin-defined commands with Telegram's Bot API
|
||||
// for the specified command scope. It first deletes any existing commands in that scope
|
||||
// to ensure a clean state, then sets the new set of commands.
|
||||
// for the specified command scope. A nil scope selects Telegram's default scope.
|
||||
//
|
||||
// The scope parameter defines where the commands should be available (e.g., private chats,
|
||||
// group chats, chat administrators). See tgapi.BotCommandScope and its predefined types.
|
||||
@@ -150,22 +136,30 @@ func (bot *Bot[T]) AutoGenerateCommands() error {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
func (bot *Bot[T]) AutoGenerateCommandsForScope(scope *tgapi.BotCommandScope) error {
|
||||
return bot.AutoGenerateCommandsForScopeWithContext(context.Background(), scope)
|
||||
}
|
||||
|
||||
// AutoGenerateCommandsForScopeWithContext is the context-aware variant of
|
||||
// AutoGenerateCommandsForScope.
|
||||
func (bot *Bot[T]) AutoGenerateCommandsForScopeWithContext(ctx context.Context, scope *tgapi.BotCommandScope) error {
|
||||
commands := gatherCommands(bot)
|
||||
if len(commands) > 100 {
|
||||
return ErrTooManyCommands
|
||||
}
|
||||
return bot.setCommandsForScope(ctx, scope, commands)
|
||||
}
|
||||
|
||||
_, err := bot.api.DeleteMyCommands(tgapi.DeleteMyCommands{Scope: scope})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete existing commands: %w", err)
|
||||
func (bot *Bot[T]) setCommandsForScope(ctx context.Context, scope *tgapi.BotCommandScope, commands []tgapi.BotCommand) error {
|
||||
if len(commands) > 100 {
|
||||
return ErrTooManyCommands
|
||||
}
|
||||
|
||||
_, err = bot.api.SetMyCommands(tgapi.SetMyCommands{
|
||||
Commands: commands,
|
||||
Scope: scope,
|
||||
})
|
||||
_, err := bot.api.SetMyCommandsWithContext(ctx, tgapi.SetMyCommands{Scope: scope, Commands: commands})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set commands for scope %q: %w", scope.Type, err)
|
||||
scopeType := tgapi.BotCommandScopeDefaultType
|
||||
if scope != nil {
|
||||
scopeType = scope.Type
|
||||
}
|
||||
return fmt.Errorf("failed to set commands for scope %q: %w", scopeType, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user