discordrb 1.8.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of discordrb might be problematic. Click here for more details.

Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.overcommit.yml +7 -0
  3. data/.rubocop.yml +5 -4
  4. data/CHANGELOG.md +77 -0
  5. data/README.md +25 -15
  6. data/discordrb.gemspec +2 -3
  7. data/examples/commands.rb +14 -2
  8. data/examples/ping.rb +1 -1
  9. data/examples/pm_send.rb +1 -1
  10. data/lib/discordrb.rb +9 -0
  11. data/lib/discordrb/api.rb +176 -50
  12. data/lib/discordrb/await.rb +3 -0
  13. data/lib/discordrb/bot.rb +607 -372
  14. data/lib/discordrb/cache.rb +208 -0
  15. data/lib/discordrb/commands/command_bot.rb +50 -18
  16. data/lib/discordrb/commands/container.rb +11 -2
  17. data/lib/discordrb/commands/events.rb +2 -0
  18. data/lib/discordrb/commands/parser.rb +10 -8
  19. data/lib/discordrb/commands/rate_limiter.rb +2 -0
  20. data/lib/discordrb/container.rb +24 -25
  21. data/lib/discordrb/data.rb +521 -219
  22. data/lib/discordrb/errors.rb +6 -7
  23. data/lib/discordrb/events/await.rb +2 -0
  24. data/lib/discordrb/events/bans.rb +3 -1
  25. data/lib/discordrb/events/channels.rb +124 -0
  26. data/lib/discordrb/events/generic.rb +2 -0
  27. data/lib/discordrb/events/guilds.rb +16 -13
  28. data/lib/discordrb/events/lifetime.rb +12 -2
  29. data/lib/discordrb/events/members.rb +26 -15
  30. data/lib/discordrb/events/message.rb +20 -7
  31. data/lib/discordrb/events/presence.rb +18 -2
  32. data/lib/discordrb/events/roles.rb +83 -0
  33. data/lib/discordrb/events/typing.rb +15 -2
  34. data/lib/discordrb/events/voice_state_update.rb +2 -0
  35. data/lib/discordrb/light.rb +8 -0
  36. data/lib/discordrb/light/data.rb +62 -0
  37. data/lib/discordrb/light/integrations.rb +73 -0
  38. data/lib/discordrb/light/light_bot.rb +56 -0
  39. data/lib/discordrb/logger.rb +4 -0
  40. data/lib/discordrb/permissions.rb +16 -12
  41. data/lib/discordrb/token_cache.rb +3 -0
  42. data/lib/discordrb/version.rb +3 -1
  43. data/lib/discordrb/voice/encoder.rb +2 -0
  44. data/lib/discordrb/voice/network.rb +21 -14
  45. data/lib/discordrb/voice/voice_bot.rb +26 -3
  46. data/lib/discordrb/websocket.rb +69 -0
  47. metadata +15 -26
  48. data/lib/discordrb/events/channel_create.rb +0 -44
  49. data/lib/discordrb/events/channel_delete.rb +0 -44
  50. data/lib/discordrb/events/channel_update.rb +0 -46
  51. data/lib/discordrb/events/guild_role_create.rb +0 -35
  52. data/lib/discordrb/events/guild_role_delete.rb +0 -36
  53. data/lib/discordrb/events/guild_role_update.rb +0 -35
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'discordrb/voice/encoder'
2
4
  require 'discordrb/voice/network'
5
+ require 'discordrb/logger'
3
6
 
4
7
  # Voice support
5
8
  module Discordrb::Voice
@@ -67,8 +70,11 @@ module Discordrb::Voice
67
70
  # @return [Float] the volume for audio playback, `1.0` by default.
68
71
  attr_accessor :volume
69
72
 
73
+ # @!visibility private
70
74
  def initialize(channel, bot, token, session, endpoint, encrypted)
71
75
  @bot = bot
76
+ @channel = channel
77
+
72
78
  @ws = VoiceWS.new(channel, bot, token, session, endpoint)
