discord

package
v1.18.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 27, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package discord - components.go provides reusable interactive component handling for Discord (buttons, select menus) with registration, TTL-based cleanup, AllowedUsers restriction, and Reusable behavior. See ComponentRegistry, ComponentSpec, and BuildButtonRow/BuildSelectRow.

Package discord implements the Discord channel for DevClaw using discordgo.

Features:

  • Send/receive text, images, audio, video, documents
  • Typing indicators
  • Reactions (emoji)
  • Thread support (auto-thread mode)
  • Embed messages for long responses
  • Guild and channel allowlists
  • Interactive components (buttons, select menus) with Reusable and AllowedUsers
  • Automatic reconnection via discordgo's gateway

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildButtonRow

func BuildButtonRow(customID, label string, style discordgo.ButtonStyle) discordgo.MessageComponent

BuildButtonRow creates a discordgo ActionsRow containing a single button. Use with Register(customID, spec) before sending the message.

func BuildSelectRow

func BuildSelectRow(customID string, options []discordgo.SelectMenuOption, placeholder string) discordgo.MessageComponent

BuildSelectRow creates a discordgo ActionsRow containing a string select menu. Use with Register(customID, spec) before sending the message.

Types

type ComponentHandler

type ComponentHandler func(ctx context.Context, evt *InteractionEvent) (content string, err error)

ComponentHandler processes a component interaction. It receives the interaction context and returns optional response content and an optional error. For select menus, evt.Values contains the selected option values.

type ComponentKind

type ComponentKind string

ComponentKind identifies the type of component.

const (
	ComponentKindButton ComponentKind = "button"
	ComponentKindSelect ComponentKind = "select"
)

type ComponentRegistry

type ComponentRegistry struct {
	// contains filtered or unexported fields
}

ComponentRegistry stores component specs by custom_id and handles TTL cleanup.

func NewComponentRegistry

func NewComponentRegistry(logger *slog.Logger) *ComponentRegistry

NewComponentRegistry creates a registry and starts background TTL cleanup.

func (*ComponentRegistry) Copy

func (r *ComponentRegistry) Copy() map[string]ComponentSpec

Copy returns a snapshot of all registered custom IDs (for tests/debug).

func (*ComponentRegistry) Get

func (r *ComponentRegistry) Get(customID string) (*ComponentSpec, bool)

Get retrieves the component spec if it exists and is not expired.

func (*ComponentRegistry) Register

func (r *ComponentRegistry) Register(customID string, spec ComponentSpec)

Register adds or overwrites a component spec for the given custom_id. Call this before sending a message that includes the component.

func (*ComponentRegistry) Stop

func (r *ComponentRegistry) Stop()

Stop halts the cleanup loop. Call when shutting down the Discord channel.

func (*ComponentRegistry) Unregister

func (r *ComponentRegistry) Unregister(customID string)

Unregister removes a component spec.

type ComponentSpec

type ComponentSpec struct {
	// Kind is the component type (button or select).
	Kind ComponentKind

	// Reusable, when true, means clicking does NOT consume/disable the component.
	// It can be clicked multiple times. Default is false.
	Reusable bool

	// AllowedUsers restricts who can interact. If nil or empty, anyone can use it.
	AllowedUsers []string

	// TTL is how long the component stays registered. After expiry it is removed
	// and interactions are ignored. Zero means no expiry.
	TTL time.Duration

	// Handler is called when an authorized user interacts. The handler may return
	// content to display in the interaction response. If the handler returns
	// an error, an error message is shown to the user.
	Handler ComponentHandler
}

ComponentSpec defines the behavior of a registered interactive component. Register components before sending messages that include them.

func (*ComponentSpec) IsAllowed

func (s *ComponentSpec) IsAllowed(userID string) bool

IsAllowed checks if the user is in AllowedUsers. If AllowedUsers is nil/empty, returns true.

type Config

