class Discorb::Client
Class for connecting to the Discord server.
Attributes
@return [Discorb::AllowedMentions] The allowed mentions that the client is using.
@return [Integer] The API version of the Discord gateway. @return [nil] If not connected to the gateway.
@return [Discorb::Application] The application that the client is using. @return [nil] If never fetched application by {#fetch_application}.
@private
@return [Discorb::Dictionary{Discorb::Snowflake => Discorb::Channel}] A dictionary of channels.
@return [Array<Discorb::Command::Command>] The commands that the client is using.
@return [Discorb::Dictionary{Discorb::Snowflake => Discorb::Emoji}] A dictionary of emojis.
@return [Discorb::Dictionary{Discorb::Snowflake => Discorb::Guild}] A dictionary of guilds.
@return [Integer] The heartbeat interval.
@return [Discorb::HTTP] The http client.
@return [Discorb::Intents] The intents that the client is currently using.
@return [Discorb::Logger] The logger.
@return [Discorb::Dictionary{Discorb::Snowflake => Discorb::Message}] A dictionary of messages.
@return [Float] The ping of the client.
@note This will be calculated from heartbeat and heartbeat_ack.
@return [nil] If not connected to the gateway.
@return [Integer] The session ID of connection.
@return [:initialized, :running, :closed] The status of the client.
@return [String] The token of the client.
@return [Discorb::ClientUser] The client user.
@return [Discorb::Dictionary{Discorb::Snowflake => Discorb::User}] A dictionary of users.
Public Class Methods
Initializes a new client.
@param [Discorb::AllowedMentions] allowed_mentions
The allowed mentions that the client is using. @param [Discorb::Intents] intents The intents that the client is currently using. @param [Integer] message_caches The number of messages to cache. @param [#puts] log The IO object to use for logging. @param [Boolean] colorize_log Whether to colorize the log. @param [:debug, :info, :warn, :error, :critical] log_level The log level. @param [Boolean] wait_until_ready Whether to delay event dispatch until ready.
# File lib/discorb/client.rb, line 68 def initialize( allowed_mentions: nil, intents: nil, message_caches: 1000, log: nil, colorize_log: false, log_level: :info, wait_until_ready: true ) @allowed_mentions = allowed_mentions || AllowedMentions.new(everyone: true, roles: true, users: true) @intents = (intents or Intents.default) @events = {} @api_version = nil @log = Logger.new(log, colorize_log, log_level) @user = nil @users = Discorb::Dictionary.new @channels = Discorb::Dictionary.new @guilds = Discorb::Dictionary.new(sort: ->(k) { k[0].to_i }) @emojis = Discorb::Dictionary.new @messages = Discorb::Dictionary.new(limit: message_caches) @application = nil @last_s = nil @identify_presence = nil @wait_until_ready = wait_until_ready @ready = false @tasks = [] @conditions = {} @commands = [] @bottom_commands = [] @status = :initialized end
Public Instance Methods
Stops the client.
# File lib/discorb/client.rb, line 446 def close! @connection.send_close @tasks.each(&:stop) @status = :closed @close_condition.signal end
Dispatch an event.
@param [Symbol] event_name The name of the event. @param [Object] args The arguments to pass to the event.
# File lib/discorb/client.rb, line 145 def dispatch(event_name, *args) Async do if (conditions = @conditions[event_name]) ids = Set[*conditions.map(&:first).map(&:object_id)] conditions.delete_if do |condition| next unless ids.include?(condition.first.object_id) check_result = condition[1].nil? || condition[1].call(*args) if check_result condition.first.signal(args) true else false end end end events = @events[event_name].dup || [] if respond_to?("on_" + event_name.to_s) event_method = method("on_" + event_name.to_s) class << event_method def id "method" end end events << event_method end if events.nil? @log.debug "Event #{event_name} doesn't have any proc, skipping" next end @log.debug "Dispatching event #{event_name}" events.each do |block| lambda { |event_args| Async(annotation: "Discorb event: #{event_name}") do |task| if block.is_a?(Discorb::Event) @events[event_name].delete(block) if block.discriminator[:once] end block.call(*event_args) @log.debug "Dispatched proc with ID #{block.id.inspect}" rescue StandardError, ScriptError => e message = "An error occurred while dispatching proc with ID #{block.id.inspect}\n#{e.full_message}" dispatch(:error, event_name, event_args, e) if @log.out @log.error message else warn message end end }.call(args) end end end
Method to wait for a event.
@param [Symbol] event The name of the event. @param [Integer] timeout The timeout in seconds. @param [Proc] check The check to use.
@return [Object] The result of the event.
@raise [Discorb::TimeoutError] If the event didn't occur in time.
# File lib/discorb/client.rb, line 338 def event_lock(event, timeout = nil, &check) Async do |task| condition = Async::Condition.new @conditions[event] ||= [] @conditions[event] << [condition, check] if timeout.nil? value = condition.wait else timeout_task = task.with_timeout(timeout) do condition.wait rescue Async::TimeoutError @conditions[event].delete_if { |c| c.first == condition } raise Discorb::TimeoutError, "Timeout waiting for event #{event}", cause: nil end value = timeout_task end value.length <= 1 ? value.first : value end end
Load the extension.
@param [Module] mod The extension to load.
# File lib/discorb/client.rb, line 369 def extend(mod) if mod.respond_to?(:events) @events.each_value do |event| event.delete_if { |c| c.discriminator[:extension] == mod.name } end mod.events.each do |name, events| @events[name] = [] if @events[name].nil? events.each do |event| @events[name] << event end end @commands.delete_if do |cmd| cmd.respond_to? :extension and cmd.extension == mod.name end mod.commands.each do |cmd| cmd.define_singleton_method(:extension) { mod.name } @commands << cmd end @bottom_commands += mod.bottom_commands mod.client = self end super(mod) end
Fetch webhook from ID. If application was cached, it will be used. @macro async @macro http
@param [Boolean] force Whether to force the fetch.
@return [Discorb::Application] The application.
# File lib/discorb/client.rb, line 280 def fetch_application(force: false) Async do next @application if @application && !force _resp, data = http.get("/oauth2/applications/@me").wait @application = Application.new(self, data) @application end end
Fetch channel from ID. @macro async @macro http
@param [#to_s] id The ID of the channel.
@return [Discorb::Channel] The channel.
@raise [Discorb::NotFoundError] If the channel doesn't exist.
# File lib/discorb/client.rb, line 227 def fetch_channel(id) Async do _resp, data = http.get("/channels/#{id}").wait Channel.make_channel(self, data) end end
Fetch guild from ID. @macro async @macro http
@param [#to_s] id <description>
@return [Discorb::Guild] The guild.
@raise [Discorb::NotFoundError] If the guild doesn't exist.
# File lib/discorb/client.rb, line 245 def fetch_guild(id) Async do _resp, data = http.get("/guilds/#{id}").wait Guild.new(self, data, false) end end
Fetch invite from code. @macro async @macro http
@param [String] code The code of the invite. @param [Boolean] with_count Whether to include the count of the invite. @param [Boolean] with_expiration Whether to include the expiration of the invite.
@return [Discorb::Invite] The invite.
# File lib/discorb/client.rb, line 263 def fetch_invite(code, with_count: false, with_expiration: false) Async do _resp, data = http.get("/invites/#{code}?with_count=#{with_count}&with_expiration=#{with_expiration}").wait Invite.new(self, data, false) end end
Fetch nitro sticker pack from ID. @macro async @macro http
@return [Array<Discorb::Sticker::Pack>] The packs.
# File lib/discorb/client.rb, line 297 def fetch_nitro_sticker_packs Async do _resp, data = http.get("/stickers-packs").wait data.map { |pack| Sticker::Pack.new(self, pack) } end end
Fetch user from ID. @macro async @macro http
@param [#to_s] id <description>
@return [Discorb::User] The user.
@raise [Discorb::NotFoundError] If the user doesn't exist.
# File lib/discorb/client.rb, line 209 def fetch_user(id) Async do _resp, data = http.get("/users/#{id}").wait User.new(self, data) end end
# File lib/discorb/client.rb, line 360 def inspect "#<#{self.class} user=\"#{user}\">" end
Registers an event handler. @see file:docs/Events.md
@param [Symbol] event_name The name of the event. @param [Symbol] id Custom ID of the event. @param [Hash] discriminator The discriminator of the event. @param [Proc] block The block to execute when the event is triggered.
@return [Discorb::Event] The event.
# File lib/discorb/client.rb, line 107 def on(event_name, id: nil, **discriminator, &block) ne = Event.new(block, id, discriminator) @events[event_name] ||= [] @events[event_name] << ne ne end
Almost same as {#on}, but only triggers the event once.
@param (see on
)
@return [Discorb::Event] The event.
# File lib/discorb/client.rb, line 121 def once(event_name, id: nil, **discriminator, &block) discriminator[:once] = true ne = Event.new(block, id, discriminator) @events[event_name] ||= [] @events[event_name] << ne ne end
Remove event by ID.
@param [Symbol] event_name The name of the event. @param [Symbol] id The ID of the event.
# File lib/discorb/client.rb, line 135 def remove_event(event_name, id) @events[event_name].delete_if { |e| e.id == id } end
Starts the client. @note This method behavior will change by CLI. @see file:docs/cli.md
@param [String] token The token to use.
# File lib/discorb/client.rb, line 403 def run(token) case ENV["DISCORB_CLI_FLAG"] when nil start_client(token) when "run" require "json" options = JSON.parse(ENV["DISCORB_CLI_OPTIONS"], symbolize_names: true) Process.daemon if options[:daemon] setup_commands(token) if options[:setup] if options[:log_level] if options[:log_level] == "none" @log.out = nil else @log.out = case options[:log_file] when nil, "stderr" $stderr when "stdout" $stdout else ::File.open(options[:log_file], "a") end @log.level = options[:log_level].to_sym @log.colorize_log = case options[:log_color] when nil if @log.out == $stdout || @log.out == $stderr true else false end when true, false options[:log_color] end end end start_client(token) when "setup" setup_commands(token) end end
Update presence of the client.
@param [Discorb::Activity] activity The activity to update. @param [:online, :idle, :dnd, :invisible] status The status to update.
# File lib/discorb/client.rb, line 310 def update_presence(activity = nil, status: nil) payload = {} if !activity.nil? payload[:activities] = [activity.to_hash] end payload[:status] = status unless status.nil? if @connection Async do send_gateway(3, **payload) end else @identify_presence = payload end end
Private Instance Methods
# File lib/discorb/client.rb, line 455 def start_client(token) Async do |task| trap(:SIGINT) { @log.info "SIGINT received, closing..." close! } @token = token.to_s @close_condition = Async::Condition.new @main_task = Async do @status = :running connect_gateway(true).wait rescue @status = :stopped @close_condition.signal raise end @close_condition.wait @main_task.stop end end