73
79
  @udp = @ws.udp
74
80
  @udp.encrypted = encrypted
@@ -85,6 +91,9 @@ module Discordrb::Voice
85
91
 
86
92
  @encoder = Encoder.new
87
93
  @ws.connect
94
+ rescue => e
95
+ Discordrb::LOGGER.log_exception(e)
96
+ raise
88
97
  end
89
98
 
90
99
  # @return [true, false] whether audio data sent will be encrypted.
@@ -141,7 +150,7 @@ module Discordrb::Voice
141
150
  # Permanently disconnects from the voice channel; to reconnect you will have to call {Bot#voice_connect} again.
142
151
  def destroy
143
152
  stop_playing
144
- @bot.voice_destroy(false)
153
+ @bot.voice_destroy(@channel.server.id, false)
145
154
  @ws.destroy
146
155
  end
147
156
 
@@ -153,6 +162,7 @@ module Discordrb::Voice
153
162
  def play(encoded_io)
154
163
  stop_playing if @playing
155
164
  @retry_attempts = 3
165
+ @first_packet = true
156
166
 
157
167
  play_internal do
158
168
  buf = nil
@@ -161,6 +171,8 @@ module Discordrb::Voice
161
171
  begin
162
172
  buf = encoded_io.readpartial(DATA_LENGTH) if encoded_io
163
173
  rescue EOFError
174
+ raise IOError, 'File or stream not found!' if @first_packet
175
+
164
176
  @bot.debug('EOF while reading, breaking immediately')
165
177
  break
166
178
  end
@@ -177,12 +189,23 @@ module Discordrb::Voice
177
189
  # Adjust volume
178
190
  buf = @encoder.adjust_volume(buf, @volume) if @volume != 1.0
179
191
 
192
+ @first_packet = false
193
+
180
194
  # Encode data
181
195
  @encoder.encode(buf)
182
196
  end
183
197
 
184
198
  # If the stream is a process, kill it
185
- Process.kill('TERM', encoded_io.pid) if encoded_io.respond_to? :pid
199
+ if encoded_io.respond_to? :pid
200
+ Discordrb::LOGGER.info("Killing ffmpeg process with pid #{encoded_io.pid.inspect}")
201
+
202
+ begin
203
+ Process.kill('TERM', encoded_io.pid)
204
+ rescue => e
205
+ Discordrb::LOGGER.warn('Failed to kill ffmpeg process! You *might* have a process leak now.')
206
+ Discordrb::LOGGER.warn("Reason: #{e}")
207
+ end
208
+ end
186
209
 
187
210
  # Close the stream
188
211
  encoded_io.close
@@ -225,7 +248,7 @@ module Discordrb::Voice
225
248
  # Read header
226
249
  header = input_stream.read(2).unpack('s<')[0]
227
250
 
228
- raise RuntimeError, 'Negative header in DCA file! Your file is likely corrupted.' if header < 0
251
+ raise 'Negative header in DCA file! Your file is likely corrupted.' if header < 0
229
252
  rescue EOFError
230
253
  @bot.debug 'Finished DCA parsing'
