discorb 0.5.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/discorb/color.rb CHANGED
@@ -130,35 +130,65 @@ module Discorb
130
130
  #
131
131
  # Create a color from a Discord's color.
132
132
  # Currently these colors are supported:
133
- # - teal (0x1abc9c)
134
- # - dark_teal (0x11806a)
135
- # - green (0x2ecc71)
136
- # - dark_green (0x1f8b4c)
137
- # - blue (0x3498db)
138
- # - dark_blue (0x206694)
139
- # - purple (0x9b59b6)
140
- # - dark_purple (0x71368a)
141
- # - magenta (0xe91e63)
142
- # - dark_magenta (0xad1457)
143
- # - gold (0xf1c40f)
144
- # - dark_gold (0xc27c0e)
145
- # - orange (0xe67e22)
146
- # - dark_orange (0xa84300)
147
- # - red (0xe74c3c)
148
- # - dark_red (0x992d22)
149
- # - lighter_grey (0x95a5a6)
150
- # - lighter_gray (0x95a5a6)
151
- # - dark_grey (0x607d8b)
152
- # - dark_gray (0x607d8b)
153
- # - light_grey (0x979c9f)
154
- # - light_gray (0x979c9f)
155
- # - darker_grey (0x546e7a)
156
- # - darker_gray (0x546e7a)
157
- # - og_blurple (0x7289da)
158
- # - blurple (0x5865f2)
159
- # - greyple (0x99aab5)
160
- # - dark_theme (0x36393f)
161
- # - fuchsia (0xeb459e)
133
+ # | Color Name | Hexadecimal |
134
+ # |------------|------------|
135
+ # | `:teal` | `#1abc9c` |
136
+ # | `:dark_teal` | `#11806a` |
137
+ # | `:green` | `#2ecc71` |
138
+ # | `:dark_green` | `#1f8b4c` |
139
+ # | `:blue` | `#3498db` |
140
+ # | `:dark_blue` | `#206694` |
141
+ # | `:purple` | `#9b59b6` |
142
+ # | `:dark_purple` | `#71368a` |
143
+ # | `:magenta` | `#e91e63` |
144
+ # | `:dark_magenta` | `#ad1457` |
145
+ # | `:gold` | `#f1c40f` |
146
+ # | `:dark_gold` | `#c27c0e` |
147
+ # | `:orange` | `#e67e22` |
148
+ # | `:dark_orange` | `#a84300` |
149
+ # | `:red` | `#e74c3c` |
150
+ # | `:dark_red` | `#992d22` |
151
+ # | `:lighter_grey` | `#95a5a6` |
152
+ # | `:lighter_gray` | `#95a5a6` |
153
+ # | `:dark_grey` | `#607d8b` |
154
+ # | `:dark_gray` | `#607d8b` |
155
+ # | `:light_grey` | `#979c9f` |
156
+ # | `:light_gray` | `#979c9f` |
157
+ # | `:darker_grey` | `#546e7a` |
158
+ # | `:darker_gray` | `#546e7a` |
159
+ # | `:og_blurple` | `#7289da` |
160
+ # | `:blurple` | `#5865f2` |
161
+ # | `:greyple` | `#99aab5` |
162
+ # | `:dark_theme` | `#36393f` |
163
+ # | `:fuchsia` | `#eb459e` |
164
+ # | `:dark_teal` | `#11806a` |
165
+ # | `:green` | `#2ecc71` |
166
+ # | `:dark_green` | `#1f8b4c` |
167
+ # | `:blue` | `#3498db` |
168
+ # | `:dark_blue` | `#206694` |
169
+ # | `:purple` | `#9b59b6` |
170
+ # | `:dark_purple` | `#71368a` |
171
+ # | `:magenta` | `#e91e63` |
172
+ # | `:dark_magenta` | `#ad1457` |
173
+ # | `:gold` | `#f1c40f` |
174
+ # | `:dark_gold` | `#c27c0e` |
175
+ # | `:orange` | `#e67e22` |
176
+ # | `:dark_orange` | `#a84300` |
177
+ # | `:red` | `#e74c3c` |
178
+ # | `:dark_red` | `#992d22` |
179
+ # | `:lighter_grey` | `#95a5a6` |
180
+ # | `:lighter_gray` | `#95a5a6` |
181
+ # | `:dark_grey` | `#607d8b` |
182
+ # | `:dark_gray` | `#607d8b` |
183
+ # | `:light_grey` | `#979c9f` |
184
+ # | `:light_gray` | `#979c9f` |
185
+ # | `:darker_grey` | `#546e7a` |
186
+ # | `:darker_gray` | `#546e7a` |
187
+ # | `:og_blurple` | `#7289da` |
188
+ # | `:blurple` | `#5865f2` |
189
+ # | `:greyple` | `#99aab5` |
190
+ # | `:dark_theme` | `#36393f` |
191
+ # | `:fuchsia` | `#eb459e` |
162
192
  #
