Class: DiscordRDA::CommandSystem

Inherits:
Object
  • Object
show all
Defined in:
lib/discord_rda/interactions/command_system.rb

Overview

Full command system for Discord slash commands Provides command registration, subcommands, permissions, cooldowns, and middleware

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger: nil) ⇒ CommandSystem

Returns a new instance of CommandSystem.



17
18
19
20
21
22
# File 'lib/discord_rda/interactions/command_system.rb', line 17

def initialize(logger: nil)
  @commands = {}
  @middleware = []
  @logger = logger
  @cooldowns = {}
end

Instance Attribute Details

#commandsHash (readonly)

Returns Registered commands by name.

Returns:

  • (Hash)

    Registered commands by name



9
10
11
# File 'lib/discord_rda/interactions/command_system.rb', line 9

def commands
  @commands
end

#loggerLogger (readonly)

Returns Logger instance.

Returns:

  • (Logger)

    Logger instance



15
16
17
# File 'lib/discord_rda/interactions/command_system.rb', line 15

def logger
  @logger
end

#middlewareArray (readonly)

Returns Global middleware chain.

Returns:

  • (Array)

    Global middleware chain



12
13
14
# File 'lib/discord_rda/interactions/command_system.rb', line 12

def middleware
  @middleware
end

Instance Method Details

#apply_cooldown(command_name, duration, user_id:, guild_id: nil, scope: :user) ⇒ Object

Apply cooldown for a command

Parameters:

  • command_name (String)

    Command name

  • duration (Integer)

    Cooldown duration in seconds

  • user_id (String)

    User ID

  • guild_id (String) (defaults to: nil)

    Guild ID (optional)

  • scope (Symbol) (defaults to: :user)

    Cooldown scope (:user, :guild, :channel)



160
161
162
163
# File 'lib/discord_rda/interactions/command_system.rb', line 160

def apply_cooldown(command_name, duration, user_id:, guild_id: nil, scope: :user)
  key = cooldown_key(command_name, user_id, guild_id, scope)
  @cooldowns[key] = Time.now.to_f + duration
end

#clear_cooldownsObject

Clear all cooldowns



166
167
168
# File 'lib/discord_rda/interactions/command_system.rb', line 166

def clear_cooldowns
  @cooldowns.clear
end

#cooldown_remaining(command_name, user_id:, guild_id: nil) ⇒ Float?

Check if a command is on cooldown

Parameters:

  • command_name (String)

    Command name

  • user_id (String)

    User ID

  • guild_id (String) (defaults to: nil)

    Guild ID (optional)

Returns:

  • (Float, nil)

    Seconds remaining on cooldown, or nil if not on cooldown



145
146
147
148
149
150
151
152
# File 'lib/discord_rda/interactions/command_system.rb', line 145

def cooldown_remaining(command_name, user_id:, guild_id: nil)
  key = cooldown_key(command_name, user_id, guild_id)
  expires_at = @cooldowns[key]
  return nil unless expires_at

  remaining = expires_at - Time.now.to_f
  remaining > 0 ? remaining : nil
end

#handle(interaction) ⇒ Object

Handle an interaction

Parameters:

  • interaction (Interaction)

    The interaction to handle

Returns:

  • (Object)

    Handler result



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/discord_rda/interactions/command_system.rb', line 114

def handle(interaction)
  return nil unless interaction.command?

  command_data = interaction.command_data
  return nil unless command_data

  command_name = command_data['name']
  command = @commands[command_name.to_s]

  return nil unless command

  context = CommandContext.new(interaction, self)

  # Run global middleware
  @middleware.each do |mw|
    result = mw.call(context)
    return result if result == :halt
  end

  # Run command
  command.execute(context)
rescue => e
  @logger&.error('Command execution failed', error: e, command: command_name)
  raise
end

#register(name, description:, options: [], subcommands: {}, subcommand_groups: {}, permissions: [], cooldown: nil, middleware: [], &block) ⇒ Command

Register a command

Parameters:

  • name (String)

    Command name

  • description (String)

    Command description

  • options (Array) (defaults to: [])

    Command options

  • subcommands (Hash) (defaults to: {})

    Subcommand handlers

  • subcommand_groups (Hash) (defaults to: {})

    Subcommand group handlers

  • permissions (Array) (defaults to: [])

    Required permissions

  • cooldown (Hash) (defaults to: nil)

    Cooldown configuration { duration: seconds, scope: :user/:guild/:channel }

  • middleware (Array) (defaults to: [])

    Per-command middleware

  • block (Proc)

    Command handler

Returns:



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/discord_rda/interactions/command_system.rb', line 35

def register(name, description:, options: [], subcommands: {}, subcommand_groups: {},
             permissions: [], cooldown: nil, middleware: [], &block)
  command = Command.new(
    name: name,
    description: description,
    options: options,
    subcommands: subcommands,
    subcommand_groups: subcommand_groups,
    permissions: permissions,
    cooldown: cooldown,
    middleware: middleware,
    handler: block,
    system: self
  )

  @commands[name.to_s] = command
  @logger&.info('Command registered', name: name)
  command
end

#register_subcommand(parent, name, description:, options: [], permissions: [], &block) ⇒ Subcommand

Register a subcommand

Parameters:

  • parent (String)

    Parent command name

  • name (String)

    Subcommand name

  • description (String)

    Description

  • options (Array) (defaults to: [])

    Options

  • permissions (Array) (defaults to: [])

    Required permissions

  • block (Proc)

    Handler

Returns:



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/discord_rda/interactions/command_system.rb', line 63

def register_subcommand(parent, name, description:, options: [], permissions: [], &block)
  parent_cmd = @commands[parent.to_s]
  raise "Parent command '#{parent}' not found" unless parent_cmd

  subcommand = Subcommand.new(
    name: name,
    description: description,
    options: options,
    permissions: permissions,
    handler: block,
    parent: parent_cmd
  )

  parent_cmd.subcommands[name.to_s] = subcommand
  @logger&.info('Subcommand registered', parent: parent, name: name)
  subcommand
end

#register_subcommand_group(parent, name, description:, subcommands: {}) ⇒ SubcommandGroup

Register a subcommand group

Parameters:

  • parent (String)

    Parent command name

  • name (String)

    Group name

  • description (String)

    Description

  • subcommands (Hash) (defaults to: {})

    Subcommands in this group

Returns:



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/discord_rda/interactions/command_system.rb', line 87

def register_subcommand_group(parent, name, description:, subcommands: {})
  parent_cmd = @commands[parent.to_s]
  raise "Parent command '#{parent}' not found" unless parent_cmd

  group = SubcommandGroup.new(
    name: name,
    description: description,
    subcommands: subcommands,
    parent: parent_cmd
  )

  parent_cmd.subcommand_groups[name.to_s] = group
  @logger&.info('Subcommand group registered', parent: parent, name: name)
  group
end

#to_discord_commandsArray<Hash>

Get all commands as Discord application command JSON

Returns:

  • (Array<Hash>)

    Commands as Discord API format



172
173
174
# File 'lib/discord_rda/interactions/command_system.rb', line 172

def to_discord_commands
  @commands.values.map(&:to_discord_format)
end

#use(middleware) ⇒ self

Add global middleware

Parameters:

  • middleware (Middleware, Proc)

    Middleware to add

Returns:

  • (self)


106
107
108
109
# File 'lib/discord_rda/interactions/command_system.rb', line 106

def use(middleware)
  @middleware << middleware
  self
end