type Config struct {
	// InstanceID identifies this instance ("" for default, e.g. "gaming" for named).
	// Set automatically from the config key in discord_instances.
	InstanceID string `yaml:"instance_id,omitempty"`

	// Token is the Discord bot token.
	Token string `yaml:"token"`

	// AllowedGuilds restricts which guild (server) IDs the bot responds in.
	// Empty means respond in all guilds.
	AllowedGuilds []string `yaml:"allowed_guilds"`

	// AllowedChannels restricts which channel IDs the bot responds in.
	// Empty means respond in all channels.
	AllowedChannels []string `yaml:"allowed_channels"`

	// RespondToThreads enables responding inside threads.
	RespondToThreads bool `yaml:"respond_to_threads"`

	// AutoThread creates a new thread per conversation for cleanliness.
	AutoThread bool `yaml:"auto_thread"`

	// SendTyping sends "typing..." indicators while processing.
	SendTyping bool `yaml:"send_typing"`
}

Config holds Discord channel configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with sensible defaults.

type Discord

type Discord struct {
	// contains filtered or unexported fields
}

Discord implements channels.Channel, channels.MediaChannel, channels.PresenceChannel, and channels.ReactionChannel.

func New

func New(cfg Config, logger *slog.Logger) *Discord

New creates a new Discord channel instance.

func (*Discord) BaseType added in v1.16.0

func (d *Discord) BaseType() string

BaseType returns "discord".

func (*Discord) ComponentRegistry

func (d *Discord) ComponentRegistry() *ComponentRegistry

ComponentRegistry returns the component registry for registering buttons and selects.

func (*Discord) Connect

func (d *Discord) Connect(ctx context.Context) error

Connect opens the Discord gateway WebSocket connection.

func (*Discord) Disconnect

func (d *Discord) Disconnect() error

Disconnect closes the Discord gateway connection.

func (*Discord) DownloadMedia

func (d *Discord) DownloadMedia(ctx context.Context, msg *channels.IncomingMessage) ([]byte, string, error)

DownloadMedia downloads an attachment from an incoming message.

func (*Discord) Health

func (d *Discord) Health() channels.HealthStatus

Health returns the channel health status.

func (*Discord) InstanceID added in v1.16.0

func (d *Discord) InstanceID() string

InstanceID returns the instance identifier ("" for default).

func (*Discord) IsConnected

func (d *Discord) IsConnected() bool

IsConnected returns true if the bot is connected.

func (*Discord) MarkRead

func (d *Discord) MarkRead(ctx context.Context, chatID string, messageIDs []string) error

MarkRead is a no-op for Discord (bots don't mark messages as read).

func (*Discord) Name

func (d *Discord) Name() string

Name returns the channel name. For the default instance this is "discord"; for named instances it returns "discord:<instance_id>".

func (*Discord) Receive

func (d *Discord) Receive() <-chan *channels.IncomingMessage

Receive returns the incoming messages channel.

func (*Discord) Send

func (d *Discord) Send(ctx context.Context, to string, message *channels.OutgoingMessage) error

Send sends a text message to the specified channel.

func (*Discord) SendMedia

func (d *Discord) SendMedia(ctx context.Context, to string, media *channels.MediaMessage) error

SendMedia sends a file/media attachment to the specified channel.

func (*Discord) SendPresence

func (d *Discord) SendPresence(ctx context.Context, available bool) error

SendPresence updates the bot's status.

func (*Discord) SendReaction

func (d *Discord) SendReaction(ctx context.Context, chatID, messageID, emoji string) error

SendReaction adds a reaction emoji to a message.

func (*Discord) SendTyping

func (d *Discord) SendTyping(ctx context.Context, to string) error

SendTyping sends a typing indicator to the channel.

func (*Discord) SendWithComponents

func (d *Discord) SendWithComponents(ctx context.Context, to string, content string, components []discordgo.MessageComponent) error

SendWithComponents sends a message with interactive components (buttons, selects). Register components with d.ComponentRegistry().Register(customID, spec) before calling.

type InteractionEvent

type InteractionEvent struct {
	CustomID      string
	UserID        string
	Username      string
	ChannelID     string
	GuildID       string
	MessageID     string
	Values        []string // For select menus
	ComponentType discordgo.ComponentType
}

InteractionEvent carries data from a component interaction.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL