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.
- #debug(message, important = false) ⇒ Object
-
#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.
-
#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.
-
#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 @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 |
#debug(message, important = false) ⇒ Object
470 471 472 |
# File 'lib/discordrb/bot.rb', line 470 def debug(, important = false) puts "[DEBUG : #{Thread.current[:discordrb_name]} @ #{Time.now}] #{message}" if @debug || important 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.
274 275 276 277 278 |
# File 'lib/discordrb/bot.rb', line 274 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: <<
465 466 467 468 |
# File 'lib/discordrb/bot.rb', line 465 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.
450 451 452 |
# File 'lib/discordrb/bot.rb', line 450 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
385 386 387 |
# File 'lib/discordrb/bot.rb', line 385 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
401 402 403 |
# File 'lib/discordrb/bot.rb', line 401 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
393 394 395 |
# File 'lib/discordrb/bot.rb', line 393 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.
294 295 296 297 298 299 300 301 |
# File 'lib/discordrb/bot.rb', line 294 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 |
#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
365 366 367 |
# File 'lib/discordrb/bot.rb', line 365 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 |
#game=(name_or_id) ⇒ Game
Sets the currently playing game to the specified game.
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/discordrb/bot.rb', line 315 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
479 480 481 |
# File 'lib/discordrb/bot.rb', line 479 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
474 475 476 477 |
# File 'lib/discordrb/bot.rb', line 474 def log_exception(e) debug("Exception: #{e.inspect}", true) e.backtrace.each { |line| debug(line, true) } end |
#member_join(attributes = {}, &block) ⇒ Object
418 419 420 |
# File 'lib/discordrb/bot.rb', line 418 def member_join(attributes = {}, &block) register_event(GuildMemberAddEvent, attributes, block) end |
#member_leave(attributes = {}, &block) ⇒ Object
426 427 428 |
# File 'lib/discordrb/bot.rb', line 426 def member_leave(attributes = {}, &block) register_event(GuildMemberDeleteEvent, attributes, block) end |
#member_update(attributes = {}, &block) ⇒ Object
422 423 424 |
# File 'lib/discordrb/bot.rb', line 422 def member_update(attributes = {}, &block) register_event(GuildMemberUpdateEvent, attributes, block) end |
#mention(attributes = {}, &block) ⇒ Object
377 378 379 |
# File 'lib/discordrb/bot.rb', line 377 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.
357 358 359 |
# File 'lib/discordrb/bot.rb', line 357 def (attributes = {}, &block) register_event(MessageEvent, attributes, block) end |
#parse_mention(mention) ⇒ User
Gets the user from a mention of the user.
306 307 308 309 310 |
# File 'lib/discordrb/bot.rb', line 306 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
454 455 456 |
# File 'lib/discordrb/bot.rb', line 454 def pm(attributes = {}, &block) register_event(PrivateMessageEvent, attributes, block) end |
#presence(attributes = {}, &block) ⇒ Object
373 374 375 |
# File 'lib/discordrb/bot.rb', line 373 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
361 362 363 |
# File 'lib/discordrb/bot.rb', line 361 def ready(attributes = {}, &block) register_event(ReadyEvent, attributes, block) end |
#remove_handler(handler) ⇒ Object
460 461 462 463 |
# File 'lib/discordrb/bot.rb', line 460 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.
263 264 265 |
# File 'lib/discordrb/bot.rb', line 263 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.
253 254 255 256 257 |
# File 'lib/discordrb/bot.rb', line 253 def (channel_id, content) debug("Sending message to #{channel_id} with content '#{content}'") response = API.(@token, channel_id, content) 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
430 431 432 |
# File 'lib/discordrb/bot.rb', line 430 def server_create(attributes = {}, &block) register_event(GuildCreateEvent, attributes, block) end |
#server_delete(attributes = {}, &block) ⇒ Object
438 439 440 |
# File 'lib/discordrb/bot.rb', line 438 def server_delete(attributes = {}, &block) register_event(GuildDeleteEvent, attributes, block) end |
#server_update(attributes = {}, &block) ⇒ Object
434 435 436 |
# File 'lib/discordrb/bot.rb', line 434 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
369 370 371 |
# File 'lib/discordrb/bot.rb', line 369 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
414 415 416 |
# File 'lib/discordrb/bot.rb', line 414 def voice_state_update(attributes = {}, &block) register_event(VoiceStateUpdateEvent, attributes, block) end |