# frozen_string_literal: true
module ESM
module Command
class Base
module Lifecycle
extend ActiveSupport::Concern
class_methods do
#
# The entry point of a command
# This is registered with Discordrb and is called as part of an interaction lifecycle
#
# @note This method will gracefully handle 99% of the errors automatically.
# I recommend avoiding manually handling exceptions in a command's lifecycle so this system can handle it. But the choice is up to you
#
# @!visibility private
#
def event_hook(event)
event = ESM::Discord::Event::ApplicationCommand.new(event)
event.on_execution(self)
end
end
DISCORD_ACCESS_CHECKS = %i[
check_for_dev_only!
check_for_registered!
check_for_text_only!
check_for_dm_only!
check_for_player_mode!
check_for_permissions!
].freeze
WEBSITE_ACCESS_CHECKS = %i[
check_for_dev_only!
check_for_registered!
check_for_player_mode!
check_for_permissions!
].freeze
#
# Called internally by #execute, this method handles when a command has been executed on Discord.
#
def from_discord!
run_lifecycle!(access_checks: DISCORD_ACCESS_CHECKS)
end
#
# Called when a command has been invoked through the website's RPC layer.
# Skips text/DM-channel checks since the website has no channel context.
#
def from_website!
run_lifecycle!(access_checks: WEBSITE_ACCESS_CHECKS)
end
# @param request [ESM::Request] The request to build this command with
# @note Don't load `target_user` from the request. If the arguments contain a target, it will handle it
def from_request(request)
@request = request
arguments.merge!(request.command_arguments.symbolize_keys) if request.command_arguments.present?
timers.time!(:from_request) do
load_v1_code! if v1_code_needed? # V1
if @request.accepted
on_request_accepted
else
# Reset the cooldown since the request was declined.
current_cooldown.reset! if current_cooldown.present?
on_request_declined
end
end
end
def on_execute
end
def on_request_accepted
end
def on_request_declined
end
private
def run_lifecycle!(access_checks:)
# Check for these BEFORE validating the arguments so even if an argument was invalid, it doesn't matter since these take priority
timers.time!(:access_checks) do
access_checks.each { |check| public_send(check) }
end
# Now ensure the user hasn't smoked too much lead
timers.time!(:argument_validation) do
arguments.validate!
end
info!(to_h)
timers.time!(:before_execute) do
check_for_nil_target_community! unless skipped_actions.nil_target_community?
check_for_nil_target_server! unless skipped_actions.nil_target_server?
check_for_nil_target_user! unless skipped_actions.nil_target_user?
check_for_connected_server! unless skipped_actions.connected_server?
check_for_cooldown! unless skipped_actions.cooldown?
check_for_different_community! unless skipped_actions.different_community?
end
result = nil
timers.time!(:on_execute) do
load_v1_code! if v1_code_needed? # V1
result = on_execute
end
timers.time!(:after_execute) do
# Update the cooldown after the command has ran just in case there are issues
create_or_update_cooldown unless skipped_actions.cooldown?
end
result
end
end
end
end
end