module Discordrb::Cache

This mixin module does caching stuff for the library. It conveniently separates the logic behind the caching (like, storing the user hashes or making API calls to retrieve things) from the Bot that actually uses it.

Public Instance Methods

channel(id, server = nil) click to toggle source

Gets a channel given its ID. This queries the internal channel cache, and if the channel doesn’t exist in there, it will get the data from Discord. @param id [Integer] The channel ID for which to search for. @param server [Server] The server for which to search the channel for. If this isn’t specified, it will be

inferred using the API

@return [Channel, nil] The channel identified by the ID. @raise Discordrb::Errors::NoPermission

# File lib/discordrb/cache.rb, line 46
def channel(id, server = nil)
  id = id.resolve_id

  debug("Obtaining data for channel with id #{id}")
  return @channels[id] if @channels[id]

  begin
    response = API::Channel.resolve(token, id)
  rescue Discordrb::Errors::UnknownChannel
    return nil
  end
  channel = Channel.new(JSON.parse(response), self, server)
  @channels[id] = channel
end
Also aliased as: group_channel
ensure_channel(data, server = nil) click to toggle source

Ensures a given channel object is cached and if not, cache it from the given data hash. @param data [Hash] A data hash representing a channel. @param server [Server, nil] The server the channel is on, if known. @return [Channel] the channel represented by the data hash.

# File lib/discordrb/cache.rb, line 167
def ensure_channel(data, server = nil)
  if @channels.include?(data['id'].to_i)
    @channels[data['id'].to_i]
  else
    @channels[data['id'].to_i] = Channel.new(data, self, server)
  end
end
ensure_server(data, force_cache = false) click to toggle source

Ensures a given server object is cached and if not, cache it from the given data hash. @param data [Hash] A data hash representing a server. @param force_cache [true, false] Whether the object in cache should be updated with the given

data if it already exists.

@return [Server] the server represented by the data hash.

# File lib/discordrb/cache.rb, line 153
def ensure_server(data, force_cache = false)
  if @servers.include?(data['id'].to_i)
    server = @servers[data['id'].to_i]
    server.update_data(data) if force_cache
    server
  else
    @servers[data['id'].to_i] = Server.new(data, self)
  end
end
ensure_thread_member(data) click to toggle source

Ensures a given thread member object is cached. @param data [Hash] Thread member data.

# File lib/discordrb/cache.rb, line 177
def ensure_thread_member(data)
  thread_id = data['id'].to_i
  user_id = data['user_id'].to_i

  @thread_members[thread_id] ||= {}
  @thread_members[thread_id][user_id] = data.slice('join_timestamp', 'flags')
end
ensure_user(data) click to toggle source

Ensures a given user object is cached and if not, cache it from the given data hash. @param data [Hash] A data hash representing a user. @return [User] the user represented by the data hash.

# File lib/discordrb/cache.rb, line 140
def ensure_user(data)
  if @users.include?(data['id'].to_i)
    @users[data['id'].to_i]
  else
    @users[data['id'].to_i] = User.new(data, self)
  end
end
find_channel(channel_name, server_name = nil, type: nil) click to toggle source

Finds a channel given its name and optionally the name of the server it is in. @param channel_name [String] The channel to search for. @param server_name [String] The server to search for, or ‘nil` if only the channel should be searched for. @param type [Integer, nil] The type of channel to search for (0: text, 1: private, 2: voice, 3: group), or `nil` if any type of

channel should be searched for

@return [Array<Channel>] The array of channels that were found. May be empty if none were found.

# File lib/discordrb/cache.rb, line 220
def find_channel(channel_name, server_name = nil, type: nil)
  results = []

  if /<#(?<id>\d+)>?/ =~ channel_name
    # Check for channel mentions separately
    return [channel(id)]
  end

  @servers.each_value do |server|
    server.channels.each do |channel|
      results << channel if channel.name == channel_name && (server_name || server.name) == server.name && (!type || (channel.type == type))
    end
  end

  results
end
find_user(username, discrim = nil) click to toggle source

Finds a user given its username or username & discriminator. @overload find_user(username)

Find all cached users with a certain username.
@param username [String] The username to look for.
@return [Array<User>] The array of users that were found. May be empty if none were found.

@overload find_user(username, discrim)

Find a cached user with a certain username and discriminator.
Find a user by name and discriminator
@param username [String] The username to look for.
@param discrim [String] The user's discriminator
@return [User, nil] The user that was found, or `nil` if none was found

@note This method only searches through users that have been cached. Users that have not yet been cached

by the bot but still share a connection with the user (mutual server) will not be found.

@example Find users by name

bot.find_user('z64') #=> Array<User>

@example Find a user by name and discriminator

bot.find_user('z64', '2639') #=> User
# File lib/discordrb/cache.rb, line 254
def find_user(username, discrim = nil)
  users = @users.values.find_all { |e| e.username == username }
  return users.find { |u| u.discrim == discrim } if discrim

  users
end
group_channel(id, server = nil)
Alias for: channel
init_cache() click to toggle source

Initializes this cache

# File lib/discordrb/cache.rb, line 15
def init_cache
  @users = {}

  @voice_regions = {}

  @servers = {}

  @channels = {}
  @pm_channels = {}
  @thread_members = {}
end
invite(invite) click to toggle source

Gets information about an invite. @param invite [String, Invite] The invite to join. For possible formats see {#resolve_invite_code}. @return [Invite] The invite with information about the given invite URL.

# File lib/discordrb/cache.rb, line 209
def invite(invite)
  code = resolve_invite_code(invite)
  Invite.new(JSON.parse(API::Invite.resolve(token, code)), self)
end
member(server_or_id, user_id) click to toggle source

Gets a member by both IDs, or ‘Server` and user ID. @param server_or_id [Server, Integer] The `Server` or server ID for which a member should be resolved @param user_id [Integer] The ID of the user that should be resolved @return [Member, nil] The member identified by the IDs, or `nil` if none could be found

