Class: Discordrb::Bot
Overview
Represents a Discord bot, including servers, users, etc.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#bot_user ⇒ User
readonly
The user that represents the bot itself.
-
#event_threads ⇒ Array<Thread>
readonly
The list of currently running threads used to parse and call events.
-
#profile ⇒ Profile
readonly
The bot's user profile.
-
#servers ⇒ Array<Server>
readonly
The list of servers the bot is currently in.
-
#should_parse_self ⇒ Object
Whether or not the bot should parse its own messages.
-
#token ⇒ String
readonly
The Discord API token received when logging in.
-
#users ⇒ Array<User>
readonly
The list of users the bot shares a server with.
Instance Method Summary collapse
-
#add_await(key, type, attributes = {}) {|event| ... } ⇒ Await
Add an await the bot should listen to.
- #add_handler(handler) ⇒ Object (also: #<<)
-
#await(attributes = {}) {|event| ... } ⇒ AwaitEventHandler
This event is raised when an Await is triggered.
-
#channel(id) ⇒ Channel
Gets a channel given its ID.
-
#channel_create(attributes = {}, &block) ⇒ Object
Handle channel creation Attributes: * type: Channel type ('text' or 'voice') * name: Channel name.
-
#channel_delete(attributes = {}, &block) ⇒ Object
Handle channel deletion Attributes: * type: Channel type ('text' or 'voice') * name: Channel name.
-
#channel_update(attributes = {}, &block) ⇒ Object
Handle channel update Attributes: * type: Channel type ('text' or 'voice') * name: Channel name.
-
#create_server(name, region = :london) ⇒ Server
Creates a server on Discord with a specified name and a region.
- #debug(message, important = false) ⇒ Object
-
#debug=(new_debug) ⇒ Object
Sets debug mode.
-
#delete_invite(code) ⇒ Object
Revokes an invite to a server.
- #disconnected(attributes = {}, &block) ⇒ Object
-
#find(channel_name, server_name = nil, threshold = 0) ⇒ Array<Channel>
Finds a channel given its name and optionally the name of the server it is in.
-
#find_user(username, threshold = 0) ⇒ Array<User>
Finds a user given its username.
-
#game=(name_or_id) ⇒ Game
Sets the currently playing game to the specified game.
- #handler_class(event_class) ⇒ Object
-
#initialize(email, password, debug = false) ⇒ Bot
constructor
Makes a new bot with the given email and password.
-
#join(invite) ⇒ Object
Makes the bot join an invite to a server.
- #log_exception(e) ⇒ Object
- #member_join(attributes = {}, &block) ⇒ Object
- #member_leave(attributes = {}, &block) ⇒ Object
- #member_update(attributes = {}, &block) ⇒ Object
- #mention(attributes = {}, &block) ⇒ Object
-
#message(attributes = {}) {|event| ... } ⇒ MessageEventHandler
This event is raised when a message is sent to a text channel the bot is currently in.
-
#parse_mention(mention) ⇒ User
Gets the user from a mention of the user.
- #pm(attributes = {}, &block) ⇒ Object (also: #private_message)
- #presence(attributes = {}, &block) ⇒ Object
-
#private_channel(id) ⇒ Channel
Creates a private channel for the given user ID, or if one exists already, returns that one.
- #ready(attributes = {}, &block) ⇒ Object
- #remove_handler(handler) ⇒ Object
-
#resolve_invite_code(invite) ⇒ String
Gets the code for an invite.
-
#run(async = false) ⇒ Object
Runs the bot, which logs into Discord and connects the WebSocket.
- #run_async ⇒ Object
-
#send_file(channel_id, file) ⇒ Object
Sends a file to a channel.
-
#send_message(channel_id, content) ⇒ Message
Sends a text message to a channel given its ID and the message's content.
-
#server(id) ⇒ Server?
Gets a server by its ID.
- #server_create(attributes = {}, &block) ⇒ Object
- #server_delete(attributes = {}, &block) ⇒ Object
- #server_update(attributes = {}, &block) ⇒ Object
-
#stop ⇒ Object
Kills the websocket thread, stopping all connections to Discord.
-
#sync ⇒ Object
Prevents all further execution until the websocket thread stops (e. g. through a closed connection).
- #typing(attributes = {}, &block) ⇒ Object
-
#user(id) ⇒ User?
Gets a user by its ID.
-
#voice_state_update(attributes = {}, &block) ⇒ Object
Handle a change to a voice state.
Methods included from Events
Constructor Details
#initialize(email, password, debug = false) ⇒ Bot
Makes a new bot with the given email and password. It will be ready to be added event handlers to and can eventually be run with #run.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/discordrb/bot.rb', line 68 def initialize(email, password, debug = false) # Make sure people replace the login details in the example files... if email.end_with? 'example.com' puts 'You have to replace the login details in the example files with your own!' exit end LOGGER.debug = debug @should_parse_self = false @email = email @password = password @token = login @event_handlers = {} @channels = {} @users = {} @awaits = {} @event_threads = [] @current_thread = 0 end |
Instance Attribute Details
#bot_user ⇒ User (readonly)
The user that represents the bot itself. This version will always be identical to the user determined by #user called with the bot's ID.
34 35 36 |
# File 'lib/discordrb/bot.rb', line 34 def bot_user @bot_user end |
#event_threads ⇒ Array<Thread> (readonly)
The list of currently running threads used to parse and call events.
The threads will have a local variable :discordrb_name in the format of et-1234, where
"et" stands for "event thread" and the number is a continually incrementing number representing
how many events were executed before.
54 55 56 |
# File 'lib/discordrb/bot.rb', line 54 def event_threads @event_threads end |
#profile ⇒ Profile (readonly)
The bot's user profile. This special user object can be used to edit user data like the current username (see Profile#username=).
59 60 61 |
# File 'lib/discordrb/bot.rb', line 59 def profile @profile end |
#servers ⇒ Array<Server> (readonly)
The list of servers the bot is currently in.
47 48 49 |
# File 'lib/discordrb/bot.rb', line 47 def servers @servers end |
#should_parse_self ⇒ Object
Whether or not the bot should parse its own messages. Off by default.
62 63 64 |
# File 'lib/discordrb/bot.rb', line 62 def should_parse_self @should_parse_self end |
#token ⇒ String (readonly)
The Discord API token received when logging in. Useful to explicitly call API methods.
39 40 41 |
# File 'lib/discordrb/bot.rb', line 39 def token @token end |
#users ⇒ Array<User> (readonly)
The list of users the bot shares a server with.
43 44 45 |
# File 'lib/discordrb/bot.rb', line 43 def users @users end |
Instance Method Details
#add_await(key, type, attributes = {}) {|event| ... } ⇒ Await
Add an await the bot should listen to. For information on awaits, see Await.
311 312 313 314 315 |
# File 'lib/discordrb/bot.rb', line 311 def add_await(key, type, attributes = {}, &block) fail "You can't await an AwaitEvent!" if type == Discordrb::Events::AwaitEvent await = Await.new(self, key, type, attributes, block) @awaits[key] = await end |
#add_handler(handler) ⇒ Object Also known as: <<
504 505 506 507 |
# File 'lib/discordrb/bot.rb', line 504 def add_handler(handler) clazz = event_class(handler.class) @event_handlers[clazz] << handler end |
#await(attributes = {}) {|event| ... } ⇒ AwaitEventHandler
This event is raised when an Await is triggered. It provides an easy way to execute code on an await without having to rely on the await's block.
489 490 491 |
# File 'lib/discordrb/bot.rb', line 489 def await(attributes = {}, &block) register_event(AwaitEvent, attributes, block) end |
#channel(id) ⇒ 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.
150 151 152 153 154 155 156 157 |
# File 'lib/discordrb/bot.rb', line 150 def channel(id) debug("Obtaining data for channel with id #{id}") return @channels[id] if @channels[id] response = API.channel(@token, id) channel = Channel.new(JSON.parse(response), self) @channels[id] = channel end |
#channel_create(attributes = {}, &block) ⇒ Object
Handle channel creation Attributes:
- type: Channel type ('text' or 'voice')
- name: Channel name
424 425 426 |
# File 'lib/discordrb/bot.rb', line 424 def channel_create(attributes = {}, &block) register_event(ChannelCreateEvent, attributes, block) end |
#channel_delete(attributes = {}, &block) ⇒ Object
Handle channel deletion Attributes:
- type: Channel type ('text' or 'voice')
- name: Channel name
440 441 442 |
# File 'lib/discordrb/bot.rb', line 440 def channel_delete(attributes = {}, &block) register_event(ChannelDeleteEvent, attributes, block) end |
#channel_update(attributes = {}, &block) ⇒ Object
Handle channel update Attributes:
- type: Channel type ('text' or 'voice')
- name: Channel name
432 433 434 |
# File 'lib/discordrb/bot.rb', line 432 def channel_update(attributes = {}, &block) register_event(ChannelUpdateEvent, attributes, block) end |
#create_server(name, region = :london) ⇒ Server
Discord's API doesn't directly return the server when creating it, so this method waits until the data has been received via the websocket. This may make the execution take a while.
Creates a server on Discord with a specified name and a region.
331 332 333 334 335 336 337 338 |
# File 'lib/discordrb/bot.rb', line 331 def create_server(name, region = :london) response = API.create_server(@token, name, region) id = JSON.parse(response)['id'].to_i sleep 0.1 until @servers[id] server = @servers[id] debug "Successfully created server #{server.id} with name #{server.name}" server end |
#debug(message, important = false) ⇒ Object
509 510 511 |
# File 'lib/discordrb/bot.rb', line 509 def debug(, important = false) LOGGER.debug(, important) end |
#debug=(new_debug) ⇒ Object
Sets debug mode. If debug mode is on, many things will be outputted to STDOUT.
369 370 371 |
# File 'lib/discordrb/bot.rb', line 369 def debug=(new_debug) LOGGER.debug = new_debug end |
#delete_invite(code) ⇒ Object
Revokes an invite to a server. Will fail unless you have the Manage Server permission. It is recommended that you use Invite#delete instead.
199 200 201 202 |
# File 'lib/discordrb/bot.rb', line 199 def delete_invite(code) invite = resolve_invite_code(code) API.delete_invite(@token, invite) end |
#disconnected(attributes = {}, &block) ⇒ Object
404 405 406 |
# File 'lib/discordrb/bot.rb', line 404 def disconnected(attributes = {}, &block) register_event(DisconnectEvent, attributes, block) end |
#find(channel_name, server_name = nil, threshold = 0) ⇒ Array<Channel>
Finds a channel given its name and optionally the name of the server it is in. If the threshold is not 0, it will use a Levenshtein distance function to find the channel in a fuzzy way, which allows slight misspellings.
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/discordrb/bot.rb', line 228 def find(channel_name, server_name = nil, threshold = 0) require 'levenshtein' results = [] @servers.values.each do |server| server.channels.each do |channel| distance = Levenshtein.distance(channel.name, channel_name) distance += Levenshtein.distance(server_name || server.name, server.name) next if distance > threshold # Make a singleton accessor "distance" channel.instance_variable_set(:@distance, distance) class << channel attr_reader :distance end results << channel end end results end |
#find_user(username, threshold = 0) ⇒ Array<User>
Finds a user given its username. This allows fuzzy finding using Levenshtein distances, see #find
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/discordrb/bot.rb', line 255 def find_user(username, threshold = 0) require 'levenshtein' results = [] @users.values.each do |user| distance = Levenshtein.distance(user.username, username) next if distance > threshold # Make a singleton accessor "distance" user.instance_variable_set(:@distance, distance) class << user attr_reader :distance end results << user end results end |
#game=(name_or_id) ⇒ Game
Sets the currently playing game to the specified game.
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/discordrb/bot.rb', line 352 def game=(name_or_id) game = Discordrb::Games.find_game(name_or_id) @game = game data = { 'op' => 3, 'd' => { 'idle_since' => nil, 'game_id' => game ? game.id : 60 # 60 blanks out the game playing } } @ws.send(data.to_json) game end |
#handler_class(event_class) ⇒ Object
517 518 519 |
# File 'lib/discordrb/bot.rb', line 517 def handler_class(event_class) class_from_string(event_class.to_s + 'Handler') end |
#join(invite) ⇒ Object
Makes the bot join an invite to a server.
190 191 192 193 194 |
# File 'lib/discordrb/bot.rb', line 190 def join(invite) invite = resolve_invite_code(invite) resolved = JSON.parse(API.resolve_invite(@token, invite))['code'] API.join_server(@token, resolved) end |
#log_exception(e) ⇒ Object
513 514 515 |
# File 'lib/discordrb/bot.rb', line 513 def log_exception(e) LOGGER.log_exception(e) end |
#member_join(attributes = {}, &block) ⇒ Object
457 458 459 |
# File 'lib/discordrb/bot.rb', line 457 def member_join(attributes = {}, &block) register_event(GuildMemberAddEvent, attributes, block) end |
#member_leave(attributes = {}, &block) ⇒ Object
465 466 467 |
# File 'lib/discordrb/bot.rb', line 465 def member_leave(attributes = {}, &block) register_event(GuildMemberDeleteEvent, attributes, block) end |
#member_update(attributes = {}, &block) ⇒ Object
461 462 463 |
# File 'lib/discordrb/bot.rb', line 461 def member_update(attributes = {}, &block) register_event(GuildMemberUpdateEvent, attributes, block) end |
#mention(attributes = {}, &block) ⇒ Object
416 417 418 |
# File 'lib/discordrb/bot.rb', line 416 def mention(attributes = {}, &block) register_event(MentionEvent, attributes, block) end |
#message(attributes = {}) {|event| ... } ⇒ MessageEventHandler
This event is raised when a message is sent to a text channel the bot is currently in.
396 397 398 |
# File 'lib/discordrb/bot.rb', line 396 def (attributes = {}, &block) register_event(MessageEvent, attributes, block) end |
#parse_mention(mention) ⇒ User
Gets the user from a mention of the user.
343 344 345 346 347 |
# File 'lib/discordrb/bot.rb', line 343 def parse_mention(mention) # Mention format: <@id> return nil unless /\<@(?<id>\d+)\>?/ =~ mention user(id) end |
#pm(attributes = {}, &block) ⇒ Object Also known as: private_message
493 494 495 |
# File 'lib/discordrb/bot.rb', line 493 def pm(attributes = {}, &block) register_event(PrivateMessageEvent, attributes, block) end |
#presence(attributes = {}, &block) ⇒ Object
412 413 414 |
# File 'lib/discordrb/bot.rb', line 412 def presence(attributes = {}, &block) register_event(PresenceEvent, attributes, block) 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.
164 165 166 167 168 169 170 171 |
# File 'lib/discordrb/bot.rb', line 164 def private_channel(id) debug("Creating private channel with user id #{id}") return @private_channels[id] if @private_channels[id] response = API.create_private(@token, @bot_user.id, id) channel = Channel.new(JSON.parse(response), self) @private_channels[id] = channel end |
#ready(attributes = {}, &block) ⇒ Object
400 401 402 |
# File 'lib/discordrb/bot.rb', line 400 def ready(attributes = {}, &block) register_event(ReadyEvent, attributes, block) end |
#remove_handler(handler) ⇒ Object
499 500 501 502 |
# File 'lib/discordrb/bot.rb', line 499 def remove_handler(handler) clazz = event_class(handler.class) @event_handlers[clazz].delete(handler) end |
#resolve_invite_code(invite) ⇒ String
Gets the code for an invite.
182 183 184 185 186 |
# File 'lib/discordrb/bot.rb', line 182 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') || invite.start_with?('discord.gg') invite end |
#run(async = false) ⇒ Object
Runs the bot, which logs into Discord and connects the WebSocket. This prevents all further execution unless it is executed with async = :async.
100 101 102 103 104 105 106 |
# File 'lib/discordrb/bot.rb', line 100 def run(async = false) run_async return if async debug('Oh wait! Not exiting yet as run was run synchronously.') sync end |
#run_async ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/discordrb/bot.rb', line 108 def run_async # Handle heartbeats @heartbeat_interval = 1 @heartbeat_active = false @heartbeat_thread = Thread.new do Thread.current[:discordrb_name] = 'heartbeat' loop do sleep @heartbeat_interval send_heartbeat if @heartbeat_active end end @ws_thread = Thread.new do Thread.current[:discordrb_name] = 'websocket' loop do websocket_connect debug('Disconnected! Attempting to reconnect in 5 seconds.') sleep 5 @token = login end end debug('WS thread created! Now waiting for confirmation that everything worked') @ws_success = false sleep(0.5) until @ws_success debug('Confirmation received! Exiting run.') end |
#send_file(channel_id, file) ⇒ Object
This executes in a blocking way, so if you're sending long files, be wary of delays.
Sends a file to a channel. If it is an image, it will automatically be embedded.
300 301 302 |
# File 'lib/discordrb/bot.rb', line 300 def send_file(channel_id, file) API.send_file(@token, channel_id, file) end |
#send_message(channel_id, content) ⇒ Message
Sends a text message to a channel given its ID and the message's content.
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/discordrb/bot.rb', line 277 def (channel_id, content) debug("Sending message to #{channel_id} with content '#{content}'") # Replace mentions mentions = [] content.gsub!(/<@([0-9]+)>/) do id = Regexp.last_match(1).to_i if @users[id] mentions << id "@#{@users[id].name}" else "<@#{id}}>" end end response = API.(@token, channel_id, content, mentions) Message.new(JSON.parse(response), self) end |
#server(id) ⇒ Server?
This can only resolve servers the bot is currently in.
Gets a server by its ID.
216 217 218 |
# File 'lib/discordrb/bot.rb', line 216 def server(id) @servers[id] end |
#server_create(attributes = {}, &block) ⇒ Object
469 470 471 |
# File 'lib/discordrb/bot.rb', line 469 def server_create(attributes = {}, &block) register_event(GuildCreateEvent, attributes, block) end |
#server_delete(attributes = {}, &block) ⇒ Object
477 478 479 |
# File 'lib/discordrb/bot.rb', line 477 def server_delete(attributes = {}, &block) register_event(GuildDeleteEvent, attributes, block) end |
#server_update(attributes = {}, &block) ⇒ Object
473 474 475 |
# File 'lib/discordrb/bot.rb', line 473 def server_update(attributes = {}, &block) register_event(GuildUpdateEvent, attributes, block) end |
#stop ⇒ Object
Kills the websocket thread, stopping all connections to Discord.
142 143 144 |
# File 'lib/discordrb/bot.rb', line 142 def stop @ws_thread.kill end |
#sync ⇒ Object
Prevents all further execution until the websocket thread stops (e. g. through a closed connection).
137 138 139 |
# File 'lib/discordrb/bot.rb', line 137 def sync @ws_thread.join end |
#typing(attributes = {}, &block) ⇒ Object
408 409 410 |
# File 'lib/discordrb/bot.rb', line 408 def typing(attributes = {}, &block) register_event(TypingEvent, attributes, block) 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.
208 209 210 |
# File 'lib/discordrb/bot.rb', line 208 def user(id) @users[id] end |
#voice_state_update(attributes = {}, &block) ⇒ Object
Handle a change to a voice state. This includes joining a voice channel or changing mute or deaf state. Attributes:
- from: User whose voice state changed
- mute: server mute status
- deaf: server deaf status
- self_mute: self mute status
- self_deaf: self deaf status
- channel: channel the user joined
453 454 455 |
# File 'lib/discordrb/bot.rb', line 453 def voice_state_update(attributes = {}, &block) register_event(VoiceStateUpdateEvent, attributes, block) end |