231
254
  break
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'websocket-client-simple'
4
+
5
+ puts "Using WSCS version: #{WebSocket::Client::Simple::VERSION}"
6
+ module WebSocket::Client::Simple
7
+ # Patch to the WSCS class to allow reading the internal thread
8
+ class Client
9
+ # @return [Thread] the internal thread this client is using for the event loop.
10
+ attr_reader :thread
11
+ end
12
+ end
13
+
14
+ module Discordrb
15
+ # Utility wrapper class that abstracts an instance of WSCS. Useful should we decide that WSCS isn't good either -
16
+ # in that case we can just switch to something else
17
+ class WebSocket
18
+ attr_reader :open_handler, :message_handler, :close_handler, :error_handler
19
+
20
+ # Create a new WebSocket and connect to the given endpoint.
21
+ # @param endpoint [String] Where to connect to.
22
+ # @param open_handler [#call] The handler that should be called when the websocket has opened successfully.
23
+ # @param message_handler [#call] The handler that should be called when the websocket receives a message. The
24
+ # handler can take one parameter which will have a `data` attribute for normal messages and `code` and `data` for
25
+ # close frames.
26
+ # @param close_handler [#call] The handler that should be called when the websocket is closed due to an internal
27
+ # error. The error will be passed as the first parameter to the handler.
28
+ # @param error_handler [#call] The handler that should be called when an error occurs in another handler. The error
29
+ # will be passed as the first parameter to the handler.
30
+ def initialize(endpoint, open_handler, message_handler, close_handler, error_handler)
31
+ @open_handler = open_handler
32
+ @message_handler = message_handler
33
+ @close_handler = close_handler
34
+ @error_handler = error_handler
35
+
36
+ instance = self # to work around WSCS's weird way of handling blocks
37
+
38
+ @client = ::WebSocket::Client::Simple.connect(endpoint) do |ws|
39
+ ws.on(:open) { instance.open_handler.call }
40
+ ws.on(:message) do |msg|
41
+ # If the message has a code attribute, it is in reality a close message
42
+ if msg.code
43
+ instance.close_handler.call(msg)
44
+ else
45
+ instance.message_handler.call(msg.data)
46
+ end
47
+ end
48
+ ws.on(:close) { |err| instance.close_handler.call(err) }
49
+ ws.on(:error) { |err| instance.error_handler.call(err) }
50
+ end
51
+ end
52
+
53
+ # Send data over this WebSocket
54
+ # @param data [String] What to send
55
+ def send(data)
56
+ @client.send(data)
57
+ end
58
+
59
+ # Close the WebSocket connection
60
+ def close
61
+ @client.close
62
+ end
63
+
64
+ # @return [Thread] the internal WSCS thread
65
+ def thread
66
+ @client.thread
67
+ end
68
+ end
69
+ end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discordrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - meew0
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-03-11 00:00:00.000000000 Z
11
+ date: 2016-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: faye-websocket
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: rest-client
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +58,14 @@ dependencies:
72
58
  requirements:
73
59
  - - ">="
74
60
  - !ruby/object:Gem::Version
75
- version: '0'
61
+ version: 0.3.0
76
62
  type: :runtime
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - ">="
81
67
  - !ruby/object:Gem::Version
82
- version: '0'
68
+ version: 0.3.0
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: rbnacl
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -156,14 +142,14 @@ dependencies:
156
142
  requirements:
157
143
  - - '='
158
144
  - !ruby/object:Gem::Version
159
- version: 0.37.2
145
+ version: 0.39.0
160
146
  type: :development
161
147
  prerelease: false
162
148
  version_requirements: !ruby/object:Gem::Requirement
163
149
  requirements:
164
150
  - - '='
165
151
  - !ruby/object:Gem::Version
