actioncable 5.0.1 → 6.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +31 -117
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +4 -535
  5. data/app/assets/javascripts/action_cable.js +517 -0
  6. data/lib/action_cable.rb +20 -10
  7. data/lib/action_cable/channel.rb +3 -0
  8. data/lib/action_cable/channel/base.rb +31 -23
  9. data/lib/action_cable/channel/broadcasting.rb +22 -10
  10. data/lib/action_cable/channel/callbacks.rb +4 -2
  11. data/lib/action_cable/channel/naming.rb +5 -2
  12. data/lib/action_cable/channel/periodic_timers.rb +4 -3
  13. data/lib/action_cable/channel/streams.rb +39 -11
  14. data/lib/action_cable/channel/test_case.rb +310 -0
  15. data/lib/action_cable/connection.rb +3 -2
  16. data/lib/action_cable/connection/authorization.rb +8 -6
  17. data/lib/action_cable/connection/base.rb +34 -26
  18. data/lib/action_cable/connection/client_socket.rb +20 -18
  19. data/lib/action_cable/connection/identification.rb +5 -4
  20. data/lib/action_cable/connection/internal_channel.rb +4 -2
  21. data/lib/action_cable/connection/message_buffer.rb +3 -2
  22. data/lib/action_cable/connection/stream.rb +9 -5
  23. data/lib/action_cable/connection/stream_event_loop.rb +4 -2
  24. data/lib/action_cable/connection/subscriptions.rb +14 -13
  25. data/lib/action_cable/connection/tagged_logger_proxy.rb +4 -2
  26. data/lib/action_cable/connection/test_case.rb +234 -0
  27. data/lib/action_cable/connection/web_socket.rb +7 -5
  28. data/lib/action_cable/engine.rb +7 -5
  29. data/lib/action_cable/gem_version.rb +5 -3
  30. data/lib/action_cable/helpers/action_cable_helper.rb +6 -4
  31. data/lib/action_cable/remote_connections.rb +9 -4
  32. data/lib/action_cable/server.rb +2 -1
  33. data/lib/action_cable/server/base.rb +17 -10
  34. data/lib/action_cable/server/broadcasting.rb +9 -3
  35. data/lib/action_cable/server/configuration.rb +21 -22
  36. data/lib/action_cable/server/connections.rb +2 -0
  37. data/lib/action_cable/server/worker.rb +11 -11
  38. data/lib/action_cable/server/worker/active_record_connection_management.rb +2 -0
  39. data/lib/action_cable/subscription_adapter.rb +4 -0
  40. data/lib/action_cable/subscription_adapter/async.rb +3 -1
  41. data/lib/action_cable/subscription_adapter/base.rb +6 -0
  42. data/lib/action_cable/subscription_adapter/channel_prefix.rb +28 -0
  43. data/lib/action_cable/subscription_adapter/inline.rb +2 -0
  44. data/lib/action_cable/subscription_adapter/postgresql.rb +40 -14
  45. data/lib/action_cable/subscription_adapter/redis.rb +19 -11
  46. data/lib/action_cable/subscription_adapter/subscriber_map.rb +3 -1
  47. data/lib/action_cable/subscription_adapter/test.rb +40 -0
  48. data/lib/action_cable/test_case.rb +11 -0
  49. data/lib/action_cable/test_helper.rb +133 -0
  50. data/lib/action_cable/version.rb +3 -1
  51. data/lib/rails/generators/channel/USAGE +5 -6
  52. data/lib/rails/generators/channel/channel_generator.rb +16 -11
  53. data/lib/rails/generators/channel/templates/application_cable/{channel.rb → channel.rb.tt} +0 -0
  54. data/lib/rails/generators/channel/templates/application_cable/{connection.rb → connection.rb.tt} +0 -0
  55. data/lib/rails/generators/channel/templates/{channel.rb → channel.rb.tt} +0 -0
  56. data/lib/rails/generators/channel/templates/{assets/channel.js → javascript/channel.js.tt} +6 -4
  57. data/lib/rails/generators/channel/templates/javascript/consumer.js.tt +6 -0
  58. data/lib/rails/generators/channel/templates/javascript/index.js.tt +5 -0
  59. data/lib/rails/generators/test_unit/channel_generator.rb +20 -0
  60. data/lib/rails/generators/test_unit/templates/channel_test.rb.tt +8 -0
  61. metadata +46 -38
  62. data/lib/action_cable/connection/faye_client_socket.rb +0 -48
  63. data/lib/action_cable/connection/faye_event_loop.rb +0 -44
  64. data/lib/action_cable/subscription_adapter/evented_redis.rb +0 -79
  65. data/lib/assets/compiled/action_cable.js +0 -597
  66. data/lib/rails/generators/channel/templates/assets/cable.js +0 -13
  67. data/lib/rails/generators/channel/templates/assets/channel.coffee +0 -14
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/test_case"
4
+
5
+ module ActionCable
6
+ class TestCase < ActiveSupport::TestCase
7
+ include ActionCable::TestHelper
8
+
9
+ ActiveSupport.run_load_hooks(:action_cable_test_case, self)
10
+ end
11
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionCable
4
+ # Provides helper methods for testing Action Cable broadcasting
5
+ module TestHelper
6
+ def before_setup # :nodoc:
7
+ server = ActionCable.server
8
+ test_adapter = ActionCable::SubscriptionAdapter::Test.new(server)
9
+
10
+ @old_pubsub_adapter = server.pubsub
11
+
12
+ server.instance_variable_set(:@pubsub, test_adapter)
13
+ super
14
+ end
15
+
16
+ def after_teardown # :nodoc:
17
+ super
18
+ ActionCable.server.instance_variable_set(:@pubsub, @old_pubsub_adapter)
19
+ end
20
+
21
+ # Asserts that the number of broadcasted messages to the stream matches the given number.
22
+ #
23
+ # def test_broadcasts
24
+ # assert_broadcasts 'messages', 0
25
+ # ActionCable.server.broadcast 'messages', { text: 'hello' }
26
+ # assert_broadcasts 'messages', 1
27
+ # ActionCable.server.broadcast 'messages', { text: 'world' }
28
+ # assert_broadcasts 'messages', 2
29
+ # end
30
+ #
31
+ # If a block is passed, that block should cause the specified number of
32
+ # messages to be broadcasted.
33
+ #
34
+ # def test_broadcasts_again
35
+ # assert_broadcasts('messages', 1) do
36
+ # ActionCable.server.broadcast 'messages', { text: 'hello' }
37
+ # end
38
+ #
39
+ # assert_broadcasts('messages', 2) do
40
+ # ActionCable.server.broadcast 'messages', { text: 'hi' }
41
+ # ActionCable.server.broadcast 'messages', { text: 'how are you?' }
42
+ # end
43
+ # end
44
+ #
45
+ def assert_broadcasts(stream, number, &block)
46
+ if block_given?
47
+ original_count = broadcasts_size(stream)
48
+ assert_nothing_raised(&block)
49
+ new_count = broadcasts_size(stream)
50
+ actual_count = new_count - original_count
51
+ else
52
+ actual_count = broadcasts_size(stream)
53
+ end
54
+
55
+ assert_equal number, actual_count, "#{number} broadcasts to #{stream} expected, but #{actual_count} were sent"
56
+ end
57
+
58
+ # Asserts that no messages have been sent to the stream.
59
+ #
60
+ # def test_no_broadcasts
61
+ # assert_no_broadcasts 'messages'
62
+ # ActionCable.server.broadcast 'messages', { text: 'hi' }
63
+ # assert_broadcasts 'messages', 1
64
+ # end
65
+ #
66
+ # If a block is passed, that block should not cause any message to be sent.
67
+ #
68
+ # def test_broadcasts_again
69
+ # assert_no_broadcasts 'messages' do
70
+ # # No job messages should be sent from this block
71
+ # end
72
+ # end
73
+ #
74
+ # Note: This assertion is simply a shortcut for:
75
+ #
76
+ # assert_broadcasts 'messages', 0, &block
77
+ #
78
+ def assert_no_broadcasts(stream, &block)
79
+ assert_broadcasts stream, 0, &block
80
+ end
81
+
82
+ # Asserts that the specified message has been sent to the stream.
83
+ #
84
+ # def test_assert_transmitted_message
85
+ # ActionCable.server.broadcast 'messages', text: 'hello'
86
+ # assert_broadcast_on('messages', text: 'hello')
87
+ # end
88
+ #
89
+ # If a block is passed, that block should cause a message with the specified data to be sent.
90
+ #
91
+ # def test_assert_broadcast_on_again
92
+ # assert_broadcast_on('messages', text: 'hello') do
93
+ # ActionCable.server.broadcast 'messages', text: 'hello'
94
+ # end
95
+ # end
96
+ #
97
+ def assert_broadcast_on(stream, data, &block)
98
+ # Encode to JSON and back–we want to use this value to compare
99
+ # with decoded JSON.
100
+ # Comparing JSON strings doesn't work due to the order if the keys.
101
+ serialized_msg =
102
+ ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(data))
103
+
104
+ new_messages = broadcasts(stream)
105
+ if block_given?
106
+ old_messages = new_messages
107
+ clear_messages(stream)
108
+
109
+ assert_nothing_raised(&block)
110
+ new_messages = broadcasts(stream)
111
+ clear_messages(stream)
112
+
113
+ # Restore all sent messages
114
+ (old_messages + new_messages).each { |m| pubsub_adapter.broadcast(stream, m) }
115
+ end
116
+
117
+ message = new_messages.find { |msg| ActiveSupport::JSON.decode(msg) == serialized_msg }
118
+
119
+ assert message, "No messages sent with #{data} to #{stream}"
120
+ end
121
+
122
+ def pubsub_adapter # :nodoc:
123
+ ActionCable.server.pubsub
124
+ end
125
+
126
+ delegate :broadcasts, :clear_messages, to: :pubsub_adapter
127
+
128
+ private
129
+ def broadcasts_size(channel)
130
+ broadcasts(channel).size
131
+ end
132
+ end
133
+ end
@@ -1,4 +1,6 @@
1
- require_relative 'gem_version'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "gem_version"
2
4
 
