Module: Discordrb::Cache

Included in:
Bot
Defined in:
lib/discordrb/cache.rb

Overview

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.

Instance Method Summary collapse

Instance Method Details

#channel(id, server = nil) ⇒ Channel Also known as: group_channel

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.


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/discordrb/cache.rb', line 46

def channel(id, server = nil)
  id = id.resolve_id

  raise Discordrb::Errors::NoPermission if @restricted_channels.include? id

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

  begin
    begin
      response = API::Channel.resolve(token, id)
    rescue RestClient::ResourceNotFound
      return nil
    end
    channel = Channel.new(JSON.parse(response), self, server)
    @channels[id] = channel
  rescue Discordrb::Errors::NoPermission
    debug "Tried to get access to restricted channel #{id}, blacklisting it"
    @restricted_channels << id
    raise
  end
end

#ensure_channel(data, server = nil) ⇒ Channel

Ensures a given channel object is cached and if not, cache it from the given data hash.


171
172
173
174
175
176
177
# File 'lib/discordrb/cache.rb', line 171

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) ⇒ Server

Ensures a given server object is cached and if not, cache it from the given data hash.


159
160
161
162
163
164
165
# File 'lib/discordrb/cache.rb', line 159

def ensure_server(data)
  if @servers.include?(data['id'].to_i)
    @servers[data['id'].to_i]
  else
    @servers[data['id'].to_i] = Server.new(data, self)
  end
end

#ensure_user(data) ⇒ User

Ensures a given user object is cached and if not, cache it from the given data hash.


148
149
150
151
152
153
154
# File 'lib/discordrb/cache.rb', line 148

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) ⇒ Array<Channel>

Finds a channel given its name and optionally the name of the server it is in.


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/discordrb/cache.rb', line 214

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.values.each 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) ⇒ Array<User> #find_user(username, discrim) ⇒ User?

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.

Finds a user given its username or username & discriminator.

Examples:

Find users by name

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

Find a user by name and discriminator

bot.find_user('z64', '2639') #=> User

Overloads:

  • #find_user(username) ⇒ Array<User>

    Find all cached users with a certain username.

  • #find_user(username, discrim) ⇒ User?

    Find a cached user with a certain username and discriminator. Find a user by name and discriminator


248
249
250
251
252
# File 'lib/discordrb/cache.rb', line 248

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

#init_cacheObject

Initializes this cache


15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/discordrb/cache.rb', line 15

def init_cache
  @users = {}

  @voice_regions = {}

  @servers = {}

  @channels = {}
  @pm_channels = {}

  @restricted_channels = []
end

#invite(invite) ⇒ Invite

Gets information about an invite.


203
204
205
206
# File 'lib/discordrb/cache.rb', line 203

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) ⇒ Member?

Gets a member by both IDs, or Server and user ID.


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/discordrb/cache.rb', line 111

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 RestClient::ResourceNotFound
    return nil
  end
  member = Member.new(JSON.parse(response), server, self)
  server.cache_member(member)
end

#pm_channel(id) ⇒ Channel Also known as: private_channel

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.


134
135
136
137
138
139
140
141
# File 'lib/discordrb/cache.rb', line 134

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

#request_chunks(id) ⇒ Object

Requests member chunks for a given server ID.


181
182
183
# File 'lib/discordrb/cache.rb', line 181

def request_chunks(id)
  @gateway.send_request_members(id, '', 0)
end

#resolve_invite_code(invite) ⇒ String

Gets the code for an invite.


194
195
196
197
198
# File 'lib/discordrb/cache.rb', line 194

def resolve_invite_code(invite)
  invite = invite.code if invite.is_a? Discordrb::Invite
  invite = invite[invite.rindex('/') + 1..-1] if invite.start_with?('http', 'discord.gg')
  invite
end

#server(id) ⇒ Server?

Note:

This can only resolve servers the bot is currently in.

Gets a server by its ID.


93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/discordrb/cache.rb', line 93

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) ⇒ User?

Note:

This can only resolve users known by the bot (i.e. that share a server with the bot).

Gets a user by its ID.


75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/discordrb/cache.rb', line 75

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 RestClient::ResourceNotFound
    return nil
  end
  user = User.new(JSON.parse(response), self)
  @users[id] = user
end

#voice_regionsObject

Returns or caches the available voice regions


29
30
31
32
33
34
35
36
37
38
# File 'lib/discordrb/cache.rb', line 29

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