discorb 0.11.2 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/PULL_REQUEST_TEMPLATE.md +30 -0
- data/CONTRIBUTING.md +25 -0
- data/Changelog.md +22 -0
- data/README.md +2 -1
- data/lib/discorb/app_command.rb +14 -0
- data/lib/discorb/channel.rb +0 -42
- data/lib/discorb/client.rb +46 -38
- data/lib/discorb/common.rb +7 -1
- data/lib/discorb/error.rb +8 -5
- data/lib/discorb/gateway.rb +30 -23
- 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 +3 -1
- data/lib/discorb/modules.rb +42 -0
- 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: 2f43c7785e34661458d9837fd1e75877b8d343f8c920021624d92d0fb87c5ee3
|
4
|
+
data.tar.gz: f5b1ed37f600c0b2945d737a154c9d07155d38dad1b8c3da58fc209fa2db99a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42f7ffe2b1a851123d883f98223b7c8a755d40faff16a29c1eeecc58e3e023817c5a865bd2aaab52001a8311458a656e034de1f3349ed7778b033afd49840634
|
7
|
+
data.tar.gz: 3a6789362788a6c16e38ead2f6d463162f6e852da84df703ef90e32e27477fafb3ce611c931c9f1d9516275f21fb7229e4cec51b0110720b870a2d30f474120d
|
@@ -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,8 +2,30 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
## v0.12
|
6
|
+
|
7
|
+
### v0.12.1
|
8
|
+
|
9
|
+
- Fix: Fix some texts
|
10
|
+
- Add: Add `User#mention`
|
11
|
+
|
12
|
+
### v0.12.0
|
13
|
+
|
14
|
+
- Refactor: Refactor the code
|
15
|
+
- Fix: Fix resuming gateway, finally
|
16
|
+
- Fix: Fix `@client` in slash command handler in extension
|
17
|
+
|
5
18
|
## v0.11
|
6
19
|
|
20
|
+
### v0.11.4
|
21
|
+
|
22
|
+
- Fix: Fix unpinning messages
|
23
|
+
|
24
|
+
### v0.11.3
|
25
|
+
|
26
|
+
- Add: Add `Snowflake#id` as alias for `Snowflake#to_s`
|
27
|
+
- Fix: Fix `Message#unpin`
|
28
|
+
|
7
29
|
### v0.11.2
|
8
30
|
|
9
31
|
- Add: Add `setup` event
|
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/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/channel.rb
CHANGED
@@ -482,48 +482,6 @@ module Discorb
|
|
482
482
|
end
|
483
483
|
end
|
484
484
|
|
485
|
-
#
|
486
|
-
# Fetch the pinned messages in the channel.
|
487
|
-
# @macro async
|
488
|
-
# @macro http
|
489
|
-
#
|
490
|
-
# @return [Async::Task<Array<Discorb::Message>>] The pinned messages in the channel.
|
491
|
-
#
|
492
|
-
def fetch_pins
|
493
|
-
Async do
|
494
|
-
_resp, data = @client.http.get("/channels/#{@id}/pins").wait
|
495
|
-
data.map { |pin| Message.new(@client, pin) }
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
#
|
500
|
-
# Pin a message in the channel.
|
501
|
-
# @macro async
|
502
|
-
# @macro http
|
503
|
-
#
|
504
|
-
# @param [Discorb::Message] message The message to pin.
|
505
|
-
# @param [String] reason The reason of pinning the message.
|
506
|
-
#
|
507
|
-
def pin_message(message, reason: nil)
|
508
|
-
Async do
|
509
|
-
@client.http.put("/channels/#{@id}/pins/#{message.id}", {}, audit_log_reason: reason).wait
|
510
|
-
end
|
511
|
-
end
|
512
|
-
|
513
|
-
#
|
514
|
-
# Unpin a message in the channel.
|
515
|
-
# @macro async
|
516
|
-
# @macro http
|
517
|
-
#
|
518
|
-
# @param [Discorb::Message] message The message to unpin.
|
519
|
-
# @param [String] reason The reason of unpinning the message.
|
520
|
-
#
|
521
|
-
def unpin_message(message, reason: nil)
|
522
|
-
Async do
|
523
|
-
@client.http.delete("/channels/#{@id}/pins/#{message.id}", {}, audit_log_reason: reason).wait
|
524
|
-
end
|
525
|
-
end
|
526
|
-
|
527
485
|
#
|
528
486
|
# Start thread in the channel.
|
529
487
|
# @macro async
|
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.1"
|
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
|
|
@@ -64,6 +64,10 @@ module Discorb
|
|
64
64
|
# Increment of snowflake.
|
65
65
|
#
|
66
66
|
# @return [Integer] Increment of snowflake.
|
67
|
+
# @!attribute [r] id
|
68
|
+
# Alias of to_s.
|
69
|
+
#
|
70
|
+
# @return [String] The snowflake.
|
67
71
|
|
68
72
|
#
|
69
73
|
# Compares snowflake with other object.
|
@@ -105,5 +109,7 @@ module Discorb
|
|
105
109
|
def increment
|
106
110
|
@value & 0xFFF
|
107
111
|
end
|
112
|
+
|
113
|
+
alias id to_s
|
108
114
|
end
|
109
115
|
end
|
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/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)
|
@@ -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)
|
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)
|
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)
|
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
|