3
5
  module ActionCable
4
6
  # Returns the version of the currently loaded Action Cable as a <tt>Gem::Version</tt>
@@ -1,14 +1,13 @@
1
1
  Description:
2
2
  ============
3
- Stubs out a new cable channel for the server (in Ruby) and client (in CoffeeScript).
3
+ Generates a new cable channel for the server (in Ruby) and client (in JavaScript).
4
4
  Pass the channel name, either CamelCased or under_scored, and an optional list of channel actions as arguments.
5
5
 
6
- Note: Turn on the cable connection in app/assets/javascript/cable.js after generating any channels.
7
-
8
6
  Example:
9
7
  ========
10
- rails generate channel Chat speak
8
+ bin/rails generate channel Chat speak
11
9
 
12
- creates a Chat channel class and CoffeeScript asset:
10
+ creates a Chat channel class, test and JavaScript asset:
13
11
  Channel: app/channels/chat_channel.rb
14
- Assets: app/assets/javascript/channels/chat.coffee
12
+ Test: test/channels/chat_channel_test.rb
13
+ Assets: app/javascript/channels/chat_channel.js
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rails
2
4
  module Generators
3
5
  class ChannelGenerator < NamedBase
4
- source_root File.expand_path("../templates", __FILE__)
6
+ source_root File.expand_path("templates", __dir__)
5
7
 
