discorb 0.15.1 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +9 -0
- data/docs/events.md +21 -5
- data/examples/simple/rolepanel.rb +1 -1
- data/examples/simple/shard.rb +17 -0
- data/lib/discorb/app_command/handler.rb +1 -1
- data/lib/discorb/channel.rb +1 -1
- data/lib/discorb/client.rb +133 -53
- data/lib/discorb/common.rb +1 -1
- data/lib/discorb/exe/new.rb +5 -5
- data/lib/discorb/exe/run.rb +1 -15
- data/lib/discorb/gateway.rb +180 -142
- data/lib/discorb/http.rb +2 -2
- data/lib/discorb/interaction/autocomplete.rb +2 -2
- data/lib/discorb/interaction/command.rb +2 -2
- data/lib/discorb/interaction/components.rb +1 -1
- data/lib/discorb/interaction/root.rb +1 -1
- data/lib/discorb/rate_limit.rb +2 -2
- data/lib/discorb/shard.rb +74 -0
- data/lib/discorb.rb +2 -2
- data/sig/discorb.rbs +7234 -6850
- metadata +4 -3
- data/lib/discorb/log.rb +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6537aa3c45f64e6b0e8040a5a0d989934fb58d766ee6de305bf04132630a7b94
|
4
|
+
data.tar.gz: 68512bc0d2abd0738cc6e81ba2b794feb87480d6d84197a51a6deba739d31d5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 239e4658a2ade0ea8382655970a1eecbb3c62c7c3619e3de8fdf932c1c0a4053e35b722bef5dcdbd67477754388cc3c157c9be6360ef7625fe9f84504b5ecf90
|
7
|
+
data.tar.gz: d830a06c7a505ee31aeb3242e7aa59dadf6abab24a26c357b9e29e5f94d5fef7a889b114d4b7793ffda3f50b19a6be0c3f87921934393b03e71c5f50bfa96de4
|
data/Changelog.md
CHANGED
@@ -4,6 +4,15 @@
|
|
4
4
|
|
5
5
|
# Changelog
|
6
6
|
|
7
|
+
## v0.16
|
8
|
+
|
9
|
+
### v0.16.0
|
10
|
+
|
11
|
+
- Change!: Use built-in Logger instead of custom Logger.
|
12
|
+
- Delete!: `--log-level`, `--[no-]log-color` is deleted.
|
13
|
+
- Add: Support sharding
|
14
|
+
- Add: Use Mutex for preventing connection duplications.
|
15
|
+
|
7
16
|
## v0.15
|
8
17
|
|
9
18
|
### v0.15.1
|
data/docs/events.md
CHANGED
@@ -30,13 +30,13 @@ class << client
|
|
30
30
|
end
|
31
31
|
```
|
32
32
|
|
33
|
-
If you want to
|
33
|
+
If you want to separate event handlers from the client, consider using {Discorb::Extension}. {file:docs/extension.md Learn more about extensions}.
|
34
34
|
|
35
|
-
Since v0.6.1, you can set `:override` to `true` to register
|
35
|
+
Since v0.6.1, you can set `:override` to `true` to register event handlers that can be overridden.
|
36
36
|
|
37
37
|
```ruby
|
38
38
|
client.on :message, override: true do |event|
|
39
|
-
puts "This event handler
|
39
|
+
puts "This event handler can be overridden."
|
40
40
|
end
|
41
41
|
|
42
42
|
client.on :message do |event|
|
@@ -44,8 +44,8 @@ client.on :message do |event|
|
|
44
44
|
end
|
45
45
|
```
|
46
46
|
|
47
|
-
This example will print `Override!`, but not `This event handler
|
48
|
-
This is useful for registering event handlers as default
|
47
|
+
This example will print `Override!`, but not `This event handler can be overridden.`.
|
48
|
+
This is useful for registering event handlers as default behavior, such as error handlers.
|
49
49
|
|
50
50
|
```ruby
|
51
51
|
# In the library...
|
@@ -95,6 +95,22 @@ Defaults to printing the error to stderr, override to handle it yourself.
|
|
95
95
|
Fires when `discorb setup` is run.
|
96
96
|
This is useful for setting up some dependencies, such as the database.
|
97
97
|
|
98
|
+
#### `shard_standby(shard)`
|
99
|
+
|
100
|
+
Fires when a shard is standby.
|
101
|
+
|
102
|
+
| Parameter | Type | Description |
|
103
|
+
| ---------- | ----- | ----------- |
|
104
|
+
|`shard` | {Discorb::Shard} | The shard that is standby. |
|
105
|
+
|
106
|
+
#### `shard_resumed(shard)`
|
107
|
+
|
108
|
+
Fires when a shard is resumed connection.
|
109
|
+
|
110
|
+
| Parameter | Type | Description |
|
111
|
+
| ---------- | ----- | ----------- |
|
112
|
+
|`shard` | {Discorb::Shard} | The shard that is standby. |
|
113
|
+
|
98
114
|
### Guild events
|
99
115
|
|
100
116
|
#### `guild_join(guild)`
|
@@ -2,7 +2,7 @@
|
|
2
2
|
require "discorb"
|
3
3
|
intents = Discorb::Intents.new
|
4
4
|
intents.members = true
|
5
|
-
client = Discorb::Client.new(intents: intents
|
5
|
+
client = Discorb::Client.new(intents: intents)
|
6
6
|
|
7
7
|
def convert_role(guild, string)
|
8
8
|
guild.roles.find do |role|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "discorb"
|
3
|
+
|
4
|
+
client = Discorb::Client.new(log: Logger.new($stdout))
|
5
|
+
|
6
|
+
client.once :standby do
|
7
|
+
puts "Logged in as #{client.user}"
|
8
|
+
end
|
9
|
+
|
10
|
+
client.on :message do |message|
|
11
|
+
next if message.author.bot?
|
12
|
+
next unless message.content == "!inspect"
|
13
|
+
|
14
|
+
message.channel.post("I'm #{client.user}, running on shard #{client.shard_id}!")
|
15
|
+
end
|
16
|
+
|
17
|
+
client.run(ENV["DISCORD_BOT_TOKEN"], shards: [0, 1], shard_count: 2)
|
data/lib/discorb/channel.rb
CHANGED
@@ -67,7 +67,7 @@ module Discorb
|
|
67
67
|
descendants.each do |klass|
|
68
68
|
return klass.new(client, data, no_cache: no_cache) if !klass.channel_type.nil? && klass.channel_type == data[:type]
|
69
69
|
end
|
70
|
-
client.
|
70
|
+
client.logger.warn("Unknown channel type #{data[:type]}, initialized GuildChannel")
|
71
71
|
GuildChannel.new(client, data)
|
72
72
|
end
|
73
73
|
|
data/lib/discorb/client.rb
CHANGED
@@ -40,8 +40,6 @@ module Discorb
|
|
40
40
|
attr_reader :emojis
|
41
41
|
# @return [Discorb::Dictionary{Discorb::Snowflake => Discorb::Message}] A dictionary of messages.
|
42
42
|
attr_reader :messages
|
43
|
-
# @return [Discorb::Logger] The logger.
|
44
|
-
attr_reader :log
|
45
43
|
# @return [Array<Discorb::ApplicationCommand::Command>] The commands that the client is using.
|
46
44
|
attr_reader :commands
|
47
45
|
# @return [Float] The ping of the client.
|
@@ -50,15 +48,28 @@ module Discorb
|
|
50
48
|
attr_reader :ping
|
51
49
|
# @return [:initialized, :running, :closed] The status of the client.
|
52
50
|
attr_reader :status
|
53
|
-
# @return [Integer] The session ID of connection.
|
54
|
-
attr_reader :session_id
|
55
51
|
# @return [Hash{String => Discorb::Extension}] The loaded extensions.
|
56
52
|
attr_reader :extensions
|
57
|
-
#
|
53
|
+
# @return [Hash{Integer => Discorb::Shard}] The shards of the client.
|
54
|
+
attr_reader :shards
|
58
55
|
# @private
|
59
56
|
# @return [Hash{Discorb::Snowflake => Discorb::ApplicationCommand::Command}] The commands on the top level.
|
60
|
-
#
|
61
57
|
attr_reader :bottom_commands
|
58
|
+
# @private
|
59
|
+
# @return [{String => Thread::Mutex}] A hash of mutexes.
|
60
|
+
attr_reader :mutex
|
61
|
+
|
62
|
+
# @!attribute [r] session_id
|
63
|
+
# @return [String] The session ID of the client or current shard.
|
64
|
+
# @return [nil] If not connected to the gateway.
|
65
|
+
# @!attribute [r] shard
|
66
|
+
# @return [Discorb::Shard] The current shard. This is implemented with Thread variables.
|
67
|
+
# @return [nil] If client has no shard.
|
68
|
+
# @!attribute [r] shard_id
|
69
|
+
# @return [Discorb::Shard] The current shard ID. This is implemented with Thread variables.
|
70
|
+
# @return [nil] If client has no shard.
|
71
|
+
# @!attribute [r] logger
|
72
|
+
# @return [Logger] The logger.
|
62
73
|
|
63
74
|
#
|
64
75
|
# Initializes a new client.
|
@@ -66,8 +77,7 @@ module Discorb
|
|
66
77
|
# @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions that the client is using.
|
67
78
|
# @param [Discorb::Intents] intents The intents that the client is currently using.
|
68
79
|
# @param [Integer] message_caches The number of messages to cache.
|
69
|
-
# @param [
|
70
|
-
# @param [Boolean] colorize_log Whether to colorize the log.
|
80
|
+
# @param [Logger] logger The IO object to use for logging.
|
71
81
|
# @param [:debug, :info, :warn, :error, :critical] log_level The log level.
|
72
82
|
# @param [Boolean] wait_until_ready Whether to delay event dispatch until ready.
|
73
83
|
# @param [Boolean] fetch_member Whether to fetch member on ready. This may slow down the client. Default to `false`.
|
@@ -75,7 +85,7 @@ module Discorb
|
|
75
85
|
#
|
76
86
|
def initialize(
|
77
87
|
allowed_mentions: nil, intents: nil, message_caches: 1000,
|
78
|
-
|
88
|
+
logger: nil,
|
79
89
|
wait_until_ready: true, fetch_member: false,
|
80
90
|
title: nil
|
81
91
|
)
|
@@ -83,7 +93,7 @@ module Discorb
|
|
83
93
|
@intents = (intents or Intents.default)
|
84
94
|
@events = {}
|
85
95
|
@api_version = nil
|
86
|
-
@
|
96
|
+
@logger = logger || Logger.new($stdout, progname: "discorb")
|
87
97
|
@user = nil
|
88
98
|
@users = Discorb::Dictionary.new
|
89
99
|
@channels = Discorb::Dictionary.new
|
@@ -103,6 +113,8 @@ module Discorb
|
|
103
113
|
@fetch_member = fetch_member
|
104
114
|
@title = title
|
105
115
|
@extensions = {}
|
116
|
+
@mutex = {}
|
117
|
+
@shards = {}
|
106
118
|
set_default_events
|
107
119
|
end
|
108
120
|
|
@@ -183,16 +195,16 @@ module Discorb
|
|
183
195
|
events << event_method
|
184
196
|
end
|
185
197
|
if events.nil?
|
186
|
-
|
198
|
+
logger.debug "Event #{event_name} doesn't have any proc, skipping"
|
187
199
|
next
|
188
200
|
end
|
189
|
-
|
201
|
+
logger.debug "Dispatching event #{event_name}"
|
190
202
|
events.each do |block|
|
191
203
|
Async do
|
192
204
|
Async(annotation: "Discorb event: #{event_name}") do |_task|
|
193
205
|
@events[event_name].delete(block) if block.is_a?(Discorb::EventHandler) && block.metadata[:once]
|
194
206
|
block.call(*args)
|
195
|
-
|
207
|
+
logger.debug "Dispatched proc with ID #{block.id.inspect}"
|
196
208
|
rescue StandardError, ScriptError => e
|
197
209
|
dispatch(:error, event_name, args, e)
|
198
210
|
end
|
@@ -316,7 +328,7 @@ module Discorb
|
|
316
328
|
}
|
317
329
|
payload[:activities] = [activity.to_hash] unless activity.nil?
|
318
330
|
payload[:status] = status unless status.nil?
|
319
|
-
if
|
331
|
+
if connection
|
320
332
|
Async do
|
321
333
|
send_gateway(3, **payload)
|
322
334
|
end
|
@@ -427,15 +439,15 @@ module Discorb
|
|
427
439
|
#
|
428
440
|
# @note If the token is nil, you should use `discorb run` with the `-e` or `--env` option.
|
429
441
|
#
|
430
|
-
def run(token = nil)
|
442
|
+
def run(token = nil, shards: nil, shard_count: nil)
|
431
443
|
token ||= ENV["DISCORB_CLI_TOKEN"]
|
432
444
|
raise ArgumentError, "Token is not specified, and -e/--env is not specified" if token.nil?
|
433
445
|
case ENV["DISCORB_CLI_FLAG"]
|
434
446
|
when nil
|
435
|
-
start_client(token)
|
447
|
+
start_client(token, shards: shards, shard_count: shard_count)
|
436
448
|
when "run"
|
437
449
|
before_run(token)
|
438
|
-
start_client(token)
|
450
|
+
start_client(token, shards: shards, shard_count: shard_count)
|
439
451
|
when "setup"
|
440
452
|
run_setup(token)
|
441
453
|
end
|
@@ -445,10 +457,33 @@ module Discorb
|
|
445
457
|
# Stops the client.
|
446
458
|
#
|
447
459
|
def close!
|
448
|
-
@
|
460
|
+
if @shards.any?
|
461
|
+
@shards.each(&:close!)
|
462
|
+
else
|
463
|
+
@connection.send_close
|
464
|
+
end
|
449
465
|
@tasks.each(&:stop)
|
450
466
|
@status = :closed
|
451
|
-
|
467
|
+
end
|
468
|
+
|
469
|
+
def session_id
|
470
|
+
if shard
|
471
|
+
shard.session_id
|
472
|
+
else
|
473
|
+
@session_id
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
def logger
|
478
|
+
shard&.logger || @logger
|
479
|
+
end
|
480
|
+
|
481
|
+
def shard
|
482
|
+
Thread.current.thread_variable_get("shard")
|
483
|
+
end
|
484
|
+
|
485
|
+
def shard_id
|
486
|
+
Thread.current.thread_variable_get("shard_id")
|
452
487
|
end
|
453
488
|
|
454
489
|
private
|
@@ -457,22 +492,6 @@ module Discorb
|
|
457
492
|
require "json"
|
458
493
|
options = JSON.parse(ENV["DISCORB_CLI_OPTIONS"], symbolize_names: true)
|
459
494
|
setup_commands(token) if options[:setup]
|
460
|
-
if options[:log_level]
|
461
|
-
if options[:log_level] == "none"
|
462
|
-
@log.out = nil
|
463
|
-
else
|
464
|
-
@log.out = case options[:log_file]
|
465
|
-
when nil, "stderr"
|
466
|
-
$stderr
|
467
|
-
when "stdout"
|
468
|
-
$stdout
|
469
|
-
else
|
470
|
-
::File.open(options[:log_file], "a")
|
471
|
-
end
|
472
|
-
@log.level = options[:log_level].to_sym
|
473
|
-
@log.colorize_log = options[:log_color].nil? ? @log.out.isatty : options[:log_color]
|
474
|
-
end
|
475
|
-
end
|
476
495
|
end
|
477
496
|
|
478
497
|
def run_setup(token)
|
@@ -490,32 +509,93 @@ module Discorb
|
|
490
509
|
end
|
491
510
|
end
|
492
511
|
|
493
|
-
def
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
512
|
+
def set_status(status, shard)
|
513
|
+
if shard.nil?
|
514
|
+
@status = status
|
515
|
+
else
|
516
|
+
@shards[shard].status = status
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
def connection
|
521
|
+
if shard_id
|
522
|
+
@shards[shard_id].connection
|
523
|
+
else
|
524
|
+
@connection
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
def connection=(value)
|
529
|
+
if shard_id
|
530
|
+
@shards[shard_id].connection = value
|
531
|
+
else
|
532
|
+
@connection = value
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
def session_id=(value)
|
537
|
+
if shard_id
|
538
|
+
@shards[shard_id].session_id = value
|
539
|
+
else
|
540
|
+
@session_id = value
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
def start_client(token, shards: nil, shard_count: nil)
|
545
|
+
@token = token.to_s
|
546
|
+
@shard_count = shard_count
|
547
|
+
Signal.trap(:SIGINT) do
|
548
|
+
logger.info "SIGINT received, closing..."
|
549
|
+
Signal.trap(:SIGINT, "DEFAULT")
|
550
|
+
close!
|
551
|
+
end
|
552
|
+
if shards.nil?
|
553
|
+
main_loop(nil)
|
554
|
+
else
|
555
|
+
@shards = shards.map.with_index do |shard, i|
|
556
|
+
Shard.new(self, shard, shard_count, i)
|
499
557
|
end
|
500
|
-
@
|
501
|
-
|
502
|
-
@main_task = Async do
|
503
|
-
@status = :running
|
504
|
-
connect_gateway(false).wait
|
505
|
-
rescue StandardError
|
506
|
-
@status = :stopped
|
507
|
-
@close_condition.signal
|
508
|
-
raise
|
558
|
+
@shards[..-1].each_with_index do |shard, i|
|
559
|
+
shard.next_shard = @shards[i + 1]
|
509
560
|
end
|
510
|
-
@
|
511
|
-
|
561
|
+
@shards.each { |s| s.thread.join }
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
def main_loop(shard)
|
566
|
+
close_condition = Async::Condition.new
|
567
|
+
self.main_task = Async do
|
568
|
+
set_status(:running, shard)
|
569
|
+
connect_gateway(false).wait
|
570
|
+
rescue StandardError
|
571
|
+
set_status(:running, shard)
|
572
|
+
close_condition.signal
|
573
|
+
raise
|
574
|
+
end
|
575
|
+
close_condition.wait
|
576
|
+
main_task.stop
|
577
|
+
end
|
578
|
+
|
579
|
+
def main_task
|
580
|
+
if shard_id
|
581
|
+
shard.main_task
|
582
|
+
else
|
583
|
+
@main_task
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
def main_task=(value)
|
588
|
+
if shard_id
|
589
|
+
shard.main_task = value
|
590
|
+
else
|
591
|
+
@main_task = value
|
512
592
|
end
|
513
593
|
end
|
514
594
|
|
515
595
|
def set_default_events
|
516
596
|
on :error, override: true do |event_name, _args, e|
|
517
597
|
message = "An error occurred while dispatching #{event_name}:\n#{e.full_message}"
|
518
|
-
|
598
|
+
logger.error message, fallback: $stderr
|
519
599
|
end
|
520
600
|
|
521
601
|
once :standby do
|
data/lib/discorb/common.rb
CHANGED
@@ -4,7 +4,7 @@ module Discorb
|
|
4
4
|
# @return [String] The API base URL.
|
5
5
|
API_BASE_URL = "https://discord.com/api/v10"
|
6
6
|
# @return [String] The version of discorb.
|
7
|
-
VERSION = "0.
|
7
|
+
VERSION = "0.16.0"
|
8
8
|
# @return [Array<Integer>] The version array of discorb.
|
9
9
|
VERSION_ARRAY = VERSION.split(".").map(&:to_i).freeze
|
10
10
|
# @return [String] The user agent for the bot.
|
data/lib/discorb/exe/new.rb
CHANGED
@@ -164,8 +164,8 @@ def git_init
|
|
164
164
|
system "git add ."
|
165
165
|
system "git commit -m \"Initial commit\""
|
166
166
|
sputs "Initialized repository, use " \
|
167
|
-
|
168
|
-
|
167
|
+
"\e[32mgit commit --amend -m '...'\e[92m" \
|
168
|
+
" to change commit message of initial commit.\n"
|
169
169
|
end
|
170
170
|
|
171
171
|
# @private
|
@@ -228,9 +228,9 @@ if (dir = ARGV[0])
|
|
228
228
|
iputs "Found \e[30m#{dir}\e[90m and empty, using this directory."
|
229
229
|
elsif $values[:force]
|
230
230
|
iputs "Found \e[30m#{dir}\e[90m and not empty, but force is on, using this directory."
|
231
|
-
|
232
|
-
|
233
|
-
|
231
|
+
else
|
232
|
+
eputs "Directory \e[31m#{dir}\e[91m already exists and not empty. Use \e[31m-f\e[91m to force."
|
233
|
+
exit
|
234
234
|
end
|
235
235
|
else
|
236
236
|
Dir.mkdir($path)
|
data/lib/discorb/exe/run.rb
CHANGED
@@ -4,10 +4,9 @@ require "optparse"
|
|
4
4
|
require "json"
|
5
5
|
require "discorb/utils/colored_puts"
|
6
6
|
require "io/console"
|
7
|
+
require "discorb"
|
7
8
|
|
8
9
|
ARGV.delete_at 0
|
9
|
-
# @private
|
10
|
-
LOG_LEVELS = %w[none debug info warn error fatal].freeze
|
11
10
|
|
12
11
|
opt = OptionParser.new <<~BANNER
|
13
12
|
This command will run a client.
|
@@ -18,23 +17,10 @@ opt = OptionParser.new <<~BANNER
|
|
18
17
|
BANNER
|
19
18
|
options = {
|
20
19
|
title: nil,
|
21
|
-
log_level: nil,
|
22
|
-
log_file: nil,
|
23
|
-
log_color: nil,
|
24
20
|
setup: nil,
|
25
21
|
token: false,
|
26
22
|
bundler: :default,
|
27
23
|
}
|
28
|
-
opt.on("-l", "--log-level LEVEL", "Log level.") do |v|
|
29
|
-
unless LOG_LEVELS.include? v.downcase
|
30
|
-
eputs "Invalid log level: \e[31m#{v}\e[91m"
|
31
|
-
eputs "Valid log levels: \e[31m#{LOG_LEVELS.join("\e[91m, \e[31m")}\e[91m"
|
32
|
-
exit 1
|
33
|
-
end
|
34
|
-
options[:log_level] = v.downcase
|
35
|
-
end
|
36
|
-
opt.on("-f", "--log-file FILE", "File to write log to.") { |v| options[:log_file] = v }
|
37
|
-
opt.on("-c", "--[no-]log-color", "Whether to colorize log output.") { |v| options[:log_color] = v }
|
38
24
|
opt.on("-s", "--setup", "Whether to setup application commands.") { |v| options[:setup] = v }
|
39
25
|
opt.on("-e", "--env [ENV]", "The name of the environment variable to use for token, or just `-e` or `--env` for intractive prompt.") { |v| options[:token] = v }
|
40
26
|
opt.on("-t", "--title TITLE", "The title of process.") { |v| options[:title] = v }
|