Module: OnyxCord::Cache
- Includes:
- Stores::Gateway
- Included in:
- Bot
- Defined in:
- lib/onyxcord/cache/manager.rb,
lib/onyxcord/cache/stores/gateway.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.
Defined Under Namespace
Modules: Stores
Constant Summary collapse
- CACHE_STORES =
{ users: :@users, voice_regions: :@voice_regions, servers: :@servers, channels: :@channels, pm_channels: :@pm_channels, thread_members: :@thread_members, server_previews: :@server_previews, request_members: :@request_members_rl }.freeze
Instance Method Summary collapse
- #cache_enabled?(key) ⇒ Boolean
- #cache_stats ⇒ Object
-
#channel(id, server = nil) ⇒ Channel?
(also: #group_channel)
Gets a channel given its ID.
-
#ensure_channel(data, server = nil) ⇒ Channel
Ensures a given channel object is cached and if not, cache it from the given data hash.
-
#ensure_server(data, force_cache = false) ⇒ Server
Ensures a given server object is cached and if not, cache it from the given data hash.
-
#ensure_thread_member(data) ⇒ Object
Ensures a given thread member object is cached.
-
#ensure_user(data) ⇒ User
Ensures a given user object is cached and if not, cache it from the given data hash.
- #fetch_voice_regions ⇒ Object
-
#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.
-
#find_user(username, discrim = nil) ⇒ Object
Finds a user given its username or username & discriminator.
-
#init_cache ⇒ Object
Initializes this cache.
-
#invite(invite) ⇒ Invite
Gets information about an invite.
-
#member(server_or_id, user_id) ⇒ Member?
Gets a member by both IDs, or
Serverand user ID. -
#pm_channel(id) ⇒ Channel
(also: #private_channel)
Creates a PM channel for the given user ID, or if one exists already, returns that one.
- #prune_cache!(*keys) ⇒ Object
-
#request_chunks(id) ⇒ Object
Requests member chunks for a given server ID.
-
#resolve_invite_code(invite) ⇒ String
Gets the code for an invite.
-
#server(id) ⇒ Server?
Gets a server by its ID.
-
#server_preview(id) ⇒ ServerPreview?
Get a server preview.
-
#user(id) ⇒ User?
Gets a user by its ID.
-
#voice_regions ⇒ Object
Returns or caches the available voice regions.
Instance Method Details
#cache_enabled?(key) ⇒ Boolean
41 42 43 |
# File 'lib/onyxcord/cache/manager.rb', line 41 def cache_enabled?(key) @cache_policy.fetch(key, true) end |
#cache_stats ⇒ Object
45 46 47 48 49 50 |
# File 'lib/onyxcord/cache/manager.rb', line 45 def cache_stats CACHE_STORES.each_with_object({}) do |(key, ivar), stats| store = instance_variable_get(ivar) stats[key] = store.respond_to?(:count) ? store.count : 0 end end |
#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.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/onyxcord/cache/manager.rb', line 91 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 = REST::Channel.resolve(token, id) rescue OnyxCord::Errors::UnknownChannel return nil end channel = Channel.new(OnyxCord::Internal::JSON.parse(response), self, server) @channels[id] = channel if cache_enabled?(:channels) channel end |
#ensure_channel(data, server = nil) ⇒ Channel
Ensures a given channel object is cached and if not, cache it from the given data hash.
237 238 239 240 241 242 243 244 245 246 |
# File 'lib/onyxcord/cache/manager.rb', line 237 def ensure_channel(data, server = nil) return Channel.new(data, self, server) unless cache_enabled?(:channels) @channels ||= {} 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) ⇒ Server
Ensures a given server object is cached and if not, cache it from the given data hash.
220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/onyxcord/cache/manager.rb', line 220 def ensure_server(data, force_cache = false) return Server.new(data, self) unless cache_enabled?(:servers) @servers ||= {} 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) ⇒ Object
Ensures a given thread member object is cached.
250 251 252 253 254 255 256 257 258 259 |
# File 'lib/onyxcord/cache/manager.rb', line 250 def ensure_thread_member(data) return unless cache_enabled?(:thread_members) thread_id = data['id'].to_i user_id = data['user_id'].to_i @thread_members ||= {} @thread_members[thread_id] ||= {} @thread_members[thread_id][user_id] = data.slice('join_timestamp', 'flags') end |
#ensure_user(data) ⇒ User
Ensures a given user object is cached and if not, cache it from the given data hash.
204 205 206 207 208 209 210 211 212 213 |
# File 'lib/onyxcord/cache/manager.rb', line 204 def ensure_user(data) return User.new(data, self) unless cache_enabled?(:users) @users ||= {} if @users.include?(data['id'].to_i) @users[data['id'].to_i] else @users[data['id'].to_i] = User.new(data, self) end end |
#fetch_voice_regions ⇒ Object
73 74 75 76 77 78 79 80 81 82 |
# File 'lib/onyxcord/cache/manager.rb', line 73 def fetch_voice_regions regions_by_id = {} regions = OnyxCord::Internal::JSON.parse REST.voice_regions(token) regions.each do |data| regions_by_id[data['id']] = VoiceRegion.new(data) end regions_by_id 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.
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/onyxcord/cache/manager.rb', line 313 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) ⇒ Array<User> #find_user(username, discrim) ⇒ User?
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.
347 348 349 350 351 352 |
# File 'lib/onyxcord/cache/manager.rb', line 347 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_cache ⇒ Object
Initializes this cache
28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/onyxcord/cache/manager.rb', line 28 def init_cache @cache_policy ||= OnyxCord.configuration.normalize_cache(OnyxCord.configuration.cache) sizes = OnyxCord.configuration.cache_sizes @users = cache_enabled?(:users) ? LruRedux::ThreadSafeCache.new(sizes.users) : nil @voice_regions = cache_enabled?(:voice_regions) ? {} : nil @servers = cache_enabled?(:servers) ? LruRedux::ThreadSafeCache.new(sizes.servers) : nil @channels = cache_enabled?(:channels) ? LruRedux::ThreadSafeCache.new(sizes.channels) : nil @pm_channels = cache_enabled?(:pm_channels) ? LruRedux::ThreadSafeCache.new(sizes.pm_channels) : nil @thread_members = cache_enabled?(:thread_members) ? LruRedux::ThreadSafeCache.new(sizes.thread_members) : nil @server_previews = cache_enabled?(:server_previews) ? LruRedux::ThreadSafeCache.new(sizes.server_previews) : nil end |
#invite(invite) ⇒ Invite
Gets information about an invite.
302 303 304 305 |
# File 'lib/onyxcord/cache/manager.rb', line 302 def invite(invite) code = resolve_invite_code(invite) Invite.new(OnyxCord::Internal::JSON.parse(REST::Invite.resolve(token, code)), self) end |
#member(server_or_id, user_id) ⇒ Member?
Gets a member by both IDs, or Server and user ID.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/onyxcord/cache/manager.rb', line 151 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 = REST::Server.resolve_member(token, server_id, user_id) rescue OnyxCord::Errors::UnknownUser, OnyxCord::Errors::UnknownMember return nil end member = Member.new(OnyxCord::Internal::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.
173 174 175 176 177 178 179 180 181 182 |
# File 'lib/onyxcord/cache/manager.rb', line 173 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 = REST::User.create_pm(token, id) channel = Channel.new(OnyxCord::Internal::JSON.parse(response), self) @pm_channels[id] = channel if cache_enabled?(:pm_channels) channel end |
#prune_cache!(*keys) ⇒ Object
52 53 54 55 56 57 58 59 60 61 |
# File 'lib/onyxcord/cache/manager.rb', line 52 def prune_cache!(*keys) keys = CACHE_STORES.keys if keys.empty? keys.each_with_object({}) do |key, pruned| ivar = CACHE_STORES.fetch(key) store = instance_variable_get(ivar) pruned[key] = store.respond_to?(:count) ? store.count : 0 store&.clear end end |
#request_chunks(id) ⇒ Object
Requests member chunks for a given server ID.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/onyxcord/cache/manager.rb', line 263 def request_chunks(id) id = id.resolve_id bucket = (@request_members_rl[id] ||= { mutex: Mutex.new, time: Time.at(0) }) bucket[:mutex].synchronize do last = bucket[:time] now = Time.now if now < last duration = last - now LOGGER.info("Preemptively locking REQUEST_GUILD_MEMBERS for #{duration} seconds") sleep(duration) end @gateway.send_request_members(id, '', 0) bucket[:time] = (Time.now + 30) end end |
#resolve_invite_code(invite) ⇒ String
Gets the code for an invite.
293 294 295 296 297 |
# File 'lib/onyxcord/cache/manager.rb', line 293 def resolve_invite_code(invite) invite = invite.code if invite.is_a? OnyxCord::Invite invite = invite[(invite.rindex('/') + 1)..] if invite.start_with?('http', 'discord.gg') invite end |
#server(id) ⇒ Server?
This can only resolve servers the bot is currently in.
Gets a server by its ID.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/onyxcord/cache/manager.rb', line 132 def server(id) id = id.resolve_id return @servers[id] if @servers&.[](id) LOGGER.out("Resolving server #{id}") begin response = REST::Server.resolve(token, id) rescue OnyxCord::Errors::NoPermission return nil end server = Server.new(OnyxCord::Internal::JSON.parse(response), self) @servers[id] = server if cache_enabled?(:servers) server end |
#server_preview(id) ⇒ ServerPreview?
Get a server preview. If the bot isn't a member of the server, the server must be discoverable.
189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/onyxcord/cache/manager.rb', line 189 def server_preview(id) id = id.resolve_id return @server_previews[id] if @server_previews&.[](id) response = OnyxCord::Internal::JSON.parse(REST::Server.preview(token, id)) preview = ServerPreview.new(response, self) @server_previews[id] = preview if cache_enabled?(:server_previews) preview rescue StandardError nil end |
#user(id) ⇒ User?
This can only resolve users known by the bot (i.e. that share a server with the bot).
Gets a user by its ID.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/onyxcord/cache/manager.rb', line 113 def user(id) id = id.resolve_id return @users[id] if @users&.[](id) LOGGER.out("Resolving user #{id}") begin response = REST::User.resolve(token, id) rescue OnyxCord::Errors::UnknownUser return nil end user = User.new(OnyxCord::Internal::JSON.parse(response), self) @users[id] = user if cache_enabled?(:users) user end |
#voice_regions ⇒ Object
Returns or caches the available voice regions
64 65 66 67 68 69 70 71 |
# File 'lib/onyxcord/cache/manager.rb', line 64 def voice_regions return fetch_voice_regions unless cache_enabled?(:voice_regions) @voice_regions ||= {} return @voice_regions unless @voice_regions.empty? @voice_regions = fetch_voice_regions end |