6
8
  argument :actions, type: :array, default: [], banner: "method method"
7
9
 
@@ -9,36 +11,39 @@ module Rails
9
11
 
10
12
  check_class_collision suffix: "Channel"
11
13
 
14
+ hook_for :test_framework
15
+
12
16
  def create_channel_file
13
- template "channel.rb", File.join('app/channels', class_path, "#{file_name}_channel.rb")
17
+ template "channel.rb", File.join("app/channels", class_path, "#{file_name}_channel.rb")
14
18
 
15
19
  if options[:assets]
16
- if self.behavior == :invoke
17
- template "assets/cable.js", "app/assets/javascripts/cable.js"
20
+ if behavior == :invoke
21
+ template "javascript/index.js", "app/javascript/channels/index.js"
22
+ template "javascript/consumer.js", "app/javascript/channels/consumer.js"
18
23
  end
19
24
 
20
- js_template "assets/channel", File.join('app/assets/javascripts/channels', class_path, "#{file_name}")
25
+ js_template "javascript/channel", File.join("app/javascript/channels", class_path, "#{file_name}_channel")
21
26
  end
22
27
 
23
28
  generate_application_cable_files
24
29
  end
25
30
 
26
- protected
31
+ private
27
32
  def file_name
28
- @_file_name ||= super.gsub(/_channel/i, '')
33
+ @_file_name ||= super.sub(/_channel\z/i, "")
29
34
  end
30
35
 
31
36
  # FIXME: Change these files to symlinks once RubyGems 2.5.0 is required.
32
37
  def generate_application_cable_files
33
- return if self.behavior != :invoke
38
+ return if behavior != :invoke
34
39
 
35
40
  files = [
36
- 'application_cable/channel.rb',
37
- 'application_cable/connection.rb'
41
+ "application_cable/channel.rb",
42
+ "application_cable/connection.rb"
38
43
  ]
39
44
 
40
45
  files.each do |name|
