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

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.

Parameters:

  • id (Integer)

    The channel ID for which to search for.

  • server (Server) (defaults to: nil)

    The server for which to search the channel for. If this isn't specified, it will be inferred using the API

Returns:

  • (Channel)

    The channel identified by the ID.

Raises:



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/discordrb/cache.rb', line 29

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(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.

Parameters:

  • data (Hash)

    A data hash representing a channel.

  • server (Server, nil) (defaults to: nil)

    The server the channel is on, if known.

Returns:

  • (Channel)

    the channel represented by the data hash.



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

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.

Parameters:

  • data (Hash)

    A data hash representing a server.

Returns:

  • (Server)

    the server represented by the data hash.



138
139
140
141
142
143
144
# File 'lib/discordrb/cache.rb', line 138

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.

Parameters:

  • data (Hash)

    A data hash representing a user.

Returns:

  • (User)

    the user represented by the data hash.



127
128
129
130
131
132
133
# File 'lib/discordrb/cache.rb', line 127

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.

Parameters:

  • channel_name (String)

    The channel to search for.

  • server_name (String) (defaults to: nil)

    The server to search for, or nil if only the channel should be searched for.

  • type (String, nil) (defaults to: nil)

    The type of channel to search for ('text' or 'voice'), or nil if either type of channel should be searched for

Returns:

  • (Array<Channel>)

    The array of channels that were found. May be empty if none were found.



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/discordrb/cache.rb', line 201

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>

Finds a user given its username.

Parameters:

  • username (String)

    The username to look for.

Returns:

  • (Array<User>)

    The array of users that were found. May be empty if none were found.



221
222
223
# File 'lib/discordrb/cache.rb', line 221

def find_user(username)
  @users.values.find_all { |e| e.username == username }
end

#init_cacheObject

Initializes this cache



12
13
14
15
16
17
18
19
20
21
# File 'lib/discordrb/cache.rb', line 12

def init_cache
  @users = {}

  @servers = {}

  @channels = {}
  @private_channels = {}

  @restricted_channels = []
end

#invite(invite) ⇒ Invite

Gets information about an invite.

Parameters:

Returns:

  • (Invite)

    The invite with information about the given invite URL.



190
191
192
193
# File 'lib/discordrb/cache.rb', line 190

def invite(invite)
  code = resolve_invite_code(invite)
  Invite.new(JSON.parse(API.resolve_invite(token, code)), self)
end

#member(server_id, user_id) ⇒ Member?

Gets a member by both IDs

Parameters:

  • server_id (Integer)

    The server ID for which a member should be resolved

  • user_id (Integer)

    The ID of the user that should be resolved

Returns:

  • (Member, nil)

    The member identified by the IDs, or nil if none could be found



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

def member(server_id, user_id)
  server_id = server_id.resolve_id
  user_id = user_id.resolve_id

  server = 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.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

#private_channel(id) ⇒ Channel

Creates a private 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.

Parameters:

  • id (Integer)

    The user ID to generate a private channel for.

Returns:

  • (Channel)

    A private channel for that user.



114
115
116
117
118
119
120
121
122
# File 'lib/discordrb/cache.rb', line 114

def private_channel(id)
  id = id.resolve_id
  debug("Creating private channel with user id #{id}")
  return @private_channels[id] if @private_channels[id]

  response = API.create_private(token, @profile.id, id)
  channel = Channel.new(JSON.parse(response), self)
  @private_channels[id] = channel
end

#request_chunks(id) ⇒ Object

Requests member chunks for a given server ID.

Parameters:

  • id (Integer)

    The server ID to request chunks for.



160
161
162
163
164
165
166
167
168
169
170
# File 'lib/discordrb/cache.rb', line 160

def request_chunks(id)
  chunk_packet = {
    op: 8,
    d: {
      guild_id: id,
      query: '',
      limit: 0
    }
  }.to_json
  @ws.send(chunk_packet)
end

#resolve_invite_code(invite) ⇒ String

Gets the code for an invite.

Parameters:

  • 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://discordapp.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)

Returns:

  • (String)

    Only the code for the invite.



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

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.

Parameters:

  • id (Integer)

    The server ID that should be resolved.

Returns:

  • (Server, nil)

    The server identified by the ID, or nil if it couldn't be found.



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

def server(id)
  id = id.resolve_id
  return @servers[id] if @servers[id]

  LOGGER.out("Resolving server #{id}")
  begin
    response = API.server(token, id)
  rescue RestClient::ResourceNotFound
    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.

Parameters:

  • id (Integer)

    The user ID that should be resolved.

Returns:

  • (User, nil)

    The user identified by the ID, or nil if it couldn't be found.



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/discordrb/cache.rb', line 56

def user(id)
  id = id.resolve_id
  return @users[id] if @users[id]

  LOGGER.out("Resolving user #{id}")
  begin
    response = API.user(token, id)
  rescue RestClient::ResourceNotFound
    return nil
  end
  user = User.new(JSON.parse(response), self)
  @users[id] = user
end