discorb 0.11.4 → 0.12.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/PULL_REQUEST_TEMPLATE.md +30 -0
- data/CONTRIBUTING.md +25 -0
- data/Changelog.md +23 -0
- data/README.md +2 -1
- data/docs/cli/run.md +2 -1
- data/lib/discorb/app_command.rb +14 -0
- data/lib/discorb/client.rb +46 -38
- data/lib/discorb/common.rb +1 -1
- data/lib/discorb/error.rb +8 -5
- data/lib/discorb/exe/run.rb +16 -1
- data/lib/discorb/gateway.rb +30 -23
- data/lib/discorb/integration.rb +1 -1
- data/lib/discorb/interaction/autocomplete.rb +49 -0
- data/lib/discorb/interaction/command.rb +142 -0
- data/lib/discorb/interaction/components.rb +85 -0
- data/lib/discorb/interaction/response.rb +188 -0
- data/lib/discorb/interaction/root.rb +94 -0
- data/lib/discorb/interaction.rb +2 -618
- data/lib/discorb/message.rb +25 -23
- data/lib/discorb/user.rb +7 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97e8934c0d9286dcc626010c68600a4a60526e2e63a6446a7b641a52c839f611
|
4
|
+
data.tar.gz: 4da595714d4957e17f2fa2a8f2d62001a4194ef1c78b3ef72ae88337c0df92fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '09ae808debab6b7372df86f62a32c2fc2a55f64bd8ac5c85d39aee62f10e9e9cb4351cf07ae91a6a493b1874062e92aaa4dbed7da61665ca1718426615145035'
|
7
|
+
data.tar.gz: b62074077a30a3577a34174c4b4183196734df8b6ef9ee4b05bb037bbe04e7c67019460b4558caf6d815a1569779cade308bb26d476daa89d06087736cd86a4f
|
@@ -0,0 +1,30 @@
|
|
1
|
+
## What does this PR do?
|
2
|
+
|
3
|
+
<!--
|
4
|
+
Please describe the changes you are making (be as descriptive as possible).
|
5
|
+
Ex: Fix `Foo#bar`
|
6
|
+
Add `Hoge#fuga`
|
7
|
+
-->
|
8
|
+
|
9
|
+
## Information
|
10
|
+
|
11
|
+
- [ ] This PR fixes an issue.
|
12
|
+
- [ ] This PR adds a new feature.
|
13
|
+
- [ ] This PR refactors code.
|
14
|
+
- [ ] This PR has breaking changes.
|
15
|
+
- [ ] This PR **won't** change the behavior of the code. (e.g. documentation)
|
16
|
+
<!-- If you need to add more information, please add it here. -->
|
17
|
+
|
18
|
+
|
19
|
+
## Checklist
|
20
|
+
|
21
|
+
- [ ] I have reviewed the code and it is clean and well documented.
|
22
|
+
- [ ] I have ran bot and it is working as expected.
|
23
|
+
- [ ] I have updated the document.
|
24
|
+
|
25
|
+
## Related issues
|
26
|
+
|
27
|
+
<!--
|
28
|
+
If there are any related issues, please add them here.
|
29
|
+
If there are no related issues, please write `None`.
|
30
|
+
-->
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Contributing to the project
|
2
|
+
|
3
|
+
## Submitting a bug report
|
4
|
+
|
5
|
+
Please follow these steps to report a bug:
|
6
|
+
1. Check if the bug already exists in issue tracker. Don't forget to search closed issues too.
|
7
|
+
2. Create issue from [the template](https://github.com/discorb-lib/discorb/issues/new?assignees=&labels=bug&template=bug_report.md).
|
8
|
+
3. Fill in the issue with the information about the bug.
|
9
|
+
4. Submit the issue.
|
10
|
+
|
11
|
+
## Submitting a feature request
|
12
|
+
|
13
|
+
Please follow these steps to request a feature:
|
14
|
+
1. Check if the feature already exists in main branch.
|
15
|
+
2. Check if the request already exists in issue tracker. Don't forget to search closed issues too.
|
16
|
+
3. Create issue from [the template](https://github.com/discorb-lib/discorb/issues/new?assignees=&labels=Feature+Request%2CEnhancement&template=feature_request.md).
|
17
|
+
4. Fill in the issue with the information about the feature.
|
18
|
+
5. Submit the issue.
|
19
|
+
|
20
|
+
## Submitting a pull request
|
21
|
+
|
22
|
+
Please follow these steps to request a pull request:
|
23
|
+
1. Check if the thing you want to request already exists in main branch.
|
24
|
+
2. Check if the request already exists and is merged or closed.
|
25
|
+
3. [Create a pull request](https://github.com/discorb-lib/discorb/compare).
|
data/Changelog.md
CHANGED
@@ -2,6 +2,29 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
## v0.12
|
6
|
+
|
7
|
+
### v0.12.3
|
8
|
+
|
9
|
+
- Fix: Fix NoMethodError in command interaction
|
10
|
+
- Fix: Fix NoMethodError in Integration#initialize
|
11
|
+
|
12
|
+
### v0.12.2
|
13
|
+
|
14
|
+
- Fix: Fix `Message#type`
|
15
|
+
- Change: `discorb run` will lookup for `main.rb` in parent directories
|
16
|
+
|
17
|
+
### v0.12.1
|
18
|
+
|
19
|
+
- Fix: Fix some texts
|
20
|
+
- Add: Add `User#mention`
|
21
|
+
|
22
|
+
### v0.12.0
|
23
|
+
|
24
|
+
- Refactor: Refactor the code
|
25
|
+
- Fix: Fix resuming gateway, finally
|
26
|
+
- Fix: Fix `@client` in slash command handler in extension
|
27
|
+
|
5
28
|
## v0.11
|
6
29
|
|
7
30
|
### v0.11.4
|
data/README.md
CHANGED
@@ -4,7 +4,8 @@
|
|
4
4
|
<a href="https://rubygems.org/gems/discorb"><img src="https://img.shields.io/gem/dt/discorb?logo=rubygems&logoColor=fff&label=Downloads&style=flat-square&labelColor=2f3136" alt="Gem"></a>
|
5
5
|
<a href="https://rubygems.org/gems/discorb"><img src="https://img.shields.io/gem/v/discorb?logo=rubygems&logoColor=fff&label=Version&style=flat-square&labelColor=2f3136" alt="Gem"></a>
|
6
6
|
<a href="https://discord.gg/hCP6zq8Vpj"><img src="https://img.shields.io/discord/863581274916913193?logo=discord&logoColor=fff&color=5865f2&label=Discord&style=flat-square&labelColor=2f3136" alt="Discord"></a>
|
7
|
-
<a href="https://github.com/discorb-lib/discorb"><img src="https://img.shields.io/github/stars/discorb-lib/discorb?color=24292e&label=Stars&logo=GitHub&logoColor=fff&style=flat-square&labelColor=2f3136" alt="GitHub"></a
|
7
|
+
<a href="https://github.com/discorb-lib/discorb"><img src="https://img.shields.io/github/stars/discorb-lib/discorb?color=24292e&label=Stars&logo=GitHub&logoColor=fff&style=flat-square&labelColor=2f3136" alt="GitHub"></a>
|
8
|
+
<a href="https://codeclimate.com/github/discorb-lib/discorb"><img alt="Code Climate maintainability" src="https://img.shields.io/codeclimate/maintainability/discorb-lib/discorb?logo=Code%20Climate&logoColor=ffffff&style=flat-square&labelColor=2f3136&label=Maintainability"></a></div>
|
8
9
|
|
9
10
|
----
|
10
11
|
|
data/docs/cli/run.md
CHANGED
@@ -16,6 +16,7 @@ discorb run [options] [script]
|
|
16
16
|
#### `script`
|
17
17
|
|
18
18
|
The script to run. Defaults to `main.rb`.
|
19
|
+
If the script wasn't specified, it will also look for a file named `main.rb` in the parent directories, like rake.
|
19
20
|
|
20
21
|
### Options
|
21
22
|
|
@@ -57,4 +58,4 @@ The name of the environment variable to use for token, or just `-t` or `--token`
|
|
57
58
|
|
58
59
|
#### `-b`, `--bundler`
|
59
60
|
|
60
|
-
Whether to use bundler to load the script.
|
61
|
+
Whether to use bundler to load the script.
|
data/lib/discorb/app_command.rb
CHANGED
@@ -172,6 +172,14 @@ module Discorb
|
|
172
172
|
@id_map = Discorb::Dictionary.new
|
173
173
|
end
|
174
174
|
|
175
|
+
# @private
|
176
|
+
def replace_block(instance)
|
177
|
+
current_block = @block.dup
|
178
|
+
@block = Proc.new do |*args|
|
179
|
+
instance.instance_exec(*args, ¤t_block)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
175
183
|
# @private
|
176
184
|
def to_hash
|
177
185
|
{
|
@@ -314,6 +322,12 @@ module Discorb
|
|
314
322
|
@name
|
315
323
|
end
|
316
324
|
|
325
|
+
# @private
|
326
|
+
def block_replace(instance)
|
327
|
+
super
|
328
|
+
@commands.each { |c| c.replace_block(instance) }
|
329
|
+
end
|
330
|
+
|
317
331
|
# @private
|
318
332
|
def to_hash
|
319
333
|
options_payload = @commands.map do |command|
|
data/lib/discorb/client.rb
CHANGED
@@ -395,10 +395,11 @@ module Discorb
|
|
395
395
|
end
|
396
396
|
end
|
397
397
|
@commands.delete_if do |cmd|
|
398
|
-
cmd.respond_to? :extension and cmd.extension == ins.name
|
398
|
+
cmd.respond_to? :extension and cmd.extension == ins.class.name
|
399
399
|
end
|
400
400
|
ins.class.commands.each do |cmd|
|
401
|
-
cmd.define_singleton_method(:extension) { ins.name }
|
401
|
+
cmd.define_singleton_method(:extension) { ins.class.name }
|
402
|
+
cmd.replace_block(ins)
|
402
403
|
@commands << cmd
|
403
404
|
end
|
404
405
|
|
@@ -419,50 +420,19 @@ module Discorb
|
|
419
420
|
#
|
420
421
|
# @param [String, nil] token The token to use.
|
421
422
|
#
|
422
|
-
# @note If the token is nil, you should use `discorb run` with the `-
|
423
|
+
# @note If the token is nil, you should use `discorb run` with the `-e` or `--env` option.
|
423
424
|
#
|
424
425
|
def run(token = nil)
|
425
426
|
token ||= ENV["DISCORB_CLI_TOKEN"]
|
426
|
-
raise ArgumentError, "Token is not specified, and -
|
427
|
+
raise ArgumentError, "Token is not specified, and -e/--env is not specified" if token.nil?
|
427
428
|
case ENV["DISCORB_CLI_FLAG"]
|
428
429
|
when nil
|
429
430
|
start_client(token)
|
430
431
|
when "run"
|
431
|
-
|
432
|
-
options = JSON.parse(ENV["DISCORB_CLI_OPTIONS"], symbolize_names: true)
|
433
|
-
@daemon = options[:daemon]
|
434
|
-
|
435
|
-
setup_commands(token) if options[:setup]
|
436
|
-
if options[:log_level]
|
437
|
-
if options[:log_level] == "none"
|
438
|
-
@log.out = nil
|
439
|
-
else
|
440
|
-
@log.out = case options[:log_file]
|
441
|
-
when nil, "stderr"
|
442
|
-
$stderr
|
443
|
-
when "stdout"
|
444
|
-
$stdout
|
445
|
-
else
|
446
|
-
::File.open(options[:log_file], "a")
|
447
|
-
end
|
448
|
-
@log.level = options[:log_level].to_sym
|
449
|
-
@log.colorize_log = options[:log_color] == nil ? @log.out.isatty : options[:log_color]
|
450
|
-
end
|
451
|
-
end
|
432
|
+
before_run(token)
|
452
433
|
start_client(token)
|
453
434
|
when "setup"
|
454
|
-
|
455
|
-
if guilds = ENV["DISCORB_SETUP_GUILDS"]
|
456
|
-
guild_ids = guilds.split(",")
|
457
|
-
end
|
458
|
-
if guild_ids == ["global"]
|
459
|
-
guild_ids = false
|
460
|
-
end
|
461
|
-
setup_commands(token, guild_ids: guild_ids).wait
|
462
|
-
@events[:setup]&.each do |event|
|
463
|
-
event.call
|
464
|
-
end
|
465
|
-
self.on_setup if respond_to? :on_setup
|
435
|
+
run_setup(token)
|
466
436
|
end
|
467
437
|
end
|
468
438
|
|
@@ -478,10 +448,48 @@ module Discorb
|
|
478
448
|
|
479
449
|
private
|
480
450
|
|
451
|
+
def before_run(token)
|
452
|
+
require "json"
|
453
|
+
options = JSON.parse(ENV["DISCORB_CLI_OPTIONS"], symbolize_names: true)
|
454
|
+
setup_commands(token) if options[:setup]
|
455
|
+
if options[:log_level]
|
456
|
+
if options[:log_level] == "none"
|
457
|
+
@log.out = nil
|
458
|
+
else
|
459
|
+
@log.out = case options[:log_file]
|
460
|
+
when nil, "stderr"
|
461
|
+
$stderr
|
462
|
+
when "stdout"
|
463
|
+
$stdout
|
464
|
+
else
|
465
|
+
::File.open(options[:log_file], "a")
|
466
|
+
end
|
467
|
+
@log.level = options[:log_level].to_sym
|
468
|
+
@log.colorize_log = options[:log_color] == nil ? @log.out.isatty : options[:log_color]
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
def run_setup(token)
|
474
|
+
guild_ids = "global"
|
475
|
+
if guilds = ENV["DISCORB_SETUP_GUILDS"]
|
476
|
+
guild_ids = guilds.split(",")
|
477
|
+
end
|
478
|
+
if guild_ids == ["global"]
|
479
|
+
guild_ids = false
|
480
|
+
end
|
481
|
+
setup_commands(token, guild_ids: guild_ids).wait
|
482
|
+
@events[:setup]&.each do |event|
|
483
|
+
event.call
|
484
|
+
end
|
485
|
+
self.on_setup if respond_to? :on_setup
|
486
|
+
end
|
487
|
+
|
481
488
|
def start_client(token)
|
482
489
|
Async do |task|
|
483
|
-
trap(:SIGINT) {
|
490
|
+
Signal.trap(:SIGINT) {
|
484
491
|
@log.info "SIGINT received, closing..."
|
492
|
+
Signal.trap(:SIGINT, "DEFAULT")
|
485
493
|
close!
|
486
494
|
}
|
487
495
|
@token = token.to_s
|
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/v9"
|
6
6
|
# @return [String] The version of discorb.
|
7
|
-
VERSION = "0.
|
7
|
+
VERSION = "0.12.3"
|
8
8
|
# @return [String] The user agent for the bot.
|
9
9
|
USER_AGENT = "DiscordBot (https://discorb-lib.github.io #{VERSION}) Ruby/#{RUBY_VERSION}"
|
10
10
|
|
data/lib/discorb/error.rb
CHANGED
@@ -38,7 +38,8 @@ module Discorb
|
|
38
38
|
# @abstract
|
39
39
|
#
|
40
40
|
class HTTPError < DiscorbError
|
41
|
-
# @return [String] the
|
41
|
+
# @return [String] the JSON response code.
|
42
|
+
# @see https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes
|
42
43
|
attr_reader :code
|
43
44
|
# @return [Net::HTTPResponse] the HTTP response.
|
44
45
|
attr_reader :response
|
@@ -47,7 +48,7 @@ module Discorb
|
|
47
48
|
def initialize(resp, data)
|
48
49
|
@code = data[:code]
|
49
50
|
@response = resp
|
50
|
-
super(data[:message])
|
51
|
+
super(data[:message] + " (#{@code})")
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
@@ -60,9 +61,11 @@ module Discorb
|
|
60
61
|
@code = data[:code]
|
61
62
|
@response = resp
|
62
63
|
DiscorbError.instance_method(:initialize).bind(self).call(
|
63
|
-
[
|
64
|
-
"#{
|
65
|
-
|
64
|
+
[
|
65
|
+
data[:message] + " (#{@code})", enumerate_errors(data[:errors])
|
66
|
+
.map { |ek, ev| "#{ek}=>#{ev}" }
|
67
|
+
.join("\n"),
|
68
|
+
].join("\n")
|
66
69
|
)
|
67
70
|
end
|
68
71
|
end
|
data/lib/discorb/exe/run.rb
CHANGED
@@ -42,7 +42,22 @@ opt.parse!(ARGV)
|
|
42
42
|
|
43
43
|
script = ARGV[0]
|
44
44
|
|
45
|
-
script
|
45
|
+
if script.nil?
|
46
|
+
script = "main.rb"
|
47
|
+
dir = Dir.pwd
|
48
|
+
loop do
|
49
|
+
if File.exist?(File.join(dir, "main.rb"))
|
50
|
+
script = File.join(dir, "main.rb")
|
51
|
+
break
|
52
|
+
end
|
53
|
+
break if dir == File.dirname(dir)
|
54
|
+
dir = File.dirname(dir)
|
55
|
+
end
|
56
|
+
if File.dirname(script) != Dir.pwd
|
57
|
+
Dir.chdir(File.dirname(script))
|
58
|
+
iputs "Changed directory to \e[m#{File.dirname(script)}"
|
59
|
+
end
|
60
|
+
end
|
46
61
|
|
47
62
|
ENV["DISCORB_CLI_FLAG"] = "run"
|
48
63
|
ENV["DISCORB_CLI_OPTIONS"] = JSON.generate(options)
|
data/lib/discorb/gateway.rb
CHANGED
@@ -482,38 +482,44 @@ module Discorb
|
|
482
482
|
private
|
483
483
|
|
484
484
|
def connect_gateway(reconnect)
|
485
|
-
|
485
|
+
if reconnect
|
486
|
+
@log.info "Reconnecting to gateway..."
|
487
|
+
else
|
488
|
+
@log.info "Connecting to gateway..."
|
489
|
+
end
|
486
490
|
Async do
|
491
|
+
@connection&.close
|
487
492
|
@http = HTTP.new(self)
|
488
493
|
_, gateway_response = @http.get("/gateway").wait
|
489
494
|
gateway_url = gateway_response[:url]
|
490
495
|
endpoint = Async::HTTP::Endpoint.parse("#{gateway_url}?v=9&encoding=json&compress=zlib-stream",
|
491
496
|
alpn_protocols: Async::HTTP::Protocol::HTTP11.names)
|
492
497
|
begin
|
493
|
-
Async::WebSocket::Client.connect(endpoint, headers: [["User-Agent", Discorb::USER_AGENT]], handler: RawConnection)
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
handle_gateway(message, reconnect)
|
511
|
-
end
|
498
|
+
@connection = Async::WebSocket::Client.connect(endpoint, headers: [["User-Agent", Discorb::USER_AGENT]], handler: RawConnection)
|
499
|
+
@zlib_stream = Zlib::Inflate.new(Zlib::MAX_WBITS)
|
500
|
+
buffer = +""
|
501
|
+
begin
|
502
|
+
while (message = @connection.read)
|
503
|
+
buffer << message
|
504
|
+
if message.end_with?((+"\x00\x00\xff\xff").force_encoding("ASCII-8BIT"))
|
505
|
+
begin
|
506
|
+
data = @zlib_stream.inflate(buffer)
|
507
|
+
buffer = +""
|
508
|
+
message = JSON.parse(data, symbolize_names: true)
|
509
|
+
rescue JSON::ParserError
|
510
|
+
buffer = +""
|
511
|
+
@log.error "Received invalid JSON from gateway."
|
512
|
+
@log.debug "#{data}"
|
513
|
+
else
|
514
|
+
handle_gateway(message, reconnect)
|
512
515
|
end
|
513
516
|
end
|
514
|
-
rescue EOFError, Async::Wrapper::Cancelled, Async::Wrapper::WaitError
|
515
|
-
# Ignore
|
516
517
|
end
|
518
|
+
rescue Async::Wrapper::Cancelled, OpenSSL::SSL::SSLError, Async::Wrapper::WaitError, EOFError => e
|
519
|
+
@log.error "Gateway connection closed: #{e.class}: #{e.message}"
|
520
|
+
connect_gateway(true)
|
521
|
+
else # should never happen
|
522
|
+
connect_gateway(true)
|
517
523
|
end
|
518
524
|
rescue Protocol::WebSocket::ClosedError => e
|
519
525
|
@tasks.map(&:stop)
|
@@ -542,7 +548,7 @@ module Discorb
|
|
542
548
|
connect_gateway(false)
|
543
549
|
end
|
544
550
|
rescue => e
|
545
|
-
@log.error "Discord WebSocket error: #{e.
|
551
|
+
@log.error "Discord WebSocket error: #{e.full_message}"
|
546
552
|
connect_gateway(false)
|
547
553
|
end
|
548
554
|
end
|
@@ -1034,6 +1040,7 @@ module Discorb
|
|
1034
1040
|
dispatch(interaction.class.event_name, interaction)
|
1035
1041
|
when "RESUMED"
|
1036
1042
|
@log.info("Successfully resumed connection")
|
1043
|
+
@tasks << handle_heartbeat
|
1037
1044
|
dispatch(:resumed)
|
1038
1045
|
else
|
1039
1046
|
if respond_to?("event_" + event_name.downcase)
|
data/lib/discorb/integration.rb
CHANGED
@@ -84,7 +84,7 @@ module Discorb
|
|
84
84
|
@account = Account.new(data[:account])
|
85
85
|
@subscriber_count = data[:subscriber_count]
|
86
86
|
@revoked = data[:revoked]
|
87
|
-
@application = Application.new(@client, data[:application])
|
87
|
+
@application = data[:application] and Application.new(@client, data[:application])
|
88
88
|
end
|
89
89
|
|
90
90
|
class << self
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Discorb
|
2
|
+
#
|
3
|
+
# Represents auto complete interaction.
|
4
|
+
#
|
5
|
+
class AutoComplete < Interaction
|
6
|
+
@interaction_type = 4
|
7
|
+
@interaction_name = :auto_complete
|
8
|
+
|
9
|
+
# @private
|
10
|
+
def _set_data(data)
|
11
|
+
super
|
12
|
+
Sync do
|
13
|
+
name, options = Discorb::CommandInteraction::SlashCommand.get_command_data(data)
|
14
|
+
|
15
|
+
unless (command = @client.bottom_commands.find { |c| c.to_s == name && c.type_raw == 1 })
|
16
|
+
@client.log.warn "Unknown command name #{name}, ignoring"
|
17
|
+
next
|
18
|
+
end
|
19
|
+
|
20
|
+
option_map = command.options.map { |k, v| [k.to_s, v[:default]] }.to_h
|
21
|
+
Discorb::CommandInteraction::SlashCommand.modify_option_map(option_map, options, guild)
|
22
|
+
focused_index = options.find_index { |o| o[:focused] }
|
23
|
+
val = command.options.values[focused_index][:autocomplete]&.call(self, *command.options.map { |k, v| option_map[k.to_s] })
|
24
|
+
send_complete_result(val)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @private
|
29
|
+
def send_complete_result(val)
|
30
|
+
@client.http.post("/interactions/#{@id}/#{@token}/callback", {
|
31
|
+
type: 8,
|
32
|
+
data: {
|
33
|
+
choices: val.map do |vk, vv|
|
34
|
+
{
|
35
|
+
name: vk,
|
36
|
+
value: vv,
|
37
|
+
}
|
38
|
+
end,
|
39
|
+
},
|
40
|
+
}).wait
|
41
|
+
rescue Discorb::NotFoundError
|
42
|
+
@client.log.warn "Failed to send auto complete result, This may be caused by the suggestion is taking too long (over 3 seconds) to respond", fallback: $stderr
|
43
|
+
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
alias make_interaction new
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Discorb
|
2
|
+
#
|
3
|
+
# Represents a command interaction.
|
4
|
+
#
|
5
|
+
class CommandInteraction < Interaction
|
6
|
+
@interaction_type = 2
|
7
|
+
@interaction_name = :application_command
|
8
|
+
include Interaction::SourceResponse
|
9
|
+
|
10
|
+
#
|
11
|
+
# Represents a slash command interaction.
|
12
|
+
#
|
13
|
+
class SlashCommand < CommandInteraction
|
14
|
+
@command_type = 1
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def _set_data(data)
|
19
|
+
super
|
20
|
+
|
21
|
+
name, options = SlashCommand.get_command_data(data)
|
22
|
+
|
23
|
+
unless (command = @client.bottom_commands.find { |c| c.to_s == name && c.type_raw == 1 })
|
24
|
+
@client.log.warn "Unknown command name #{name}, ignoring"
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
option_map = command.options.map { |k, v| [k.to_s, v[:default]] }.to_h
|
29
|
+
SlashCommand.modify_option_map(option_map, options, guild)
|
30
|
+
|
31
|
+
command.block.call(self, *command.options.map { |k, v| option_map[k.to_s] })
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
# @private
|
36
|
+
def get_command_data(data)
|
37
|
+
name = data[:name]
|
38
|
+
options = nil
|
39
|
+
return name, options unless (option = data[:options]&.first)
|
40
|
+
|
41
|
+
case option[:type]
|
42
|
+
when 1
|
43
|
+
name += " #{option[:name]}"
|
44
|
+
options = option[:options]
|
45
|
+
when 2
|
46
|
+
name += " #{option[:name]}"
|
47
|
+
unless option[:options]&.first&.[](:type) == 1
|
48
|
+
options = option[:options]
|
49
|
+
return name, options
|
50
|
+
end
|
51
|
+
option_sub = option[:options]&.first
|
52
|
+
name += " #{option_sub[:name]}"
|
53
|
+
options = option_sub[:options]
|
54
|
+
else
|
55
|
+
options = data[:options]
|
56
|
+
end
|
57
|
+
|
58
|
+
return name, options
|
59
|
+
end
|
60
|
+
|
61
|
+
# @private
|
62
|
+
def modify_option_map(option_map, options, guild)
|
63
|
+
options ||= []
|
64
|
+
options.each_with_index do |option|
|
65
|
+
val = case option[:type]
|
66
|
+
when 3, 4, 5, 10
|
67
|
+
option[:value]
|
68
|
+
when 6
|
69
|
+
guild.members[option[:value]] || guild.fetch_member(option[:value]).wait
|
70
|
+
when 7
|
71
|
+
guild.channels[option[:value]] || guild.fetch_channels.wait.find { |channel| channel.id == option[:value] }
|
72
|
+
when 8
|
73
|
+
guild.roles[option[:value]] || guild.fetch_roles.wait.find { |role| role.id == option[:value] }
|
74
|
+
when 9
|
75
|
+
guild.members[option[:value]] || guild.roles[option[:value]] || guild.fetch_member(option[:value]).wait || guild.fetch_roles.wait.find { |role| role.id == option[:value] }
|
76
|
+
end
|
77
|
+
option_map[option[:name]] = val
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# Represents a user context menu interaction.
|
85
|
+
#
|
86
|
+
class UserMenuCommand < CommandInteraction
|
87
|
+
@command_type = 2
|
88
|
+
|
89
|
+
# @return [Discorb::Member, Discorb::User] The target user.
|
90
|
+
attr_reader :target
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def _set_data(data)
|
95
|
+
@target = guild.members[data[:target_id]] || Discorb::Member.new(@client, @guild_id, data[:resolved][:users][data[:target_id].to_sym], data[:resolved][:members][data[:target_id].to_sym])
|
96
|
+
@client.commands.find { |c| c.name == data[:name] && c.type_raw == 2 }.block.call(self, @target)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Represents a message context menu interaction.
|
102
|
+
#
|
103
|
+
class MessageMenuCommand < CommandInteraction
|
104
|
+
@command_type = 3
|
105
|
+
|
106
|
+
# @return [Discorb::Message] The target message.
|
107
|
+
attr_reader :target
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def _set_data(data)
|
112
|
+
@target = Message.new(@client, data[:resolved][:messages][data[:target_id].to_sym].merge(guild_id: @guild_id.to_s))
|
113
|
+
@client.commands.find { |c| c.name == data[:name] && c.type_raw == 3 }.block.call(self, @target)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def _set_data(data)
|
120
|
+
@name = data[:name]
|
121
|
+
end
|
122
|
+
|
123
|
+
class << self
|
124
|
+
# @private
|
125
|
+
attr_reader :command_type
|
126
|
+
|
127
|
+
# @private
|
128
|
+
def make_interaction(client, data)
|
129
|
+
nested_classes.each do |klass|
|
130
|
+
return klass.new(client, data) if !klass.command_type.nil? && klass.command_type == data[:data][:type]
|
131
|
+
end
|
132
|
+
client.log.warn("Unknown command type #{data[:type]}, initialized CommandInteraction")
|
133
|
+
CommandInteraction.new(client, data)
|
134
|
+
end
|
135
|
+
|
136
|
+
# @private
|
137
|
+
def nested_classes
|
138
|
+
constants.select { |c| const_get(c).is_a? Class }.map { |c| const_get(c) }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|