41
- path = File.join('app/channels/', name)
46
+ path = File.join("app/channels/", name)
42
47
  template(name, path) if !File.exist?(path)
43
48
  end
44
49
  end
@@ -1,13 +1,15 @@
1
- App.<%= class_name.underscore %> = App.cable.subscriptions.create("<%= class_name %>Channel", {
2
- connected: function() {
1
+ import consumer from "./consumer"
2
+
3
+ consumer.subscriptions.create("<%= class_name %>Channel", {
4
+ connected() {
3
5
  // Called when the subscription is ready for use on the server
4
6
  },
5
7
 
6
- disconnected: function() {
8
+ disconnected() {
7
9
  // Called when the subscription has been terminated by the server
8
10
  },
9
11
 
10
- received: function(data) {
12
+ received(data) {
11
13
  // Called when there's incoming data on the websocket for this channel
12
14
  }<%= actions.any? ? ",\n" : '' %>
13
15
  <% actions.each do |action| -%>
@@ -0,0 +1,6 @@
1
+ // Action Cable provides the framework to deal with WebSockets in Rails.
2
+ // You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.
3
+
4
+ import { createConsumer } from "@rails/actioncable"
5
+
6
+ export default createConsumer()
@@ -0,0 +1,5 @@
1
+ // Load all the channels within this directory and all subdirectories.
2
+ // Channel files must be named *_channel.js.
3
+
4
+ const channels = require.context('.', true, /_channel\.js$/)
5
+ channels.keys().forEach(channels)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestUnit
4
+ module Generators
5
+ class ChannelGenerator < ::Rails::Generators::NamedBase
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ check_class_collision suffix: "ChannelTest"
9
+
10
+ def create_test_files
11
+ template "channel_test.rb", File.join("test/channels", class_path, "#{file_name}_channel_test.rb")
12
+ end
13
+
14
+ private
15
+ def file_name # :doc:
16
+ @_file_name ||= super.sub(/_channel\z/i, "")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ require "test_helper"
2
+
3
+ class <%= class_name %>ChannelTest < ActionCable::Channel::TestCase
4
+ # test "subscribes" do
5
+ # subscribe
6
+ # assert subscription.confirmed?
7
+ # end
8
+ end
metadata CHANGED
@@ -1,72 +1,72 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actioncable
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.1
4
+ version: 6.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pratik Naik
8
8
  - David Heinemeier Hansson
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-12-21 00:00:00.000000000 Z
12
+ date: 2021-02-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: actionpack
15
+ name: activesupport
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
18
  - - '='
19
19
  - !ruby/object:Gem::Version
20
- version: 5.0.1
20
+ version: 6.1.3
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - '='
26
26
  - !ruby/object:Gem::Version
27
- version: 5.0.1
27
+ version: 6.1.3
28
28
  - !ruby/object:Gem::Dependency
29
- name: nio4r
29
+ name: actionpack
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - '='
33
33
  - !ruby/object:Gem::Version
34
- version: '1.2'
34
+ version: 6.1.3
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - '='
40
40
  - !ruby/object:Gem::Version
41
- version: '1.2'
41
+ version: 6.1.3
42
42
  - !ruby/object:Gem::Dependency
43
- name: websocket-driver
43
+ name: nio4r
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: 0.6.1
48
+ version: '2.0'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: 0.6.1
55
+ version: '2.0'
56
56
  - !ruby/object:Gem::Dependency
57
- name: blade
57
+ name: websocket-driver
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - "~>"
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: 0.5.1
63
- type: :development
62
+ version: 0.6.1
63
+ type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - "~>"
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 0.5.1
69
+ version: 0.6.1
70
70
  description: Structure many real-time application concerns into channels over a single
71
71
  WebSocket connection.
72
72
  email:
@@ -79,6 +79,7 @@ files:
79
79
  - CHANGELOG.md
80
80
  - MIT-LICENSE
81
81
  - README.md
82
+ - app/assets/javascripts/action_cable.js
82
83
  - lib/action_cable.rb
83
84
  - lib/action_cable/channel.rb
84
85
  - lib/action_cable/channel/base.rb
@@ -87,12 +88,11 @@ files:
87
88
  - lib/action_cable/channel/naming.rb
88
89
  - lib/action_cable/channel/periodic_timers.rb
89
90
  - lib/action_cable/channel/streams.rb
91
+ - lib/action_cable/channel/test_case.rb
90
92
  - lib/action_cable/connection.rb
91
93
  - lib/action_cable/connection/authorization.rb
92
94
  - lib/action_cable/connection/base.rb
93
95
  - lib/action_cable/connection/client_socket.rb
94
- - lib/action_cable/connection/faye_client_socket.rb
95
- - lib/action_cable/connection/faye_event_loop.rb
96
96
  - lib/action_cable/connection/identification.rb
97
97
  - lib/action_cable/connection/internal_channel.rb
98
98
  - lib/action_cable/connection/message_buffer.rb
@@ -100,6 +100,7 @@ files:
100
100
  - lib/action_cable/connection/stream_event_loop.rb
101
101
  - lib/action_cable/connection/subscriptions.rb
102
102
  - lib/action_cable/connection/tagged_logger_proxy.rb
103
+ - lib/action_cable/connection/test_case.rb
103
104
  - lib/action_cable/connection/web_socket.rb
104
105
  - lib/action_cable/engine.rb
105
106
  - lib/action_cable/gem_version.rb
@@ -115,26 +116,35 @@ files:
115
116
  - lib/action_cable/subscription_adapter.rb
116
117
  - lib/action_cable/subscription_adapter/async.rb
117
118
  - lib/action_cable/subscription_adapter/base.rb
118
- - lib/action_cable/subscription_adapter/evented_redis.rb
119
+ - lib/action_cable/subscription_adapter/channel_prefix.rb
119
120
  - lib/action_cable/subscription_adapter/inline.rb
120
121
  - lib/action_cable/subscription_adapter/postgresql.rb
121
122
  - lib/action_cable/subscription_adapter/redis.rb
122
123
  - lib/action_cable/subscription_adapter/subscriber_map.rb
124
+ - lib/action_cable/subscription_adapter/test.rb
125
+ - lib/action_cable/test_case.rb
126
+ - lib/action_cable/test_helper.rb
123
127
  - lib/action_cable/version.rb
124
- - lib/assets/compiled/action_cable.js
125
128
  - lib/rails/generators/channel/USAGE
126
129
  - lib/rails/generators/channel/channel_generator.rb
127
- - lib/rails/generators/channel/templates/application_cable/channel.rb
128
- - lib/rails/generators/channel/templates/application_cable/connection.rb
129
- - lib/rails/generators/channel/templates/assets/cable.js
130
- - lib/rails/generators/channel/templates/assets/channel.coffee
131
- - lib/rails/generators/channel/templates/assets/channel.js
132
- - lib/rails/generators/channel/templates/channel.rb
133
- homepage: http://rubyonrails.org
130
+ - lib/rails/generators/channel/templates/application_cable/channel.rb.tt
131
+ - lib/rails/generators/channel/templates/application_cable/connection.rb.tt
132
+ - lib/rails/generators/channel/templates/channel.rb.tt
133
+ - lib/rails/generators/channel/templates/javascript/channel.js.tt
134
+ - lib/rails/generators/channel/templates/javascript/consumer.js.tt
135
+ - lib/rails/generators/channel/templates/javascript/index.js.tt
136
+ - lib/rails/generators/test_unit/channel_generator.rb
137
+ - lib/rails/generators/test_unit/templates/channel_test.rb.tt
138
+ homepage: https://rubyonrails.org
134
139
  licenses:
135
140
  - MIT
136
- metadata: {}
137
- post_install_message:
141
+ metadata:
142
+ bug_tracker_uri: https://github.com/rails/rails/issues
143
+ changelog_uri: https://github.com/rails/rails/blob/v6.1.3/actioncable/CHANGELOG.md
144
+ documentation_uri: https://api.rubyonrails.org/v6.1.3/
145
+ mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
146
+ source_code_uri: https://github.com/rails/rails/tree/v6.1.3/actioncable
147
+ post_install_message:
138
148
  rdoc_options: []
139
149
  require_paths:
140
150
  - lib
@@ -142,17 +152,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
142
152
  requirements:
143
153
  - - ">="
144
154
  - !ruby/object:Gem::Version
145
- version: 2.2.2
155
+ version: 2.5.0
146
156
  required_rubygems_version: !ruby/object:Gem::Requirement
147
157
  requirements:
148
158
  - - ">="
149
159
  - !ruby/object:Gem::Version
150
160
  version: '0'
151
161
  requirements: []
152
- rubyforge_project:
153
- rubygems_version: 2.5.2
154
- signing_key:
162
+ rubygems_version: 3.2.3
163
+ signing_key:
155
164
  specification_version: 4
156
165
  summary: WebSocket framework for Rails.
157
166
  test_files: []
158
- has_rdoc: