discord_rda 0.1.3 → 0.2.0

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.
@@ -291,4 +291,291 @@ module DiscordRDA
291
291
  @user ||= User.new(@raw_data['user']) if @raw_data['user']
292
292
  end
293
293
  end
294
+
295
+ class Integration < Entity
296
+ attribute :name, type: :string
297
+ attribute :type, type: :string
298
+ attribute :enabled, type: :boolean, default: false
299
+ attribute :syncing, type: :boolean, default: false
300
+ attribute :role_id, type: :snowflake
301
+ attribute :enable_emoticons, type: :boolean, default: false
302
+ attribute :expire_behavior, type: :integer
303
+ attribute :expire_grace_period, type: :integer
304
+ attribute :subscriber_count, type: :integer
305
+ attribute :revoked, type: :boolean, default: false
306
+ attribute :scopes, type: :array, default: []
307
+ attribute :guild_id, type: :snowflake
308
+ attribute :application_id, type: :snowflake
309
+
310
+ def user
311
+ @raw_data['user'] ? User.new(@raw_data['user']) : nil
312
+ end
313
+
314
+ def account
315
+ @raw_data['account'] || {}
316
+ end
317
+
318
+ def synced_at
319
+ @raw_data['synced_at'] ? Time.parse(@raw_data['synced_at']) : nil
320
+ end
321
+
322
+ def application
323
+ @raw_data['application'] ? Application.new(@raw_data['application']) : nil
324
+ end
325
+ end
326
+
327
+ class Presence < Entity
328
+ attribute :guild_id, type: :snowflake
329
+ attribute :status, type: :string
330
+
331
+ def user
332
+ @raw_data['user'] ? User.new(@raw_data['user']) : nil
333
+ end
334
+
335
+ def user_id
336
+ user&.id
337
+ end
338
+
339
+ def activities
340
+ @raw_data['activities'] || []
341
+ end
342
+
343
+ def client_status
344
+ @raw_data['client_status'] || {}
345
+ end
346
+
347
+ def desktop_status
348
+ client_status['desktop']
349
+ end
350
+
351
+ def mobile_status
352
+ client_status['mobile']
353
+ end
354
+
355
+ def web_status
356
+ client_status['web']
357
+ end
358
+
359
+ def online?
360
+ status == 'online'
361
+ end
362
+
363
+ def idle?
364
+ status == 'idle'
365
+ end
366
+
367
+ def dnd?
368
+ status == 'dnd'
369
+ end
370
+
371
+ def offline?
372
+ status == 'offline'
373
+ end
374
+ end
375
+
376
+ class VoiceState < Entity
377
+ attribute :guild_id, type: :snowflake
378
+ attribute :channel_id, type: :snowflake
379
+ attribute :user_id, type: :snowflake
380
+ attribute :session_id, type: :string
381
+ attribute :deaf, type: :boolean, default: false
382
+ attribute :mute, type: :boolean, default: false
383
+ attribute :self_deaf, type: :boolean, default: false
384
+ attribute :self_mute, type: :boolean, default: false
385
+ attribute :self_stream, type: :boolean, default: false
386
+ attribute :self_video, type: :boolean, default: false
387
+ attribute :suppress, type: :boolean, default: false
388
+
389
+ def member
390
+ return nil unless @raw_data['member']
391
+
392
+ Member.new(@raw_data['member'].merge('guild_id' => @raw_data['guild_id']))
393
+ end
394
+
395
+ def request_to_speak_timestamp
396
+ @raw_data['request_to_speak_timestamp'] ? Time.parse(@raw_data['request_to_speak_timestamp']) : nil
397
+ end
398
+
399
+ def connected?
400
+ !channel_id.nil?
401
+ end
402
+ end
403
+
404
+ class VoiceServer < Entity
405
+ attribute :token, type: :string
406
+ attribute :guild_id, type: :snowflake
407
+ attribute :endpoint, type: :string
408
+ end
409
+
410
+ class Webhook < Entity
411
+ TYPES = {
412
+ incoming: 1,
413
+ channel_follower: 2,
414
+ application: 3
415
+ }.freeze
416
+
417
+ attribute :type, type: :integer
418
+ attribute :guild_id, type: :snowflake
419
+ attribute :channel_id, type: :snowflake
420
+ attribute :name, type: :string
421
+ attribute :avatar, type: :string
422
+ attribute :token, type: :string
423
+ attribute :application_id, type: :snowflake
424
+ attribute :url, type: :string
425
+
426
+ def user
427
+ @raw_data['user'] ? User.new(@raw_data['user']) : nil
428
+ end
429
+
430
+ def source_guild
431
+ @raw_data['source_guild'] ? Guild.new(@raw_data['source_guild']) : nil
432
+ end
433
+
434
+ def source_channel
435
+ @raw_data['source_channel'] ? Channel.new(@raw_data['source_channel']) : nil
436
+ end
437
+
438
+ def incoming?
439
+ type == 1
440
+ end
441
+
442
+ def channel_follower?
443
+ type == 2
444
+ end
445
+
446
+ def application?
447
+ type == 3
448
+ end
449
+ end
450
+
451
+ class StageInstance < Entity
452
+ attribute :guild_id, type: :snowflake
453
+ attribute :channel_id, type: :snowflake
454
+ attribute :topic, type: :string
455
+ attribute :privacy_level, type: :integer
456
+ attribute :discoverable_disabled, type: :boolean, default: false
457
+ attribute :guild_scheduled_event_id, type: :snowflake
458
+
459
+ def guild_only?
460
+ privacy_level == 2
461
+ end
462
+ end
463
+
464
+ class Entitlement < Entity
465
+ attribute :sku_id, type: :snowflake
466
+ attribute :application_id, type: :snowflake
467
+ attribute :user_id, type: :snowflake
468
+ attribute :guild_id, type: :snowflake
469
+ attribute :type, type: :integer
470
+ attribute :deleted, type: :boolean, default: false
471
+ attribute :consumed, type: :boolean, default: false
472
+
473
+ def starts_at
474
+ @raw_data['starts_at'] ? Time.parse(@raw_data['starts_at']) : nil
475
+ end
476
+
477
+ def ends_at
478
+ @raw_data['ends_at'] ? Time.parse(@raw_data['ends_at']) : nil
479
+ end
480
+
481
+ def active?(at: Time.now.utc)
482
+ return false if deleted
483
+ return false if starts_at && at < starts_at
484
+ return false if ends_at && at > ends_at
485
+
486
+ true
487
+ end
488
+
489
+ def owner_id
490
+ user_id || guild_id
491
+ end
492
+
493
+ def owner_type
494
+ user_id ? :user : :guild
495
+ end
496
+ end
497
+
498
+ class Application < Entity
499
+ attribute :name, type: :string
500
+ attribute :icon, type: :string
501
+ attribute :description, type: :string
502
+ attribute :rpc_origins, type: :array, default: []
503
+ attribute :bot_public, type: :boolean, default: true
504
+ attribute :bot_require_code_grant, type: :boolean, default: false
505
+ attribute :terms_of_service_url, type: :string
506
+ attribute :privacy_policy_url, type: :string
507
+ attribute :summary, type: :string
508
+ attribute :verify_key, type: :string
509
+ attribute :cover_image, type: :string
510
+ attribute :flags, type: :integer, default: 0
511
+ attribute :approximate_guild_count, type: :integer
512
+ attribute :redirect_uris, type: :array, default: []
513
+ attribute :interactions_endpoint_url, type: :string
514
+ attribute :role_connections_verification_url, type: :string
515
+ attribute :tags, type: :array, default: []
516
+ attribute :custom_install_url, type: :string
517
+ attribute :install_params, type: :hash
518
+
519
+ def owner
520
+ @owner ||= User.new(@raw_data['owner']) if @raw_data['owner']
521
+ end
522
+
523
+ def team
524
+ @team ||= Team.new(@raw_data['team']) if @raw_data['team']
525
+ end
526
+ end
527
+
528
+ class Team < Entity
529
+ attribute :icon, type: :string
530
+ attribute :name, type: :string
531
+ attribute :owner_user_id, type: :snowflake
532
+
533
+ def members
534
+ (@raw_data['members'] || []).map do |member|
535
+ user = member['user'] ? User.new(member['user']) : nil
536
+ member.merge('user' => user)
537
+ end
538
+ end
539
+ end
540
+
541
+ class AuditLogEntry < Entity
542
+ attribute :target_id, type: :string
543
+ attribute :changes, type: :array, default: []
544
+ attribute :user_id, type: :snowflake
545
+ attribute :action_type, type: :integer
546
+ attribute :options, type: :hash
547
+ attribute :reason, type: :string
548
+
549
+ def user(users_index = nil)
550
+ return users_index[user_id.to_s] if users_index && user_id
551
+
552
+ @user ||= User.new(@raw_data['user']) if @raw_data['user']
553
+ end
554
+ end
555
+
556
+ class AuditLog
557
+ attr_reader :entries, :users, :webhooks, :integrations, :threads
558
+
559
+ def initialize(data = {})
560
+ @entries = (data['audit_log_entries'] || []).map { |entry| AuditLogEntry.new(entry) }
561
+ @users = (data['users'] || []).map { |user| User.new(user) }
562
+ @webhooks = data['webhooks'] || []
563
+ @integrations = data['integrations'] || []
564
+ @threads = (data['threads'] || []).map { |thread| Channel.new(thread) }
565
+ @application_commands = data['application_commands'] || []
566
+ @auto_moderation_rules = data['auto_moderation_rules'] || []
567
+ end
568
+
569
+ def users_index
570
+ @users_index ||= @users.each_with_object({}) { |user, index| index[user.id.to_s] = user }
571
+ end
572
+
573
+ def application_commands
574
+ @application_commands
575
+ end
576
+
577
+ def auto_moderation_rules
578
+ @auto_moderation_rules
579
+ end
580
+ end
294
581
  end