# File lib/discordrb/cache.rb, line 103
def member(server_or_id, user_id)
  server_id = server_or_id.resolve_id
  user_id = user_id.resolve_id
  server = server_or_id.is_a?(Server) ? server_or_id : self.server(server_id)

  return server.member(user_id) if server.member_cached?(user_id)

  LOGGER.out("Resolving member #{server_id} on server #{user_id}")
  begin
    response = API::Server.resolve_member(token, server_id, user_id)
  rescue Discordrb::Errors::UnknownUser, Discordrb::Errors::UnknownMember
    return nil
  end
  member = Member.new(JSON.parse(response), server, self)
  server.cache_member(member)
end
pm_channel(id) click to toggle source

Creates a PM channel for the given user ID, or if one exists already, returns that one. It is recommended that you use {User#pm} instead, as this is mainly for internal use. However, usage of this method may be unavoidable if only the user ID is known. @param id [Integer] The user ID to generate a private channel for. @return [Channel] A private channel for that user.

# File lib/discordrb/cache.rb, line 125
def pm_channel(id)
  id = id.resolve_id
  return @pm_channels[id] if @pm_channels[id]

  debug("Creating pm channel with user id #{id}")
  response = API::User.create_pm(token, id)
  channel = Channel.new(JSON.parse(response), self)
  @pm_channels[id] = channel
end
Also aliased as: private_channel
private_channel(id)
Alias for: pm_channel
request_chunks(id) click to toggle source

Requests member chunks for a given server ID. @param id [Integer] The server ID to request chunks for.

# File lib/discordrb/cache.rb, line 187
def request_chunks(id)
  @gateway.send_request_members(id, '', 0)
end
resolve_invite_code(invite) click to toggle source

Gets the code for an invite. @param invite [String, Invite] The invite to get the code for. Possible formats are:

* An {Invite} object
* The code for an invite
* A fully qualified invite URL (e.g. `https://discord.com/invite/0A37aN7fasF7n83q`)
* A short invite URL with protocol (e.g. `https://discord.gg/0A37aN7fasF7n83q`)
* A short invite URL without protocol (e.g. `discord.gg/0A37aN7fasF7n83q`)

@return [String] Only the code for the invite.

# File lib/discordrb/cache.rb, line 200
def resolve_invite_code(invite)
  invite = invite.code if invite.is_a? Discordrb::Invite
  invite = invite[invite.rindex('/') + 1..] if invite.start_with?('http', 'discord.gg')
  invite
end
server(id) click to toggle source

Gets a server by its ID. @note This can only resolve servers the bot is currently in. @param id [Integer] The server ID that should be resolved. @return [Server, nil] The server identified by the ID, or ‘nil` if it couldn’t be found.

# File lib/discordrb/cache.rb, line 85
def server(id)
  id = id.resolve_id
  return @servers[id] if @servers[id]

  LOGGER.out("Resolving server #{id}")
  begin
    response = API::Server.resolve(token, id)
  rescue Discordrb::Errors::NoPermission
    return nil
  end
  server = Server.new(JSON.parse(response), self)
  @servers[id] = server
end
user(id) click to toggle source

Gets a user by its ID. @note This can only resolve users known by the bot (i.e. that share a server with the bot). @param id [Integer] The user ID that should be resolved. @return [User, nil] The user identified by the ID, or ‘nil` if it couldn’t be found.

# File lib/discordrb/cache.rb, line 67
def user(id)
  id = id.resolve_id
  return @users[id] if @users[id]

  LOGGER.out("Resolving user #{id}")
  begin
    response = API::User.resolve(token, id)
  rescue Discordrb::Errors::UnknownUser
    return nil
  end
  user = User.new(JSON.parse(response), self)
  @users[id] = user
end
voice_regions() click to toggle source

Returns or caches the available voice regions

# File lib/discordrb/cache.rb, line 28
def voice_regions
  return @voice_regions unless @voice_regions.empty?

  regions = JSON.parse API.voice_regions(token)
  regions.each do |data|
    @voice_regions[data['id']] = VoiceRegion.new(data)
  end

  @voice_regions
end