163
193
  # @param [Symbol] color A Discord color name.
164
194
  #
@@ -4,7 +4,7 @@ module Discorb
4
4
  # @return [String] The API base URL.
5
5
  API_BASE_URL = "https://discord.com/api/v9"
6
6
  # @return [String] The version of discorb.
7
- VERSION = "0.5.5"
7
+ VERSION = "0.7.0"
8
8
  # @return [String] The user agent for the bot.
9
9
  USER_AGENT = "DiscordBot (https://github.com/discorb-lib/discorb #{VERSION}) Ruby/#{RUBY_VERSION}"
10
10
 
data/lib/discorb/embed.rb CHANGED
@@ -93,18 +93,18 @@ module Discorb
93
93
  # @return [Hash] Converted embed.
94
94
  #
95
95
  def to_hash
96
- {
97
- title: @title,
98
- description: @description,
99
- url: @url,
100
- timestamp: @timestamp&.iso8601,
101
- color: @color&.to_i,
102
- footer: @footer&.to_hash,
103
- image: @image&.to_hash,
104
- thumbnail: @thumbnail&.to_hash,
105
- author: @author&.to_hash,
106
- fields: @fields&.map { |f| f.to_hash },
107
- }
96
+ ret = { type: "rich" }
97
+ ret[:title] = @title if @title
98
+ ret[:description] = @description if @description
99
+ ret[:url] = @url if @url
100
+ ret[:timestamp] = @timestamp&.iso8601 if @timestamp
101
+ ret[:color] = @color&.to_i if @color
102
+ ret[:footer] = @footer&.to_hash if @footer
103
+ ret[:image] = @image&.to_hash if @image
104
+ ret[:thumbnail] = @thumbnail&.to_hash if @thumbnail
105
+ ret[:author] = @author&.to_hash if @author
106
+ ret[:fields] = @fields&.map { |f| f.to_hash } if @fields.any?
107
+ ret
108
108
  end
109
109
 
110
110
  #
data/lib/discorb/emoji.rb CHANGED
@@ -6,6 +6,13 @@ module Discorb
6
6
  # Represents a Discord emoji.
7
7
  # @abstract
8
8
  class Emoji
9
+ def eql?(other)
10
+ other.is_a?(self.class) && other.to_uri == to_uri
11
+ end
12
+
13
+ def ==(other)
14
+ eql?(other)
15
+ end
9
16
  end
10
17
 
11
18
  # Represents a custom emoji in discord.
@@ -79,7 +86,7 @@ module Discorb
79
86
  # @param [Array<Discorb::Role>] roles The new roles that can use this emoji.
80
87
  # @param [String] reason The reason for editing the emoji.
81
88
  #
82
- # @return [self] The edited emoji.
89
+ # @return [Async::Task<self>] The edited emoji.
83
90
  #
84
91
  def edit(name: :unset, roles: :unset, reason: nil)
85
92
  Async do
@@ -100,7 +107,7 @@ module Discorb
100
107
  #
101
108
  # @param [String] reason The reason for deleting the emoji.
102
109
  #
103
- # @return [self] The deleted emoji.
110
+ # @return [Async::Task<self>] The deleted emoji.
104
111
  #
105
112
  def delete!(reason: nil)
106
113
  Async do
data/lib/discorb/error.rb CHANGED
@@ -67,6 +67,12 @@ module Discorb
67
67
  end
68
68
  end
69
69
 
70
+ #
71
+ # Represents a 401 error.
72
+ #
73
+ class UnauthorizedError < HTTPError
74
+ end
75
+
70
76
  #
71
77
  # Represents a 403 error.
72
78
  #
@@ -88,7 +94,7 @@ module Discorb
88
94
  @client.close!
89
95
  DiscorbError.instance_method(:initialize).bind(self).call(<<~MESSAGE)
90
96
  The client is banned from CloudFlare.
91
- Hint: Try to increase the number of requests per second, e.g. Use sleep in between requests.
97
+ Hint: Try to decrease the number of requests per second, e.g. Use sleep in between requests.
92
98
  MESSAGE