@@ -23,10 +23,9 @@ module DiscordRDA
23
23
  # @param shard_id [Integer] Shard ID
24
24
  def initialize(type, data, shard_id: 0)
25
25
  @type = type.to_s
26
- @data = data.freeze
26
+ @data = data.each_with_object({}) { |(key, value), hash| hash[key.to_s] = value }.freeze
27
27
  @shard_id = shard_id
28
28
  @timestamp = Time.now.utc.freeze
29
- freeze
30
29
  end
31
30
 
32
31
  # Get creation time from data if available
@@ -152,7 +151,7 @@ module DiscordRDA
152
151
  'ENTITLEMENT_CREATE' => 'EntitlementCreateEvent',
153
152
  'ENTITLEMENT_UPDATE' => 'EntitlementUpdateEvent',
154
153
  'ENTITLEMENT_DELETE' => 'EntitlementDeleteEvent'
155
- }.freeze
154
+ }
156
155
 
157
156
  class << self
158
157
  # Create an event from Gateway data
@@ -161,10 +160,10 @@ module DiscordRDA
161
160
  # @param shard_id [Integer] Shard ID
162
161
  # @return [Event] Event instance
163
162
  def create(event_type, data, shard_id = 0)
164
- class_name = EVENT_CLASSES[event_type]
163
+ class_name = event_classes[event_type.to_s]
165
164
 
