discorb 0.15.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitattributes +1 -0
- data/.github/workflows/build_main.yml +2 -2
- data/.github/workflows/build_version.yml +1 -1
- data/.github/workflows/codeql-analysis.yml +1 -1
- data/.github/workflows/lint-push.yml +3 -5
- data/.github/workflows/lint.yml +1 -1
- data/.github/workflows/spec.yml +30 -0
- data/.lefthook/commit-msg/validator.rb +5 -0
- data/.rspec +2 -0
- data/.rspec_parallel +2 -0
- data/.rubocop.yml +49 -8
- data/Changelog.md +32 -1
- data/Gemfile +14 -8
- data/Rakefile +46 -25
- data/bin/console +3 -3
- data/docs/Examples.md +1 -1
- data/docs/application_command.md +138 -46
- data/docs/cli/irb.md +2 -2
- data/docs/cli/new.md +14 -9
- data/docs/cli/run.md +7 -11
- data/docs/cli.md +17 -10
- data/docs/events.md +257 -193
- data/docs/extension.md +1 -2
- data/docs/faq.md +0 -1
- data/docs/tutorial.md +12 -12
- data/docs/voice_events.md +106 -106
- data/examples/commands/message.rb +63 -0
- data/examples/commands/permission.rb +18 -0
- data/examples/commands/slash.rb +44 -0
- data/examples/commands/user.rb +51 -0
- data/examples/components/authorization_button.rb +2 -2
- data/examples/components/select_menu.rb +2 -2
- data/examples/extension/main.rb +1 -1
- data/examples/extension/message_expander.rb +5 -2
- data/examples/simple/eval.rb +2 -2
- data/examples/simple/ping_pong.rb +1 -1
- data/examples/simple/rolepanel.rb +2 -2
- data/examples/simple/shard.rb +17 -0
- data/examples/simple/wait_for_message.rb +1 -1
- data/exe/discorb +31 -16
- data/lefthook.yml +45 -0
- data/lib/discorb/allowed_mentions.rb +8 -0
- data/lib/discorb/app_command/command.rb +184 -60
- data/lib/discorb/app_command/common.rb +25 -0
- data/lib/discorb/app_command/handler.rb +116 -34
- data/lib/discorb/app_command.rb +2 -1
- data/lib/discorb/application.rb +17 -7
- data/lib/discorb/asset.rb +10 -2
- data/lib/discorb/attachment.rb +17 -2
- data/lib/discorb/audit_logs.rb +53 -12
- data/lib/discorb/channel/base.rb +108 -0
- data/lib/discorb/channel/category.rb +32 -0
- data/lib/discorb/channel/container.rb +44 -0
- data/lib/discorb/channel/dm.rb +28 -0
- data/lib/discorb/channel/guild.rb +245 -0
- data/lib/discorb/channel/stage.rb +140 -0
- data/lib/discorb/channel/text.rb +345 -0
- data/lib/discorb/channel/thread.rb +321 -0
- data/lib/discorb/channel/voice.rb +79 -0
- data/lib/discorb/channel.rb +2 -1126
- data/lib/discorb/client.rb +160 -64
- data/lib/discorb/common.rb +18 -3
- data/lib/discorb/components/button.rb +7 -7
- data/lib/discorb/components/select_menu.rb +6 -18
- data/lib/discorb/components/text_input.rb +12 -2
- data/lib/discorb/components.rb +1 -1
- data/lib/discorb/dictionary.rb +2 -0
- data/lib/discorb/embed.rb +55 -14
- data/lib/discorb/emoji.rb +59 -5
- data/lib/discorb/emoji_table.rb +4970 -4
- data/lib/discorb/error.rb +7 -1
- data/lib/discorb/event.rb +56 -21
- data/lib/discorb/exe/about.rb +1 -0
- data/lib/discorb/exe/irb.rb +2 -4
- data/lib/discorb/exe/new.rb +95 -28
- data/lib/discorb/exe/run.rb +9 -37
- data/lib/discorb/exe/setup.rb +25 -12
- data/lib/discorb/exe/show.rb +4 -3
- data/lib/discorb/extend.rb +1 -0
- data/lib/discorb/extension.rb +6 -3
- data/lib/discorb/flag.rb +11 -0
- data/lib/discorb/gateway.rb +312 -169
- data/lib/discorb/gateway_requests.rb +4 -7
- data/lib/discorb/guild.rb +255 -89
- data/lib/discorb/guild_template.rb +34 -7
- data/lib/discorb/http.rb +23 -11
- data/lib/discorb/integration.rb +27 -9
- data/lib/discorb/intents.rb +8 -8
- data/lib/discorb/interaction/autocomplete.rb +31 -19
- data/lib/discorb/interaction/command.rb +70 -17
- data/lib/discorb/interaction/components.rb +20 -4
- data/lib/discorb/interaction/modal.rb +0 -1
- data/lib/discorb/interaction/response.rb +73 -22
- data/lib/discorb/interaction/root.rb +29 -14
- data/lib/discorb/interaction.rb +1 -0
- data/lib/discorb/invite.rb +16 -9
- data/lib/discorb/member.rb +46 -5
- data/lib/discorb/message.rb +56 -15
- data/lib/discorb/message_meta.rb +39 -9
- data/lib/discorb/modules.rb +56 -14
- data/lib/discorb/permission.rb +14 -5
- data/lib/discorb/presence.rb +43 -10
- data/lib/discorb/rate_limit.rb +13 -3
- data/lib/discorb/reaction.rb +10 -4
- data/lib/discorb/role.rb +31 -4
- data/lib/discorb/shard.rb +74 -0
- data/lib/discorb/sticker.rb +30 -21
- data/lib/discorb/user.rb +13 -1
- data/lib/discorb/utils/colored_puts.rb +1 -0
- data/lib/discorb/voice_state.rb +30 -8
- data/lib/discorb/webhook.rb +88 -25
- data/lib/discorb.rb +10 -6
- data/po/yard.pot +9 -9
- data/sig/discorb.rbs +7232 -5837
- metadata +23 -6
- data/examples/commands/bookmarker.rb +0 -42
- data/examples/commands/hello.rb +0 -10
- data/examples/commands/inspect.rb +0 -25
- data/lib/discorb/log.rb +0 -81
data/lib/discorb/gateway.rb
CHANGED
@@ -14,12 +14,22 @@ module Discorb
|
|
14
14
|
module Gateway
|
15
15
|
#
|
16
16
|
# Represents an event.
|
17
|
+
# @abstract
|
17
18
|
#
|
18
19
|
class GatewayEvent
|
20
|
+
#
|
21
|
+
# Initializes a new instance of the GatewayEvent class.
|
19
22
|
# @private
|
23
|
+
#
|
24
|
+
# @param [Hash] data The data of the event.
|
25
|
+
#
|
20
26
|
def initialize(data)
|
21
27
|
@data = data
|
22
28
|
end
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
"#<#{self.class}>"
|
32
|
+
end
|
23
33
|
end
|
24
34
|
|
25
35
|
#
|
@@ -61,7 +71,13 @@ module Discorb
|
|
61
71
|
alias reactor fired_by
|
62
72
|
alias from fired_by
|
63
73
|
|
74
|
+
#
|
75
|
+
# Initializes a new instance of the ReactionEvent class.
|
64
76
|
# @private
|
77
|
+
#
|
78
|
+
# @param [Discorb::Client] client The client that instantiated the object.
|
79
|
+
# @param [Hash] data The data of the event.
|
80
|
+
#
|
65
81
|
def initialize(client, data)
|
66
82
|
@client = client
|
67
83
|
@data = data
|
@@ -80,7 +96,8 @@ module Discorb
|
|
80
96
|
|
81
97
|
unless @guild.nil?
|
82
98
|
@member = if data.key?(:member)
|
83
|
-
@guild.members[data[:member][:user][:id]] || Member.new(@client, @guild_id, data[:member][:user],
|
99
|
+
@guild.members[data[:member][:user][:id]] || Member.new(@client, @guild_id, data[:member][:user],
|
100
|
+
data[:member])
|
84
101
|
else
|
85
102
|
@guild.members[data[:user_id]]
|
86
103
|
end
|
@@ -114,6 +131,7 @@ module Discorb
|
|
114
131
|
class IntegrationDeleteEvent < GatewayEvent
|
115
132
|
# @return [Discorb::Snowflake] The ID of the integration.
|
116
133
|
attr_reader :id
|
134
|
+
|
117
135
|
# @!attribute [r] guild
|
118
136
|
# @macro client_cache
|
119
137
|
# @return [Discorb::Guild] The guild of the integration.
|
@@ -121,7 +139,14 @@ module Discorb
|
|
121
139
|
# @macro client_cache
|
122
140
|
# @return [Discorb::User] The user associated with the integration.
|
123
141
|
|
142
|
+
#
|
143
|
+
# Initialize a new instance of the IntegrationDeleteEvent class.
|
124
144
|
# @private
|
145
|
+
#
|
146
|
+
#
|
147
|
+
# @param [Hash] data The data of the event.
|
148
|
+
#
|
149
|
+
#
|
125
150
|
def initialize(_client, data)
|
126
151
|
@id = Snowflake.new(data[:id])
|
127
152
|
@guild_id = data[:guild_id]
|
@@ -157,7 +182,13 @@ module Discorb
|
|
157
182
|
# @return [Discorb::Message] The message the reaction was sent in.
|
158
183
|
attr_reader :message
|
159
184
|
|
185
|
+
#
|
186
|
+
# Initialize a new instance of the ReactionRemoveAllEvent class.
|
160
187
|
# @private
|
188
|
+
#
|
189
|
+
# @param [Discorb::Client] client The client that instantiated the object.
|
190
|
+
# @param [Hash] data The data of the event.
|
191
|
+
#
|
161
192
|
def initialize(client, data)
|
162
193
|
@client = client
|
163
194
|
@data = data
|
@@ -207,7 +238,13 @@ module Discorb
|
|
207
238
|
# @return [Discorb::UnicodeEmoji, Discorb::PartialEmoji] The emoji that was reacted with.
|
208
239
|
attr_reader :emoji
|
209
240
|
|
241
|
+
#
|
242
|
+
# Initialize a new instance of the ReactionRemoveEmojiEvent class.
|
210
243
|
# @private
|
244
|
+
#
|
245
|
+
# @param [Discorb::Client] client The client that instantiated the object.
|
246
|
+
# @param [Hash] data The data of the event.
|
247
|
+
#
|
211
248
|
def initialize(client, data)
|
212
249
|
@client = client
|
213
250
|
@data = data
|
@@ -246,7 +283,14 @@ module Discorb
|
|
246
283
|
attr_reader :guild
|
247
284
|
# @return [Discorb::ScheduledEvent] The scheduled event.
|
248
285
|
attr_reader :scheduled_event
|
286
|
+
|
287
|
+
#
|
288
|
+
# Initialize a new instance of the ScheduledEventUserEvent class.
|
249
289
|
# @private
|
290
|
+
#
|
291
|
+
# @param [Discorb::Client] client The client that instantiated the object.
|
292
|
+
# @param [Hash] data The data of the event.
|
293
|
+
#
|
250
294
|
def initialize(client, data)
|
251
295
|
@client = client
|
252
296
|
@scheduled_event_id = Snowflake.new(data[:scheduled_event_id])
|
@@ -342,7 +386,13 @@ module Discorb
|
|
342
386
|
# @macro client_cache
|
343
387
|
# @return [Discorb::Guild] The guild the message was sent in.
|
344
388
|
|
389
|
+
#
|
390
|
+
# Initialize a new instance of the UnknownDeleteBulkMessage class.
|
345
391
|
# @private
|
392
|
+
#
|
393
|
+
# @param [Discorb::Client] client The client that instantiated the object.
|
394
|
+
# @param [Hash] data The data of the event.
|
395
|
+
#
|
346
396
|
def initialize(client, id, data)
|
347
397
|
@client = client
|
348
398
|
@id = id
|
@@ -374,7 +424,13 @@ module Discorb
|
|
374
424
|
# @macro client_cache
|
375
425
|
# @return [Discorb::Guild] The guild the message was sent in.
|
376
426
|
|
427
|
+
#
|
428
|
+
# Initialize a new instance of the InviteDeleteEvent class.
|
377
429
|
# @private
|
430
|
+
#
|
431
|
+
# @param [Discorb::Client] client The client that instantiated the object.
|
432
|
+
# @param [Hash] data The data of the event.
|
433
|
+
#
|
378
434
|
def initialize(client, data)
|
379
435
|
@client = client
|
380
436
|
@data = data
|
@@ -392,21 +448,6 @@ module Discorb
|
|
392
448
|
end
|
393
449
|
end
|
394
450
|
|
395
|
-
#
|
396
|
-
# Represents a `GUILD_INTEGRATIONS_UPDATE` event.
|
397
|
-
#
|
398
|
-
class GuildIntegrationsUpdateEvent < GatewayEvent
|
399
|
-
def initialize(client, data)
|
400
|
-
@client = client
|
401
|
-
@data = data
|
402
|
-
@guild_id = Snowflake.new(data[:guild_id])
|
403
|
-
end
|
404
|
-
|
405
|
-
def guild
|
406
|
-
@client.guilds[@guild_id]
|
407
|
-
end
|
408
|
-
end
|
409
|
-
|
410
451
|
#
|
411
452
|
# Represents a `TYPING_START` event.
|
412
453
|
#
|
@@ -430,7 +471,13 @@ module Discorb
|
|
430
471
|
# @macro client_cache
|
431
472
|
# @return [Discorb::Member, Discorb::User] The member or user that started typing.
|
432
473
|
|
474
|
+
#
|
475
|
+
# Initialize a new instance of the TypingStartEvent class.
|
433
476
|
# @private
|
477
|
+
#
|
478
|
+
# @param [Discorb::Client] client The client that instantiated the object.
|
479
|
+
# @param [Hash] data The data of the event.
|
480
|
+
#
|
434
481
|
def initialize(client, data)
|
435
482
|
@client = client
|
436
483
|
@data = data
|
@@ -438,7 +485,14 @@ module Discorb
|
|
438
485
|
@guild_id = Snowflake.new(data[:guild_id]) if data.key?(:guild_id)
|
439
486
|
@user_id = Snowflake.new(data[:user_id])
|
440
487
|
@timestamp = Time.at(data[:timestamp])
|
441
|
-
|
488
|
+
if guild
|
489
|
+
@member = guild.members[@user_id] || Member.new(
|
490
|
+
@client,
|
491
|
+
@guild_id,
|
492
|
+
@client.users[@user_id].instance_variable_get(:@data),
|
493
|
+
data[:member]
|
494
|
+
)
|
495
|
+
end
|
442
496
|
end
|
443
497
|
|
444
498
|
def user
|
@@ -507,7 +561,13 @@ module Discorb
|
|
507
561
|
# @macro client_cache
|
508
562
|
# @return [Discorb::Guild] The guild where the webhook was updated.
|
509
563
|
|
564
|
+
#
|
565
|
+
# Initialize a new instance of the WebhooksUpdateEvent class.
|
510
566
|
# @private
|
567
|
+
#
|
568
|
+
# @param [Discorb::Client] client The client that instantiated the object.
|
569
|
+
# @param [Hash] data The data of the event.
|
570
|
+
#
|
511
571
|
def initialize(client, data)
|
512
572
|
@client = client
|
513
573
|
@data = data
|
@@ -531,115 +591,136 @@ module Discorb
|
|
531
591
|
private
|
532
592
|
|
533
593
|
def connect_gateway(reconnect)
|
534
|
-
if reconnect
|
535
|
-
@log.info "Reconnecting to gateway..."
|
536
|
-
else
|
537
|
-
@log.info "Connecting to gateway..."
|
538
|
-
end
|
539
594
|
Async do
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
end
|
545
|
-
@http = HTTP.new(self)
|
546
|
-
_, gateway_response = @http.request(Route.new("/gateway", "//gateway", :get)).wait
|
547
|
-
gateway_url = gateway_response[:url]
|
548
|
-
gateway_version = if @intents.to_h[:message_content].nil?
|
549
|
-
warn "message_content intent not set, using gateway version 9. You should specify `message_content` intent for preventing unexpected changes in the future."
|
550
|
-
9
|
595
|
+
@mutex["gateway_#{shard_id}"] ||= Mutex.new
|
596
|
+
@mutex["gateway_#{shard_id}"].synchronize do
|
597
|
+
if reconnect
|
598
|
+
logger.info "Reconnecting to gateway..."
|
551
599
|
else
|
552
|
-
|
600
|
+
logger.info "Connecting to gateway..."
|
553
601
|
end
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
602
|
+
|
603
|
+
@http = HTTP.new(self)
|
604
|
+
_, gateway_response = @http.request(Route.new("/gateway", "//gateway", :get)).wait
|
605
|
+
gateway_url = gateway_response[:url]
|
606
|
+
gateway_version = if @intents.to_h[:message_content].nil?
|
607
|
+
warn "message_content intent not set, using gateway version 9. " \
|
608
|
+
"You should specify `message_content` intent for preventing unexpected changes in the future."
|
609
|
+
9
|
610
|
+
else
|
611
|
+
10
|
612
|
+
end
|
613
|
+
endpoint = Async::HTTP::Endpoint.parse(
|
614
|
+
"#{gateway_url}?v=#{gateway_version}&encoding=json&compress=zlib-stream&_=#{Time.now.to_i}",
|
615
|
+
alpn_protocols: Async::HTTP::Protocol::HTTP11.names,
|
616
|
+
)
|
560
617
|
begin
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
618
|
+
self.connection = Async::WebSocket::Client.connect(
|
619
|
+
endpoint,
|
620
|
+
headers: [["User-Agent", Discorb::USER_AGENT]],
|
621
|
+
handler: RawConnection,
|
622
|
+
)
|
623
|
+
zlib_stream = Zlib::Inflate.new(Zlib::MAX_WBITS)
|
624
|
+
buffer = +""
|
625
|
+
begin
|
626
|
+
while (message = connection.read)
|
627
|
+
buffer << message
|
628
|
+
if message.end_with?((+"\x00\x00\xff\xff").force_encoding("ASCII-8BIT"))
|
629
|
+
begin
|
630
|
+
data = zlib_stream.inflate(buffer)
|
631
|
+
buffer = +""
|
632
|
+
message = JSON.parse(data, symbolize_names: true)
|
633
|
+
rescue JSON::ParserError
|
634
|
+
buffer = +""
|
635
|
+
logger.error "Received invalid JSON from gateway."
|
636
|
+
logger.debug "#{data}"
|
637
|
+
else
|
638
|
+
handle_gateway(message, reconnect)
|
639
|
+
end
|
574
640
|
end
|
575
641
|
end
|
642
|
+
rescue Async::Wrapper::Cancelled,
|
643
|
+
OpenSSL::SSL::SSLError,
|
644
|
+
Async::Wrapper::WaitError,
|
645
|
+
EOFError,
|
646
|
+
Errno::EPIPE,
|
647
|
+
Errno::ECONNRESET,
|
648
|
+
IOError => e
|
649
|
+
next if @status == :closed
|
650
|
+
|
651
|
+
logger.error "Gateway connection closed accidentally: #{e.class}: #{e.message}"
|
652
|
+
connection.force_close
|
653
|
+
connect_gateway(true)
|
654
|
+
next
|
576
655
|
end
|
577
|
-
rescue
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
@log.error "Discord WebSocket closed with code #{e.code}."
|
613
|
-
@log.debug "#{e.message}"
|
656
|
+
rescue Protocol::WebSocket::ClosedError => e
|
657
|
+
@tasks.map(&:stop)
|
658
|
+
case e.code
|
659
|
+
when 4004
|
660
|
+
raise ClientError.new("Authentication failed"), cause: nil
|
661
|
+
when 4009
|
662
|
+
logger.info "Session timed out, reconnecting."
|
663
|
+
connection.force_close
|
664
|
+
connect_gateway(true)
|
665
|
+
next
|
666
|
+
when 4014
|
667
|
+
raise ClientError.new("Disallowed intents were specified"), cause: nil
|
668
|
+
when 4001, 4002, 4003, 4005, 4007
|
669
|
+
raise ClientError.new(<<~ERROR), cause: e
|
670
|
+
Disconnected from gateway, probably due to library issues.
|
671
|
+
#{e.message}
|
672
|
+
|
673
|
+
Please report this to the library issue tracker.
|
674
|
+
https://github.com/discorb-lib/discorb/issues
|
675
|
+
ERROR
|
676
|
+
when 1001
|
677
|
+
logger.info "Gateway closed with code 1001, reconnecting."
|
678
|
+
connection.force_close
|
679
|
+
connect_gateway(true)
|
680
|
+
next
|
681
|
+
else
|
682
|
+
logger.error "Discord WebSocket closed with code #{e.code}."
|
683
|
+
logger.debug "#{e.message}"
|
684
|
+
connection.force_close
|
685
|
+
connect_gateway(false)
|
686
|
+
next
|
687
|
+
end
|
688
|
+
rescue StandardError => e
|
689
|
+
logger.error "Discord WebSocket error: #{e.full_message}"
|
690
|
+
connection.force_close
|
614
691
|
connect_gateway(false)
|
692
|
+
next
|
615
693
|
end
|
616
|
-
rescue StandardError => e
|
617
|
-
@log.error "Discord WebSocket error: #{e.full_message}"
|
618
|
-
@connection.force_close
|
619
|
-
connect_gateway(false)
|
620
694
|
end
|
621
695
|
end
|
622
696
|
end
|
623
697
|
|
624
698
|
def send_gateway(opcode, **value)
|
625
|
-
@
|
626
|
-
|
627
|
-
|
699
|
+
if @shards.any? && shard.nil?
|
700
|
+
@shards.map(&:connection)
|
701
|
+
else
|
702
|
+
[connection]
|
703
|
+
end.each do |con|
|
704
|
+
con.write({ op: opcode, d: value }.to_json)
|
705
|
+
con.flush
|
706
|
+
end
|
707
|
+
logger.debug "Sent message to fd #{connection.io.fileno}: #{{ op: opcode, d: value }.to_json.gsub(@token,
|
708
|
+
"[Token]")}"
|
628
709
|
end
|
629
710
|
|
630
711
|
def handle_gateway(payload, reconnect)
|
631
712
|
Async do |_task|
|
632
713
|
data = payload[:d]
|
633
714
|
@last_s = payload[:s] if payload[:s]
|
634
|
-
|
635
|
-
|
715
|
+
logger.debug "Received message with opcode #{payload[:op]} from gateway."
|
716
|
+
logger.debug "#{payload.to_json.gsub(@token, "[Token]")}"
|
636
717
|
case payload[:op]
|
637
718
|
when 10
|
638
719
|
@heartbeat_interval = data[:heartbeat_interval]
|
639
720
|
if reconnect
|
640
721
|
payload = {
|
641
722
|
token: @token,
|
642
|
-
session_id:
|
723
|
+
session_id: session_id,
|
643
724
|
seq: @last_s,
|
644
725
|
}
|
645
726
|
send_gateway(6, **payload)
|
@@ -650,27 +731,29 @@ module Discorb
|
|
650
731
|
compress: false,
|
651
732
|
properties: { "$os" => RUBY_PLATFORM, "$browser" => "discorb", "$device" => "discorb" },
|
652
733
|
}
|
734
|
+
payload[:shard] = [shard_id, @shard_count] if shard_id
|
653
735
|
payload[:presence] = @identify_presence if @identify_presence
|
654
736
|
send_gateway(2, **payload)
|
655
737
|
end
|
656
738
|
when 7
|
657
|
-
|
739
|
+
logger.info "Received opcode 7, stopping tasks"
|
658
740
|
@tasks.map(&:stop)
|
659
741
|
when 9
|
660
|
-
|
742
|
+
logger.warn "Received opcode 9, closed connection"
|
661
743
|
@tasks.map(&:stop)
|
662
744
|
if data
|
663
|
-
|
664
|
-
|
745
|
+
logger.info "Connection is resumable, reconnecting"
|
746
|
+
connection.force_close
|
665
747
|
connect_gateway(true)
|
666
748
|
else
|
667
|
-
|
668
|
-
|
749
|
+
logger.info "Connection is not resumable, reconnecting with opcode 2"
|
750
|
+
connection.force_close
|
751
|
+
|
669
752
|
sleep(2)
|
670
753
|
connect_gateway(false)
|
671
754
|
end
|
672
755
|
when 11
|
673
|
-
|
756
|
+
logger.debug "Received opcode 11"
|
674
757
|
@ping = Time.now.to_f - @heartbeat_before
|
675
758
|
when 0
|
676
759
|
handle_event(payload[:t], data)
|
@@ -683,12 +766,12 @@ module Discorb
|
|
683
766
|
interval = @heartbeat_interval
|
684
767
|
sleep((interval / 1000.0 - 1) * rand)
|
685
768
|
loop do
|
686
|
-
unless
|
769
|
+
unless connection.closed?
|
687
770
|
@heartbeat_before = Time.now.to_f
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
771
|
+
connection.write({ op: 1, d: @last_s }.to_json)
|
772
|
+
connection.flush
|
773
|
+
logger.debug "Sent opcode 1."
|
774
|
+
logger.debug "Waiting for heartbeat."
|
692
775
|
end
|
693
776
|
sleep(interval / 1000.0 - 1)
|
694
777
|
end
|
@@ -696,29 +779,34 @@ module Discorb
|
|
696
779
|
end
|
697
780
|
|
698
781
|
def handle_event(event_name, data)
|
699
|
-
return
|
782
|
+
return logger.debug "Client isn't ready; event #{event_name} wasn't handled" if @wait_until_ready &&
|
783
|
+
!@ready &&
|
784
|
+
!%w[
|
785
|
+
READY GUILD_CREATE
|
786
|
+
].include?(event_name)
|
700
787
|
|
701
788
|
dispatch(:event_receive, event_name, data)
|
702
|
-
|
789
|
+
logger.debug "Handling event #{event_name}"
|
703
790
|
case event_name
|
704
791
|
when "READY"
|
705
792
|
@api_version = data[:v]
|
706
|
-
|
793
|
+
self.session_id = data[:session_id]
|
707
794
|
@user = ClientUser.new(self, data[:user])
|
708
795
|
@uncached_guilds = data[:guilds].map { |g| g[:id] }
|
709
796
|
ready if (@uncached_guilds == []) || !@intents.guilds
|
710
797
|
dispatch(:ready)
|
798
|
+
|
711
799
|
@tasks << handle_heartbeat
|
712
800
|
when "GUILD_CREATE"
|
713
801
|
if @uncached_guilds.include?(data[:id])
|
714
802
|
Guild.new(self, data, true)
|
715
803
|
@uncached_guilds.delete(data[:id])
|
716
804
|
if @uncached_guilds == []
|
717
|
-
|
805
|
+
logger.debug "All guilds cached"
|
718
806
|
ready
|
719
807
|
end
|
720
808
|
elsif @guilds.has?(data[:id])
|
721
|
-
@guilds[data[:id]].send(:_set_data, data)
|
809
|
+
@guilds[data[:id]].send(:_set_data, data, true)
|
722
810
|
dispatch(:guild_available, guild)
|
723
811
|
else
|
724
812
|
guild = Guild.new(self, data, true)
|
@@ -735,51 +823,53 @@ module Discorb
|
|
735
823
|
current.send(:_set_data, data, false)
|
736
824
|
dispatch(:guild_update, before, current)
|
737
825
|
else
|
738
|
-
|
826
|
+
logger.warn "Unknown guild id #{data[:id]}, ignoring"
|
739
827
|
end
|
740
828
|
when "GUILD_DELETE"
|
741
|
-
return
|
829
|
+
return logger.warn "Unknown guild id #{data[:id]}, ignoring" unless (guild = @guilds.delete(data[:id]))
|
742
830
|
|
743
831
|
dispatch(:guild_delete, guild)
|
744
|
-
if
|
832
|
+
if data[:unavailable]
|
745
833
|
dispatch(:guild_destroy, guild)
|
746
834
|
else
|
747
835
|
dispatch(:guild_leave, guild)
|
748
836
|
end
|
749
837
|
when "GUILD_ROLE_CREATE"
|
750
|
-
return
|
838
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
751
839
|
|
752
840
|
nr = Role.new(@client, guild, data[:role])
|
753
841
|
guild.roles[data[:role][:id]] = nr
|
754
842
|
dispatch(:role_create, nr)
|
755
843
|
when "GUILD_ROLE_UPDATE"
|
756
|
-
return
|
757
|
-
return
|
844
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
845
|
+
return logger.warn "Unknown role id #{data[:role][:id]}, ignoring" unless guild.roles.has?(data[:role][:id])
|
758
846
|
|
759
847
|
current = guild.roles[data[:role][:id]]
|
760
848
|
before = Role.new(@client, guild, current.instance_variable_get(:@data).update({ no_cache: true }))
|
761
849
|
current.send(:_set_data, data[:role])
|
762
850
|
dispatch(:role_update, before, current)
|
763
851
|
when "GUILD_ROLE_DELETE"
|
764
|
-
return
|
765
|
-
|
852
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
853
|
+
unless (role = guild.roles.delete(data[:role_id]))
|
854
|
+
return logger.warn "Unknown role id #{data[:role_id]}, ignoring"
|
855
|
+
end
|
766
856
|
|
767
857
|
dispatch(:role_delete, role)
|
768
858
|
when "CHANNEL_CREATE"
|
769
|
-
return
|
859
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
770
860
|
|
771
861
|
nc = Channel.make_channel(self, data)
|
772
862
|
guild.channels[data[:id]] = nc
|
773
863
|
|
774
864
|
dispatch(:channel_create, nc)
|
775
865
|
when "CHANNEL_UPDATE"
|
776
|
-
return
|
866
|
+
return logger.warn "Unknown channel id #{data[:id]}, ignoring" unless (current = @channels[data[:id]])
|
777
867
|
|
778
868
|
before = Channel.make_channel(self, current.instance_variable_get(:@data), no_cache: true)
|
779
869
|
current.send(:_set_data, data)
|
780
870
|
dispatch(:channel_update, before, current)
|
781
871
|
when "CHANNEL_DELETE"
|
782
|
-
return
|
872
|
+
return logger.warn "Unknown channel id #{data[:id]}, ignoring" unless (channel = @channels.delete(data[:id]))
|
783
873
|
|
784
874
|
@guilds[data[:guild_id]]&.channels&.delete(data[:id])
|
785
875
|
dispatch(:channel_delete, channel)
|
@@ -795,27 +885,29 @@ module Discorb
|
|
795
885
|
dispatch(:thread_new, thread)
|
796
886
|
end
|
797
887
|
when "THREAD_UPDATE"
|
798
|
-
return
|
888
|
+
return logger.warn "Unknown thread id #{data[:id]}, ignoring" unless (thread = @channels[data[:id]])
|
799
889
|
|
800
890
|
before = Channel.make_channel(self, thread.instance_variable_get(:@data), no_cache: true)
|
801
891
|
thread.send(:_set_data, data)
|
802
892
|
dispatch(:thread_update, before, thread)
|
803
893
|
when "THREAD_DELETE"
|
804
|
-
return
|
894
|
+
return logger.warn "Unknown thread id #{data[:id]}, ignoring" unless (thread = @channels.delete(data[:id]))
|
805
895
|
|
806
896
|
@guilds[data[:guild_id]]&.channels&.delete(data[:id])
|
807
897
|
dispatch(:thread_delete, thread)
|
808
898
|
when "THREAD_LIST_SYNC"
|
809
899
|
data[:threads].each do |raw_thread|
|
810
|
-
thread = Channel.make_channel(self, raw_thread.merge({ member: raw_thread[:members].find
|
900
|
+
thread = Channel.make_channel(self, raw_thread.merge({ member: raw_thread[:members].find do |m|
|
901
|
+
m[:id] == raw_thread[:id]
|
902
|
+
end }))
|
811
903
|
@channels[thread.id] = thread
|
812
904
|
end
|
813
905
|
when "THREAD_MEMBER_UPDATE"
|
814
|
-
return
|
906
|
+
return logger.warn "Unknown thread id #{data[:id]}, ignoring" unless (thread = @channels[data[:id]])
|
815
907
|
|
816
908
|
if (member = thread.members[data[:id]])
|
817
909
|
old = ThreadChannel::Member.new(self, member.instance_variable_get(:@data))
|
818
|
-
member._set_data
|
910
|
+
member.send(:_set_data, data)
|
819
911
|
else
|
820
912
|
old = nil
|
821
913
|
member = ThreadChannel::Member.new(self, data)
|
@@ -823,7 +915,7 @@ module Discorb
|
|
823
915
|
end
|
824
916
|
dispatch(:thread_member_update, thread, old, member)
|
825
917
|
when "THREAD_MEMBERS_UPDATE"
|
826
|
-
return
|
918
|
+
return logger.warn "Unknown thread id #{data[:id]}, ignoring" unless (thread = @channels[data[:id]])
|
827
919
|
|
828
920
|
thread.instance_variable_set(:@member_count, data[:member_count])
|
829
921
|
members = []
|
@@ -841,37 +933,49 @@ module Discorb
|
|
841
933
|
instance = StageInstance.new(self, data)
|
842
934
|
dispatch(:stage_instance_create, instance)
|
843
935
|
when "STAGE_INSTANCE_UPDATE"
|
844
|
-
|
845
|
-
|
936
|
+
unless (channel = @channels[data[:channel_id]])
|
937
|
+
return logger.warn "Unknown channel id #{data[:channel_id]} , ignoring"
|
938
|
+
end
|
939
|
+
unless (instance = channel.stage_instances[data[:id]])
|
940
|
+
return logger.warn "Unknown stage instance id #{data[:id]}, ignoring"
|
941
|
+
end
|
846
942
|
|
847
943
|
old = StageInstance.new(self, instance.instance_variable_get(:@data), no_cache: true)
|
848
944
|
current.send(:_set_data, data)
|
849
945
|
dispatch(:stage_instance_update, old, current)
|
850
946
|
when "STAGE_INSTANCE_DELETE"
|
851
|
-
|
852
|
-
|
947
|
+
unless (channel = @channels[data[:channel_id]])
|
948
|
+
return logger.warn "Unknown channel id #{data[:channel_id]} , ignoring"
|
949
|
+
end
|
950
|
+
unless (instance = channel.stage_instances.delete(data[:id]))
|
951
|
+
return logger.warn "Unknown stage instance id #{data[:id]}, ignoring"
|
952
|
+
end
|
853
953
|
|
854
954
|
dispatch(:stage_instance_delete, instance)
|
855
955
|
when "GUILD_MEMBER_ADD"
|
856
|
-
return
|
956
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
857
957
|
|
858
958
|
nm = Member.new(self, data[:guild_id], data[:user].update({ no_cache: true }), data)
|
859
959
|
guild.members[nm.id] = nm
|
860
960
|
dispatch(:member_add, nm)
|
861
961
|
when "GUILD_MEMBER_UPDATE"
|
862
|
-
return
|
863
|
-
|
962
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
963
|
+
unless (nm = guild.members[data[:user][:id]])
|
964
|
+
return logger.warn "Unknown member id #{data[:user][:id]}, ignoring"
|
965
|
+
end
|
864
966
|
|
865
967
|
old = Member.new(self, data[:guild_id], data[:user], data.update({ no_cache: true }))
|
866
968
|
nm.send(:_set_data, data[:user], data)
|
867
969
|
dispatch(:member_update, old, nm)
|
868
970
|
when "GUILD_MEMBER_REMOVE"
|
869
|
-
return
|
870
|
-
|
971
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
972
|
+
unless (member = guild.members.delete(data[:user][:id]))
|
973
|
+
return logger.warn "Unknown member id #{data[:user][:id]}, ignoring"
|
974
|
+
end
|
871
975
|
|
872
976
|
dispatch(:member_remove, member)
|
873
977
|
when "GUILD_BAN_ADD"
|
874
|
-
return
|
978
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
875
979
|
|
876
980
|
user = if @users.has? data[:user][:id]
|
877
981
|
@users[data[:user][:id]]
|
@@ -881,7 +985,7 @@ module Discorb
|
|
881
985
|
|
882
986
|
dispatch(:guild_ban_add, guild, user)
|
883
987
|
when "GUILD_BAN_REMOVE"
|
884
|
-
return
|
988
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
885
989
|
|
886
990
|
user = if @users.has? data[:user][:id]
|
887
991
|
@users[data[:user][:id]]
|
@@ -891,7 +995,7 @@ module Discorb
|
|
891
995
|
|
892
996
|
dispatch(:guild_ban_remove, guild, user)
|
893
997
|
when "GUILD_EMOJIS_UPDATE"
|
894
|
-
return
|
998
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
895
999
|
|
896
1000
|
before_emojis = guild.emojis.values.map(&:id).to_set
|
897
1001
|
data[:emojis].each do |emoji|
|
@@ -902,17 +1006,16 @@ module Discorb
|
|
902
1006
|
guild.emojis.delete(emoji)
|
903
1007
|
end
|
904
1008
|
when "GUILD_INTEGRATIONS_UPDATE"
|
905
|
-
|
906
|
-
# Currently not implemented
|
1009
|
+
dispatch(:guild_integrations_update, @guilds[data[:guild_id]])
|
907
1010
|
when "INTEGRATION_CREATE"
|
908
1011
|
dispatch(:integration_create, Integration.new(self, data, data[:guild_id]))
|
909
1012
|
when "INTEGRATION_UPDATE"
|
910
|
-
return
|
1013
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
911
1014
|
|
912
1015
|
integration = Integration.new(self, data, data[:guild_id])
|
913
1016
|
dispatch(:integration_update, integration)
|
914
1017
|
when "INTEGRATION_DELETE"
|
915
|
-
return
|
1018
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
916
1019
|
|
917
1020
|
dispatch(:integration_delete, IntegrationDeleteEvent.new(self, data))
|
918
1021
|
when "WEBHOOKS_UPDATE"
|
@@ -922,7 +1025,7 @@ module Discorb
|
|
922
1025
|
when "INVITE_DELETE"
|
923
1026
|
dispatch(:invite_delete, InviteDeleteEvent.new(self, data))
|
924
1027
|
when "VOICE_STATE_UPDATE"
|
925
|
-
return
|
1028
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
926
1029
|
|
927
1030
|
current = guild.voice_states[data[:user_id]]
|
928
1031
|
if current.nil?
|
@@ -1019,7 +1122,7 @@ module Discorb
|
|
1019
1122
|
end
|
1020
1123
|
end
|
1021
1124
|
when "PRESENCE_UPDATE"
|
1022
|
-
return
|
1125
|
+
return logger.warn "Unknown guild id #{data[:guild_id]}, ignoring" unless (guild = @guilds[data[:guild_id]])
|
1023
1126
|
|
1024
1127
|
guild.presences[data[:user][:id]] = Presence.new(self, data)
|
1025
1128
|
when "MESSAGE_UPDATE"
|
@@ -1045,7 +1148,8 @@ module Discorb
|
|
1045
1148
|
when "MESSAGE_DELETE"
|
1046
1149
|
message.instance_variable_set(:@deleted, true) if (message = @messages[data[:id]])
|
1047
1150
|
|
1048
|
-
dispatch(:message_delete_id, Snowflake.new(data[:id]), channels[data[:channel_id]],
|
1151
|
+
dispatch(:message_delete_id, Snowflake.new(data[:id]), channels[data[:channel_id]],
|
1152
|
+
data[:guild_id] && guilds[data[:guild_id]])
|
1049
1153
|
dispatch(:message_delete, message, channels[data[:channel_id]], data[:guild_id] && guilds[data[:guild_id]])
|
1050
1154
|
when "MESSAGE_DELETE_BULK"
|
1051
1155
|
messages = []
|
@@ -1092,10 +1196,12 @@ module Discorb
|
|
1092
1196
|
dispatch(:reaction_remove_all, ReactionRemoveAllEvent.new(self, data))
|
1093
1197
|
when "MESSAGE_REACTION_REMOVE_EMOJI"
|
1094
1198
|
if (target_message = @messages[data[:message_id]]) &&
|
1095
|
-
(target_reaction = target_message.reactions.find
|
1199
|
+
(target_reaction = target_message.reactions.find do |r|
|
1200
|
+
data[:emoji][:id].nil? ? r.name == data[:emoji][:name] : r.id == data[:emoji][:id]
|
1201
|
+
end)
|
1096
1202
|
target_message.reactions.delete(target_reaction)
|
1097
1203
|
end
|
1098
|
-
dispatch(:reaction_remove_emoji, ReactionRemoveEmojiEvent.new(data))
|
1204
|
+
dispatch(:reaction_remove_emoji, ReactionRemoveEmojiEvent.new(self, data))
|
1099
1205
|
when "TYPING_START"
|
1100
1206
|
dispatch(:typing_start, TypingStartEvent.new(self, data))
|
1101
1207
|
when "INTERACTION_CREATE"
|
@@ -1104,17 +1210,23 @@ module Discorb
|
|
1104
1210
|
|
1105
1211
|
dispatch(interaction.class.event_name, interaction)
|
1106
1212
|
when "RESUMED"
|
1107
|
-
|
1213
|
+
logger.info("Successfully resumed connection")
|
1108
1214
|
@tasks << handle_heartbeat
|
1109
|
-
|
1215
|
+
if shard
|
1216
|
+
dispatch(:shard_resumed, shard)
|
1217
|
+
else
|
1218
|
+
dispatch(:resumed)
|
1219
|
+
end
|
1110
1220
|
when "GUILD_SCHEDULED_EVENT_CREATE"
|
1111
|
-
|
1221
|
+
logger.warn("Unknown guild id #{data[:guild_id]}, ignoring") unless (guild = @guilds[data[:guild_id]])
|
1112
1222
|
event = ScheduledEvent.new(self, data)
|
1113
1223
|
guild.scheduled_events[data[:id]] = event
|
1114
1224
|
dispatch(:scheduled_event_create, event)
|
1115
1225
|
when "GUILD_SCHEDULED_EVENT_UPDATE"
|
1116
|
-
|
1117
|
-
|
1226
|
+
logger.warn("Unknown guild id #{data[:guild_id]}, ignoring") unless (guild = @guilds[data[:guild_id]])
|
1227
|
+
unless (event = guild.scheduled_events[data[:id]])
|
1228
|
+
logger.warn("Unknown scheduled event id #{data[:id]}, ignoring")
|
1229
|
+
end
|
1118
1230
|
old = event.dup
|
1119
1231
|
event.send(:_set_data, data)
|
1120
1232
|
dispatch(:scheduled_event_update, old, event)
|
@@ -1129,22 +1241,24 @@ module Discorb
|
|
1129
1241
|
end
|
1130
1242
|
end
|
1131
1243
|
when "GUILD_SCHEDULED_EVENT_DELETE"
|
1132
|
-
|
1133
|
-
|
1244
|
+
logger.warn("Unknown guild id #{data[:guild_id]}, ignoring") unless (guild = @guilds[data[:guild_id]])
|
1245
|
+
unless (event = guild.scheduled_events[data[:id]])
|
1246
|
+
logger.warn("Unknown scheduled event id #{data[:id]}, ignoring")
|
1247
|
+
end
|
1134
1248
|
guild.scheduled_events.remove(data[:id])
|
1135
1249
|
dispatch(:scheduled_event_delete, event)
|
1136
1250
|
dispatch(:scheduled_event_cancel, event)
|
1137
1251
|
when "GUILD_SCHEDULED_EVENT_USER_ADD"
|
1138
|
-
|
1252
|
+
logger.warn("Unknown guild id #{data[:guild_id]}, ignoring") unless (guild = @guilds[data[:guild_id]])
|
1139
1253
|
dispatch(:scheduled_event_user_add, ScheduledEventUserEvent.new(self, data))
|
1140
1254
|
when "GUILD_SCHEDULED_EVENT_USER_REMOVE"
|
1141
|
-
|
1255
|
+
logger.warn("Unknown guild id #{data[:guild_id]}, ignoring") unless (guild = @guilds[data[:guild_id]])
|
1142
1256
|
dispatch(:scheduled_event_user_remove, ScheduledEventUserEvent.new(self, data))
|
1143
1257
|
else
|
1144
1258
|
if respond_to?("event_" + event_name.downcase)
|
1145
1259
|
__send__("event_" + event_name.downcase, data)
|
1146
1260
|
else
|
1147
|
-
|
1261
|
+
logger.debug "Unhandled event: #{event_name}\n#{data.inspect}"
|
1148
1262
|
end
|
1149
1263
|
end
|
1150
1264
|
end
|
@@ -1152,7 +1266,7 @@ module Discorb
|
|
1152
1266
|
def ready
|
1153
1267
|
Async do
|
1154
1268
|
if @fetch_member
|
1155
|
-
|
1269
|
+
logger.debug "Fetching members"
|
1156
1270
|
barrier = Async::Barrier.new
|
1157
1271
|
|
1158
1272
|
@guilds.each do |guild|
|
@@ -1163,8 +1277,25 @@ module Discorb
|
|
1163
1277
|
barrier.wait
|
1164
1278
|
end
|
1165
1279
|
@ready = true
|
1166
|
-
|
1167
|
-
|
1280
|
+
|
1281
|
+
if self.shard
|
1282
|
+
logger.info("Shard #{shard_id} is ready!")
|
1283
|
+
self.shard&.tap do |shard|
|
1284
|
+
if shard.next_shard
|
1285
|
+
dispatch(:shard_standby, shard)
|
1286
|
+
shard.next_shard.tap do |next_shard|
|
1287
|
+
logger.debug("Starting shard #{next_shard.id}")
|
1288
|
+
next_shard.start
|
1289
|
+
end
|
1290
|
+
else
|
1291
|
+
logger.info("All shards are ready!")
|
1292
|
+
dispatch(:standby)
|
1293
|
+
end
|
1294
|
+
end
|
1295
|
+
else
|
1296
|
+
logger.info("Client is ready!")
|
1297
|
+
dispatch(:standby)
|
1298
|
+
end
|
1168
1299
|
end
|
1169
1300
|
end
|
1170
1301
|
end
|
@@ -1179,6 +1310,10 @@ module Discorb
|
|
1179
1310
|
@closed = false
|
1180
1311
|
end
|
1181
1312
|
|
1313
|
+
def inspect
|
1314
|
+
"<#{self.class.name} #{io.fileno}>"
|
1315
|
+
end
|
1316
|
+
|
1182
1317
|
def closed?
|
1183
1318
|
@closed
|
1184
1319
|
end
|
@@ -1191,10 +1326,18 @@ module Discorb
|
|
1191
1326
|
end
|
1192
1327
|
|
1193
1328
|
def force_close
|
1194
|
-
|
1329
|
+
io.close
|
1195
1330
|
@closed = true
|
1196
1331
|
end
|
1197
1332
|
|
1333
|
+
def io
|
1334
|
+
@framer
|
1335
|
+
.instance_variable_get(:@stream)
|
1336
|
+
.instance_variable_get(:@io)
|
1337
|
+
.instance_variable_get(:@io)
|
1338
|
+
.instance_variable_get(:@io)
|
1339
|
+
end
|
1340
|
+
|
1198
1341
|
def parse(buffer)
|
1199
1342
|
# noop
|
1200
1343
|
buffer.to_s
|