93
99
  end
94
100
  end
data/lib/discorb/event.rb CHANGED
@@ -11,17 +11,17 @@ module Discorb
11
11
  attr_reader :block
12
12
  # @return [Symbol] the event id.
13
13
  attr_reader :id
14
- # @return [Hash] the event discriminator.
15
- attr_reader :discriminator
14
+ # @return [Hash] the event metadata.
15
+ attr_reader :metadata
16
16
  # @return [Boolean] whether the event is once or not.
17
17
  attr_reader :once
18
18
  alias once? once
19
19
 
20
- def initialize(block, id, discriminator)
20
+ def initialize(block, id, metadata)
21
21
  @block = block
22
22
  @id = id
23
- @once = discriminator.fetch(:once, false)
24
- @discriminator = discriminator
23
+ @once = metadata.fetch(:once, false)
24
+ @metadata = metadata
25
25
  @rescue = nil
26
26
  end
27
27
 
@@ -2,6 +2,7 @@
2
2
  require "optparse"
3
3
  require "json"
4
4
  require "discorb/utils/colored_puts"
5
+ require "io/console"
5
6
 
6
7
  ARGV.delete_at 0
7
8
  # @!visibility private
@@ -20,6 +21,7 @@ options = {
20
21
  log_file: nil,
21
22
  log_color: nil,
22
23
  setup: nil,
24
+ token: false,
23
25
  }
24
26
  opt.on("-d", "--deamon", "Run as a daemon.") { |v| options[:daemon] = v }
25
27
  opt.on("-l", "--log-level LEVEL", "Log level.") do |v|
@@ -33,6 +35,7 @@ end
33
35
  opt.on("-f", "--log-file FILE", "File to write log to.") { |v| options[:log_file] = v }
34
36
  opt.on("-c", "--[no-]log-color", "Whether to colorize log output.") { |v| options[:log_color] = v }
35
37
  opt.on("-s", "--setup", "Whether to setup application commands.") { |v| options[:setup] = v }
38
+ opt.on("-t", "--token [ENV]", "The name of the environment variable to use for token, or just `-t` or `--token` for intractive prompt.") { |v| options[:token] = v }
36
39
  opt.parse!(ARGV)
37
40
 
38
41
  script = ARGV[0]
@@ -42,6 +45,15 @@ script ||= "main.rb"
42
45
  ENV["DISCORB_CLI_FLAG"] = "run"
43
46
  ENV["DISCORB_CLI_OPTIONS"] = JSON.generate(options)
44
47
 
48
+ if options[:token]
49
+ ENV["DISCORB_CLI_TOKEN"] = ENV[options[:token]]
50
+ raise "#{options[:token]} is not set." if ENV["DISCORB_CLI_TOKEN"].nil?
51
+ elsif options[:token].nil? || options[:token] == "-"
52
+ print "\e[90mPlease enter your token: \e[m"
53
+ ENV["DISCORB_CLI_TOKEN"] = $stdin.noecho(&:gets).chomp
54
+ puts ""
55
+ end
56
+
45
57
  begin
46
58
  load script
47
59
  rescue LoadError
@@ -4,19 +4,32 @@ require "discorb/utils/colored_puts"
4
4
 
5
5
  ARGV.delete_at 0
6
6
 
7
+ options = {
8
+ guilds: nil,
9
+ }
10
+
7
11
  opt = OptionParser.new <<~BANNER
8
12
  This command will setup application commands.
9
13
 
10
- Usage: discorb setup [script]
14
+ Usage: discorb setup [options] [script]
11
15
 
12
16
  script The script to setup.
13
17
  BANNER
18
+ opt.on("-g", "--guild ID", Array, "The guild ID to setup, use comma for setup commands in multiple guilds, or `global` for setup global commands.") { |v| options[:guilds] = v }
14
19
  opt.parse!(ARGV)
15
20
 
16
21
  script = ARGV[0]
17
22
  script ||= "main.rb"
18
23
  ENV["DISCORB_CLI_FLAG"] = "setup"
19
24
 
25
+ if options[:guilds] == ["global"]
26
+ ENV["DISCORB_SETUP_GUILDS"] = "global"
27
+ elsif options[:guilds]
28
+ ENV["DISCORB_SETUP_GUILDS"] = options[:guilds].join(",")
29
+ else
30
+ ENV["DISCORB_SETUP_GUILDS"] = nil
31
+ end
32
+
20
33
  begin
21
34
  load script
22
35
  rescue LoadError