166
- if class_name && Event.const_defined?(class_name)
167
- Event.const_get(class_name).new(data, shard_id: shard_id)
165
+ if class_name && DiscordRDA.const_defined?(class_name, false)
166
+ DiscordRDA.const_get(class_name, false).new(data, shard_id: shard_id)
168
167
  else
169
168
  Event.new(event_type, data, shard_id: shard_id)
170
169
  end
@@ -175,7 +174,13 @@ module DiscordRDA
175
174
  # @param klass [Class] Event class
176
175
  # @return [void]
177
176
  def register(event_type, klass)
178
- EVENT_CLASSES[event_type] = klass.name
177
+ event_classes[event_type.to_s] = klass.name.split('::').last
178
+ end
179
+
180
+ private
181
+
182
+ def event_classes
183
+ @event_classes ||= EVENT_CLASSES.dup
179
184
  end
180
185
  end
181
186
  end
@@ -983,4 +988,250 @@ module DiscordRDA
983
988
  @data['removed_member_ids'] || []
984
989
  end
985
990
  end
991
+
992
+ class GuildIntegrationsUpdateEvent < Event
993
+ def initialize(data, shard_id:)
994
+ super('GUILD_INTEGRATIONS_UPDATE', data, shard_id: shard_id)
995
+ end
996
+
997
+ def guild_id
998
+ @data['guild_id'] ? Snowflake.new(@data['guild_id']) : nil
999
+ end
1000
+ end
1001
+
1002
+ class PresenceUpdateEvent < Event
1003
+ def initialize(data, shard_id:)
1004
+ super('PRESENCE_UPDATE', data, shard_id: shard_id)
1005
+ end
1006
+
1007
+ def presence
1008
+ Presence.new(@data)
1009
+ end
1010
+
1011
+ def user
1012
+ presence.user
1013
+ end
1014
+
1015
+ def guild_id
1016
+ presence.guild_id
1017
+ end
1018
+
1019
+ def status
1020
+ presence.status
1021
+ end
1022
+
1023
+ def activities
1024
+ presence.activities
1025
+ end
1026
+
1027
+ def client_status
1028
+ presence.client_status
1029
+ end
1030
+ end
1031
+
1032
+ class TypingStartEvent < Event
1033
+ def initialize(data, shard_id:)
1034
+ super('TYPING_START', data, shard_id: shard_id)
1035
+ end
1036
+
1037
+ def channel_id
1038
+ @data['channel_id'] ? Snowflake.new(@data['channel_id']) : nil
1039
+ end
1040
+
1041
+ def guild_id
1042
+ @data['guild_id'] ? Snowflake.new(@data['guild_id']) : nil
1043
+ end
1044
+
1045
+ def user_id
1046
+ @data['user_id'] ? Snowflake.new(@data['user_id']) : nil
1047
+ end
1048
+
1049
+ def member
1050
+ return nil unless @data['member']
1051
+
1052
+ Member.new(@data['member'].merge('guild_id' => @data['guild_id']))
1053
+ end
1054
+
1055
+ def started_at
1056
+ Time.at(@data['timestamp'].to_i).utc if @data['timestamp']
1057
+ end
1058
+
1059
+ def guild?
1060
+ !guild_id.nil?
1061
+ end
1062
+ end
1063
+
1064
+ class UserUpdateEvent < Event
1065
+ def initialize(data, shard_id:)
1066
+ super('USER_UPDATE', data, shard_id: shard_id)
1067
+ end
1068
+
1069
+ def user
1070
+ User.new(@data)
1071
+ end
1072
+ end
1073
+
1074
+ class VoiceStateUpdateEvent < Event
1075
+ def initialize(data, shard_id:)
1076
+ super('VOICE_STATE_UPDATE', data, shard_id: shard_id)
1077
+ end
1078
+
1079
+ def voice_state
1080
+ VoiceState.new(@data)
1081
+ end
1082
+
1083
+ def guild_id
1084
+ voice_state.guild_id
1085
+ end
1086
+
1087
+ def channel_id
1088
+ voice_state.channel_id
1089
+ end
1090
+
1091
+ def user_id
1092
+ voice_state.user_id
1093
+ end
1094
+
1095
+ def member
1096
+ voice_state.member
1097
+ end
1098
+
1099
+ def session_id
1100
+ voice_state.session_id
1101
+ end
1102
+ end
1103
+
1104
+ class VoiceServerUpdateEvent < Event
1105
+ def initialize(data, shard_id:)
1106
+ super('VOICE_SERVER_UPDATE', data, shard_id: shard_id)
1107
+ end
1108
+
1109
+ def server
1110
+ VoiceServer.new(@data)
1111
+ end
1112
+
1113
+ def guild_id
1114
+ server.guild_id
1115
+ end
1116
+
1117
+ def token
1118
+ server.token
1119
+ end
1120
+
1121
+ def endpoint
1122
+ server.endpoint
1123
+ end
1124
+ end
1125
+
1126
+ class WebhooksUpdateEvent < Event
1127
+ def initialize(data, shard_id:)
1128
+ super('WEBHOOKS_UPDATE', data, shard_id: shard_id)
1129
+ end
1130
+
1131
+ def guild_id
1132
+ @data['guild_id'] ? Snowflake.new(@data['guild_id']) : nil
1133
+ end
1134
+
1135
+ def channel_id
1136
+ @data['channel_id'] ? Snowflake.new(@data['channel_id']) : nil
1137
+ end
1138
+ end
1139
+
1140
+ class StageInstanceCreateEvent < Event
1141
+ def initialize(data, shard_id:)
1142
+ super('STAGE_INSTANCE_CREATE', data, shard_id: shard_id)
1143
+ end
1144
+
1145
+ def stage_instance
1146
+ StageInstance.new(@data)
1147
+ end
1148
+
1149
+ def guild_id
1150
+ stage_instance.guild_id
1151
+ end
1152
+
1153
+ def channel_id
1154
+ stage_instance.channel_id
1155
+ end
1156
+ end
1157
+
1158
+ class StageInstanceUpdateEvent < Event
1159
+ def initialize(data, shard_id:)
1160
+ super('STAGE_INSTANCE_UPDATE', data, shard_id: shard_id)
1161
+ end
1162
+
1163
+ def stage_instance
1164
+ StageInstance.new(@data)
1165
+ end
1166
+
1167
+ def guild_id
1168
+ stage_instance.guild_id
1169
+ end
1170
+
1171
+ def channel_id
1172
+ stage_instance.channel_id
1173
+ end
1174
+ end
1175
+
1176
+ class StageInstanceDeleteEvent < Event
1177
+ def initialize(data, shard_id:)
1178
+ super('STAGE_INSTANCE_DELETE', data, shard_id: shard_id)
1179
+ end
1180
+
1181
+ def stage_instance
1182
+ StageInstance.new(@data)
1183
+ end
1184
+
1185
+ def guild_id
1186
+ stage_instance.guild_id
1187
+ end
1188
+
1189
+ def channel_id
1190
+ stage_instance.channel_id
1191
+ end
1192
+ end
1193
+
1194
+ class GuildAuditLogEntryCreateEvent < Event
1195
+ def initialize(data, shard_id:)
1196
+ super('GUILD_AUDIT_LOG_ENTRY_CREATE', data, shard_id: shard_id)
1197
+ end
1198
+
1199
+ def entry
1200
+ AuditLogEntry.new(@data)
1201
+ end
1202
+
1203
+ def guild_id
1204
+ @data['guild_id'] ? Snowflake.new(@data['guild_id']) : nil
1205
+ end
1206
+ end
1207
+
1208
+ class EntitlementCreateEvent < Event
1209
+ def initialize(data, shard_id:)
1210
+ super('ENTITLEMENT_CREATE', data, shard_id: shard_id)
1211
+ end
1212
+
1213
+ def entitlement
1214
+ Entitlement.new(@data)
1215
+ end
1216
+ end
1217
+
1218
+ class EntitlementUpdateEvent < Event
1219
+ def initialize(data, shard_id:)
1220
+ super('ENTITLEMENT_UPDATE', data, shard_id: shard_id)
1221
+ end
1222
+
1223
+ def entitlement
1224
+ Entitlement.new(@data)
1225
+ end
1226
+ end
1227
+
1228
+ class EntitlementDeleteEvent < Event
1229
+ def initialize(data, shard_id:)
1230
+ super('ENTITLEMENT_DELETE', data, shard_id: shard_id)
1231
+ end
1232
+
1233
+ def entitlement
1234
+ Entitlement.new(@data)
1235
+ end
1236
+ end
986
1237
  end