166
- version: 0.37.2
152
+ version: 0.39.0
167
153
  description: A Ruby implementation of the Discord (https://discordapp.com) API.
168
154
  email:
169
155
  - ''
@@ -172,6 +158,7 @@ extensions: []
172
158
  extra_rdoc_files: []
173
159
  files:
174
160
  - ".gitignore"
161
+ - ".overcommit.yml"
175
162
  - ".rspec"
176
163
  - ".rubocop.yml"
177
164
  - ".travis.yml"
@@ -191,6 +178,7 @@ files:
191
178
  - lib/discordrb/api.rb
192
179
  - lib/discordrb/await.rb
193
180
  - lib/discordrb/bot.rb
181
+ - lib/discordrb/cache.rb
194
182
  - lib/discordrb/commands/command_bot.rb
195
183
  - lib/discordrb/commands/container.rb
196
184
  - lib/discordrb/commands/events.rb
@@ -201,20 +189,20 @@ files:
201
189
  - lib/discordrb/errors.rb
202
190
  - lib/discordrb/events/await.rb
203
191
  - lib/discordrb/events/bans.rb
204
- - lib/discordrb/events/channel_create.rb
205
- - lib/discordrb/events/channel_delete.rb
206
- - lib/discordrb/events/channel_update.rb
192
+ - lib/discordrb/events/channels.rb
207
193
  - lib/discordrb/events/generic.rb
208
- - lib/discordrb/events/guild_role_create.rb
209
- - lib/discordrb/events/guild_role_delete.rb
210
- - lib/discordrb/events/guild_role_update.rb
211
194
  - lib/discordrb/events/guilds.rb
212
195
  - lib/discordrb/events/lifetime.rb
213
196
  - lib/discordrb/events/members.rb
214
197
  - lib/discordrb/events/message.rb
215
198
  - lib/discordrb/events/presence.rb
199
+ - lib/discordrb/events/roles.rb
216
200
  - lib/discordrb/events/typing.rb
217
201
  - lib/discordrb/events/voice_state_update.rb
202
+ - lib/discordrb/light.rb
203
+ - lib/discordrb/light/data.rb
204
+ - lib/discordrb/light/integrations.rb
205
+ - lib/discordrb/light/light_bot.rb
218
206
  - lib/discordrb/logger.rb
219
207
  - lib/discordrb/permissions.rb
220
208
  - lib/discordrb/token_cache.rb
@@ -222,6 +210,7 @@ files:
222
210
  - lib/discordrb/voice/encoder.rb
223
211
  - lib/discordrb/voice/network.rb
224
212
  - lib/discordrb/voice/voice_bot.rb
213
+ - lib/discordrb/websocket.rb
225
214
  homepage: https://github.com/meew0/discordrb
226
215
  licenses:
227
216
  - MIT
@@ -1,44 +0,0 @@
1
- require 'discordrb/events/generic'
2
- require 'discordrb/data'
3
-
4
- module Discordrb::Events
5
- # Raised when a channel is created
6
- class ChannelCreateEvent < Event
7
- attr_reader :type, :topic, :position, :name, :is_private, :id, :server
8
-
9
- def initialize(data, bot)
10
- @type = data['type']
11
- @topic = data['topic']
12
- @position = data['position']
13
- @name = data['name']
14
- @is_private = data['is_private']
15
- @id = data['id']
16
- @server = bot.server(data['guild_id'].to_i)
17
- end
18
- end
19
-
20
- # Event handler for ChannelCreateEvent
21
- class ChannelCreateEventHandler < EventHandler
22
- def matches?(event)
23
- # Check for the proper event type
24
- return false unless event.is_a? ChannelCreateEvent
25
-
26
- [
27
- matches_all(@attributes[:type], event.type) do |a, e|
28
- a == if a.is_a? String
29
- e.name
30
- else
31
- e
32
- end
33
- end,
34
- matches_all(@attributes[:name], event.name) do |a, e|
35
- a == if a.is_a? String
36
- e.to_s
37
- else
38
- e
39
- end
40
- end
41
- ].reduce(true, &:&)
42
- end
43
- end
44
- end
@@ -1,44 +0,0 @@
1
- require 'discordrb/events/generic'
2
- require 'discordrb/data'
3
-
4
- module Discordrb::Events
5
- # Raised when a channel is deleted
6
- class ChannelDeleteEvent < Event
7
- attr_reader :type, :topic, :position, :name, :is_private, :id, :server
8
-
9
- def initialize(data, bot)
10
- @type = data['type']
11
- @topic = data['topic']
12
- @position = data['position']
13
- @name = data['name']
14
- @is_private = data['is_private']
15
- @id = data['id'].to_i
16
- @server = bot.server(data['guild_id'].to_i)
17
- end
18
- end
19
-
20
- # Event handler for ChannelDeleteEvent
21
- class ChannelDeleteEventHandler < EventHandler
22
- def matches?(event)
23
- # Check for the proper event type
24
- return false unless event.is_a? ChannelDeleteEvent
25
-
26
- [
27
- matches_all(@attributes[:type], event.type) do |a, e|
28
- a == if a.is_a? String
29
- e.name
30
- else
31
- e
32
- end
33
- end,
34
- matches_all(@attributes[:name], event.name) do |a, e|
35
- a == if a.is_a? String
36
- e.to_s
37
- else
38
- e
39
- end
40
- end
41
- ].reduce(true, &:&)
42
- end
43
- end
44
- end
@@ -1,46 +0,0 @@
1
- require 'discordrb/events/generic'
2
- require 'discordrb/data'
3
-
4
- module Discordrb::Events
5
- # Raised when a channel is updated (e.g. topic changes)
6
- class ChannelUpdateEvent < Event
7
- attr_reader :type, :topic, :position, :name, :is_private, :channel, :server
8
-
9
- def initialize(data, bot)
10
- @type = data['type']
11
- @topic = data['topic']
12
- @position = data['position']
13
- @name = data['name']
14
- @is_private = data['is_private']
15
- @server = bot.server(data['guild_id'].to_i)
16
- return unless @server
17
-
18
- @channel = bot.channel(data['id'].to_i)
19
- end
20
- end
21
-
22
- # Event handler for ChannelUpdateEvent
23
- class ChannelUpdateEventHandler < EventHandler
24
- def matches?(event)
25
- # Check for the proper event type
26
- return false unless event.is_a? ChannelUpdateEvent
27
-
28
- [
29
- matches_all(@attributes[:type], event.type) do |a, e|
30
- a == if a.is_a? String
31
- e.name
32
- else
33
- e
34
- end
35
- end,
36
- matches_all(@attributes[:name], event.name) do |a, e|
37
- a == if a.is_a? String
38
- e.to_s
39
- else
40
- e
41
- end
42
- end
43
- ].reduce(true, &:&)
44
- end
45
- end
46
- end
@@ -1,35 +0,0 @@
1
- require 'discordrb/events/generic'
2
- require 'discordrb/data'
3
-
4
- module Discordrb::Events
5
- # Raised when a role is created on a server
6
- class GuildRoleCreateEvent < Event
7
- attr_reader :role, :server
8
-
9
- def initialize(data, bot)
10
- @server = bot.server(data['guild_id'].to_i)
11
- return unless @server
12
-
13
- role_id = data['role']['id'].to_i
14
- @role = @server.roles.find { |r| r.id == role_id }
15
- end
16
- end
17
-
18
- # Event handler for GuildRoleCreateEvent
19
- class GuildRoleCreateEventHandler < EventHandler
20
- def matches?(event)
21
- # Check for the proper event type
22
- return false unless event.is_a? GuildRoleCreateEvent
23
-
24
- [
25
- matches_all(@attributes[:name], event.name) do |a, e|
26
- a == if a.is_a? String
27
- e.to_s
28
- else
29
- e
30
- end
31
- end
32
- ].reduce(true, &:&)
33
- end
34
- end
35
- end
@@ -1,36 +0,0 @@
1
- require 'discordrb/events/generic'
2
- require 'discordrb/data'
3
-
4
- module Discordrb::Events
5
- # Raised when a role is deleted from a server
6
- class GuildRoleDeleteEvent < Event
7
- attr_reader :id, :server
8
-
9
- def initialize(data, bot)
10
- # The role should already be deleted from the server's list
11
- # by the time we create this event, so we'll create a temporary
12
- # role object for event consumers to use.
13
- @id = data['role_id'].to_i
14
- server_id = data['guild_id'].to_i
15
- @server = bot.server(server_id)
16
- end
17
- end
18
-
19
- # EventHandler for GuildRoleDeleteEvent
20
- class GuildRoleDeleteEventHandler < EventHandler
21
- def matches?(event)
22
- # Check for the proper event type
23
- return false unless event.is_a? GuildRoleDeleteEvent
24
-
25
- [
26
- matches_all(@attributes[:name], event.name) do |a, e|
27
- a == if a.is_a? String
28
- e.to_s
29
- else
30
- e
31
- end
32
- end
33
- ].reduce(true, &:&)
34
- end
35
- end
36
- end