@@ -8,7 +8,7 @@ module Discorb
8
8
  # @abstract
9
9
  #
10
10
  module Extension
11
- include Discorb::Command::Handler
11
+ include Discorb::ApplicationCommand::Handler
12
12
  undef setup_commands
13
13
 
14
14
  @events = {}
@@ -19,18 +19,18 @@ module Discorb
19
19
  #
20
20
  # @param [Symbol] event_name The name of the event.
21
21
  # @param [Symbol] id The id of the event. Used to delete the event.
22
- # @param [Hash] discriminator Other discriminators.
22
+ # @param [Hash] metadata Other metadata.
23
23
  # @param [Proc] block The block to execute when the event is triggered.
24
24
  #
25
25
  # @return [Discorb::Event] The event.
26
26
  #
27
- def event(event_name, id: nil, **discriminator, &block)
27
+ def event(event_name, id: nil, **metadata, &block)
28
28
  raise ArgumentError, "Event name must be a symbol" unless event_name.is_a?(Symbol)
29
29
  raise ArgumentError, "block must be a Proc" unless block.is_a?(Proc)
30
30
 
31
31
  @events[event_name] ||= []
32
- discriminator[:extension] = self.name
33
- @events[event_name] << Discorb::Event.new(block, id, discriminator)
32
+ metadata[:extension] = self.name
33
+ @events[event_name] << Discorb::Event.new(block, id, metadata)
34
34
  end
35
35
 
36
36
  #
@@ -38,18 +38,18 @@ module Discorb
38
38
  #
39
39
  # @param [Symbol] event_name The name of the event.
40
40
  # @param [Symbol] id The id of the event. Used to delete the event.
41
- # @param [Hash] discriminator Other discriminators.
41
+ # @param [Hash] metadata Other metadata.
42
42
  # @param [Proc] block The block to execute when the event is triggered.
43
43
  #
44
44
  # @return [Discorb::Event] The event.
45
45
  #
46
- def once_event(event_name, id: nil, **discriminator, &block)
47
- event(event_name, id: id, once: true, **discriminator, &block)
46
+ def once_event(event_name, id: nil, **metadata, &block)
47
+ event(event_name, id: id, once: true, **metadata, &block)
48
48
  end
49
49
 
50
50
  # @return [Hash{Symbol => Array<Discorb::Event>}] The events of the extension.
51
51
  attr_reader :events
52
- # @return [Array<Discorb::Command::Command] The commands of the extension.
52
+ # @return [Array<Discorb::ApplicationCommand::Command>] The commands of the extension.
53
53
  attr_reader :commands
54
54
  # @private
55
55
  attr_reader :bottom_commands
@@ -53,6 +53,12 @@ module Discorb
53
53
  attr_reader :member
54
54
  # @return [Discorb::UnicodeEmoji, Discorb::PartialEmoji] The emoji that was reacted with.
55
55
  attr_reader :emoji
56
+ # @macro client_cache
57
+ # @return [Discorb::Member, Discorb::User] The user or member who reacted.
58
+ attr_reader :fired_by
59
+
60
+ alias reactor fired_by
61
+ alias from fired_by
56
62
 
57
63
  # @!visibility private
58
64
  def initialize(client, data)
@@ -79,6 +85,8 @@ module Discorb
79
85
  end
80
86
  end
81
87
 
88
+ @fired_by = @member || @user || @client.users[data[:user_id]]
89
+
82
90
  @message = client.messages[data[:message_id]]
83
91
  @emoji = data[:emoji][:id].nil? ? UnicodeEmoji.new(data[:emoji][:name]) : PartialEmoji.new(data[:emoji])
84
92
  end
@@ -90,7 +98,7 @@ module Discorb
90
98
  #
91
99
  # @param [Boolean] force Whether to force fetching the message.
92
100
  #
93
- # @return [Discorb::Message] The message.
101
+ # @return [Async::Task<Discorb::Message>] The message.
94
102
  def fetch_message(force: false)
95
103
  Async do
96
104
  next @message if !force && @message
@@ -139,7 +147,7 @@ module Discorb
139
147
  #
140
148
  # @param [Boolean] force Whether to force fetching the message.
141
149
  #
142
- # @return [Discorb::Message] The message.
150
+ # @return [Async::Task<Discorb::Message>] The message.
143
151
  def fetch_message(force: false)
144
152
  Async do
145
153
  next @message if !force && @message
@@ -191,7 +199,7 @@ module Discorb
191
199
  #
192
200
  # @param [Boolean] force Whether to force fetching the message.
193
201
  #
194
- # @return [Discorb::Message] The message.
202
+ # @return [Async::Task<Discorb::Message>] The message.
195
203
  def fetch_message(force: false)
196
204
  Async do
197
205
  next @message if !force && @message
@@ -265,7 +273,7 @@ module Discorb
265
273
  # @macro async
266
274
  # @macro http
267
275
  #
268
- # @return [Discorb::Message] The message.
276
+ # @return [Async::Task<Discorb::Message>] The message.
269
277
  def fetch_message
270
278
  Async do
271
279
  channel.fetch_message(@id).wait
@@ -355,6 +363,9 @@ module Discorb
355
363
  class TypingStartEvent < GatewayEvent
356
364
  # @return [Discorb::Snowflake] The ID of the channel the user is typing in.
357
365
  attr_reader :user_id
366
+ # @macro client_cache
367
+ # @return [Discorb::Member] The member that is typing.
368
+ attr_reader :member
358
369
 
359
370
  # @!attribute [r] channel
360
371
  # @macro client_cache
@@ -365,6 +376,9 @@ module Discorb
365
376
  # @!attribute [r] user
366
377
  # @macro client_cache
367
378
  # @return [Discorb::User] The user that is typing.
379
+ # @!attribute [r] fired_by
380
+ # @macro client_cache
381
+ # @return [Discorb::Member, Discorb::User] The member or user that started typing.
368
382
 
369
383
  # @!visibility private
370
384
  def initialize(client, data)
@@ -388,6 +402,12 @@ module Discorb
388
402
  def guild
389
403
  @client.guilds[@guild_id]
390
404
  end
405
+
406
+ def fired_by
407
+ @member || user
408
+ end
409
+
410
+ alias from fired_by
391
411
  end
392
412
 
393
413
  #
@@ -513,7 +533,6 @@ module Discorb
513
533
  case payload[:op]
514
534
  when 10
515
535
  @heartbeat_interval = data[:heartbeat_interval]
516
- @tasks << handle_heartbeat(@heartbeat_interval)
517
536
  if @first
518
537
  payload = {
519
538
  token: @token,
@@ -523,6 +542,13 @@ module Discorb
523
542
  }
524
543
  payload[:presence] = @identify_presence if @identify_presence
525
544
  send_gateway(2, **payload)
545
+ Async do
546
+ sleep 2
547
+ next unless @uncached_guilds.nil?
548
+
549
+ raise ClientError, "Failed to connect to gateway.\nHint: This usually means that your intents are invalid."
550
+ exit 1
551
+ end
526
552
  else
527
553
  payload = {
528
554
  token: @token,
@@ -540,7 +566,7 @@ module Discorb
540
566
  connect_gateway(false)
541
567
  else
542
568
  @log.info "Connection is not resumable, reconnecting with opcode 2"
543
- task.sleep(2)
569
+ sleep(2)
544
570
  @connection.close
545
571
  connect_gateway(true)
546
572
  end
@@ -555,7 +581,7 @@ module Discorb
555
581
 
556
582
  def handle_heartbeat(interval)
557
583
  Async do |task|
558
- task.sleep((interval / 1000.0 - 1) * rand)
584
+ sleep((interval / 1000.0 - 1) * rand)
559
585
  loop do
560
586
  @heartbeat_before = Time.now.to_f
561
587
  @connection.write({ op: 1, d: @last_s }.to_json)
@@ -578,6 +604,12 @@ module Discorb
578
604
  @session_id = data[:session_id]
579
605
  @user = ClientUser.new(self, data[:user])
580
606
  @uncached_guilds = data[:guilds].map { |g| g[:id] }
607
+ if @uncached_guilds == [] or !@intents.guilds
608
+ @ready = true
609
+ dispatch(:ready)
610
+ @log.info("Successfully connected to Discord.")
611
+ end
612
+ @tasks << handle_heartbeat(@heartbeat_interval)
581
613
  when "GUILD_CREATE"
582
614
  if @uncached_guilds.include?(data[:id])
583
615
  Guild.new(self, data, true)
@@ -585,7 +617,7 @@ module Discorb
585
617
  if @uncached_guilds == []
586
618
  @ready = true
587
619
  dispatch(:ready)
588
- @log.info("Guilds were cached")
620
+ @log.info("Successfully connected to Discord, and cached all guilds.")
589
621
  end
590
622
  elsif @guilds.has?(data[:id])
591
623
  @guilds[data[:id]].send(:_set_data, data)