@@ -5,6 +5,8 @@ module DiscordRDA
5
5
  # Supports Chat Input Commands (slash), User Commands, and Message Commands.
6
6
  #
7
7
  class ApplicationCommand < Entity
8
+ EMPTY_EXECUTION_POLICY = {}.freeze
9
+
8
10
  # Command types
9
11
  TYPES = {
10
12
  chat_input: 1, # Slash commands
@@ -116,6 +118,10 @@ module DiscordRDA
116
118
  @handler
117
119
  end
118
120
 
121
+ def execution_policy
122
+ @execution_policy || EMPTY_EXECUTION_POLICY
123
+ end
124
+
119
125
  # Set the handler block
120
126
  # @param block [Proc] Handler block
121
127
  def handler=(block)
@@ -204,9 +210,10 @@ module DiscordRDA
204
210
 
205
211
  # Builder for creating application commands with DSL
206
212
  class CommandBuilder
207
- def initialize(name, description = nil)
213
+ def initialize(name, description = nil, type: 1)
208
214
  @name = name
209
215
  @description = description || ''
216
+ @type = type
210
217
  @options = []
211
218
  @name_localizations = {}
212
219
  @description_localizations = {}
@@ -214,6 +221,15 @@ module DiscordRDA
214
221
  @dm_permission = true
215
222
  @nsfw = false
216
223
  @handler = nil
224
+ @execution_policy = {}
225
+ end
226
+
227
+ # Set command type
228
+ # @param type [Integer, Symbol] Discord command type
229
+ # @return [self]
230
+ def type(type)
231
+ @type = type.is_a?(Symbol) ? ApplicationCommand::TYPES.fetch(type) : type
232
+ self
217
233
  end
218
234
 
219
235
  # Set localized name
@@ -346,8 +362,7 @@ module DiscordRDA
346
362
  # @param description [String] Subcommand description
347
363
  # @yield [CommandBuilder] Block for building subcommand options
348
364
  def subcommand(name, description, &block)
349
- builder = CommandBuilder.new(name, description)
350
- builder.instance_variable_set(:@type, 1) # sub_command type
365
+ builder = CommandBuilder.new(name, description, type: 1)
351
366
  block.call(builder) if block
352
367
  @options << builder.to_h
353
368
  self
@@ -358,8 +373,7 @@ module DiscordRDA
358
373
  # @param description [String] Group description
359
374
  # @yield [CommandBuilder] Block for building subcommands in this group
360
375
  def group(name, description, &block)
361
- builder = CommandBuilder.new(name, description)
362
- builder.instance_variable_set(:@type, 2) # sub_command_group type
376
+ builder = CommandBuilder.new(name, description, type: 2)
363
377
  block.call(builder) if block
364
378
  @options << builder.to_h
365
379
  self
@@ -397,6 +411,27 @@ module DiscordRDA
397
411
  self
398
412
  end
399
413
 
414
+ def timeout(seconds)
415
+ @execution_policy[:timeout_seconds] = seconds.to_f
416
+ self
417
+ end
418
+
419
+ def max_concurrency(value)
420
+ @execution_policy[:max_concurrency] = value.to_i
421
+ self
422
+ end
423
+
424
+ def circuit_breaker(failures:, cooldown:)
425
+ @execution_policy[:failure_threshold] = failures.to_i
426
+ @execution_policy[:cooldown_seconds] = cooldown.to_f
427
+ self
428
+ end
429
+
430
+ def execution_policy(**policy)
431
+ @execution_policy.merge!(policy)
432
+ self
433
+ end
434
+
400
435
  # Convert to hash for API
401
436
  # @return [Hash] Command hash
402
437
  def to_h
@@ -408,6 +443,7 @@ module DiscordRDA
408
443
  options: @options.empty? ? nil : @options,
409
444
  default_member_permissions: @default_member_permissions,
410
445
  dm_permission: @dm_permission,
446
+ type: @type,
411
447
  nsfw: @nsfw
412
448
  }.compact
413
449
  end
@@ -415,8 +451,10 @@ module DiscordRDA
415
451
  # Build and return ApplicationCommand
416
452
  # @return [ApplicationCommand] Command instance
417
453
  def build
418
- cmd = ApplicationCommand.new(to_h)
454
+ cmd = ApplicationCommand.new(to_h).dup
419
455
  cmd.handler = @handler
456
+ cmd.instance_variable_set(:@execution_policy, @execution_policy.dup)
457
+ cmd.freeze
420
458
  cmd
421
459
  end
422
460