actioncable 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +169 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +24 -0
  5. data/app/assets/javascripts/action_cable.js +517 -0
  6. data/lib/action_cable.rb +62 -0
  7. data/lib/action_cable/channel.rb +17 -0
  8. data/lib/action_cable/channel/base.rb +311 -0
  9. data/lib/action_cable/channel/broadcasting.rb +41 -0
  10. data/lib/action_cable/channel/callbacks.rb +37 -0
  11. data/lib/action_cable/channel/naming.rb +25 -0
  12. data/lib/action_cable/channel/periodic_timers.rb +78 -0
  13. data/lib/action_cable/channel/streams.rb +176 -0
  14. data/lib/action_cable/channel/test_case.rb +310 -0
  15. data/lib/action_cable/connection.rb +22 -0
  16. data/lib/action_cable/connection/authorization.rb +15 -0
  17. data/lib/action_cable/connection/base.rb +264 -0
  18. data/lib/action_cable/connection/client_socket.rb +157 -0
  19. data/lib/action_cable/connection/identification.rb +47 -0
  20. data/lib/action_cable/connection/internal_channel.rb +45 -0
  21. data/lib/action_cable/connection/message_buffer.rb +54 -0
  22. data/lib/action_cable/connection/stream.rb +117 -0
  23. data/lib/action_cable/connection/stream_event_loop.rb +136 -0
  24. data/lib/action_cable/connection/subscriptions.rb +79 -0
  25. data/lib/action_cable/connection/tagged_logger_proxy.rb +42 -0
  26. data/lib/action_cable/connection/test_case.rb +234 -0
  27. data/lib/action_cable/connection/web_socket.rb +41 -0
  28. data/lib/action_cable/engine.rb +79 -0
  29. data/lib/action_cable/gem_version.rb +17 -0
  30. data/lib/action_cable/helpers/action_cable_helper.rb +42 -0
  31. data/lib/action_cable/remote_connections.rb +71 -0
  32. data/lib/action_cable/server.rb +17 -0
  33. data/lib/action_cable/server/base.rb +94 -0
  34. data/lib/action_cable/server/broadcasting.rb +54 -0
  35. data/lib/action_cable/server/configuration.rb +56 -0
  36. data/lib/action_cable/server/connections.rb +36 -0
  37. data/lib/action_cable/server/worker.rb +75 -0
  38. data/lib/action_cable/server/worker/active_record_connection_management.rb +21 -0
  39. data/lib/action_cable/subscription_adapter.rb +12 -0
  40. data/lib/action_cable/subscription_adapter/async.rb +29 -0
  41. data/lib/action_cable/subscription_adapter/base.rb +30 -0
  42. data/lib/action_cable/subscription_adapter/channel_prefix.rb +28 -0
  43. data/lib/action_cable/subscription_adapter/inline.rb +37 -0
  44. data/lib/action_cable/subscription_adapter/postgresql.rb +132 -0
  45. data/lib/action_cable/subscription_adapter/redis.rb +181 -0
  46. data/lib/action_cable/subscription_adapter/subscriber_map.rb +59 -0
  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 +10 -0
  51. data/lib/rails/generators/channel/USAGE +13 -0
  52. data/lib/rails/generators/channel/channel_generator.rb +52 -0
  53. data/lib/rails/generators/channel/templates/application_cable/channel.rb.tt +4 -0
  54. data/lib/rails/generators/channel/templates/application_cable/connection.rb.tt +4 -0
  55. data/lib/rails/generators/channel/templates/channel.rb.tt +16 -0
  56. data/lib/rails/generators/channel/templates/javascript/channel.js.tt +20 -0
  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 +149 -0
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "async"
4
+
5
+ module ActionCable
6
+ module SubscriptionAdapter
7
+ # == Test adapter for Action Cable
8
+ #
9
+ # The test adapter should be used only in testing. Along with
10
+ # <tt>ActionCable::TestHelper</tt> it makes a great tool to test your Rails application.
11
+ #
12
+ # To use the test adapter set +adapter+ value to +test+ in your +config/cable.yml+ file.
13
+ #
14
+ # NOTE: Test adapter extends the <tt>ActionCable::SubscriptionsAdapter::Async</tt> adapter,
15
+ # so it could be used in system tests too.
16
+ class Test < Async
17
+ def broadcast(channel, payload)
18
+ broadcasts(channel) << payload
19
+ super
20
+ end
21
+
22
+ def broadcasts(channel)
23
+ channels_data[channel] ||= []
24
+ end
25
+
26
+ def clear_messages(channel)
27
+ channels_data[channel] = []
28
+ end
29
+
30
+ def clear
31
+ @channels_data = nil
32
+ end
33
+
34
+ private
35
+ def channels_data
36
+ @channels_data ||= {}
37
+ end
38
+ end
39
+ end
40
+ end
@@ -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)
46
+ if block_given?
47
+ original_count = broadcasts_size(stream)
48
+ yield
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)
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
+ yield
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
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "gem_version"
4
+
5
+ module ActionCable
6
+ # Returns the version of the currently loaded Action Cable as a <tt>Gem::Version</tt>
7
+ def self.version
8
+ gem_version
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ Description:
2
+ ============
3
+ Stubs out a new cable channel for the server (in Ruby) and client (in JavaScript).
4
+ Pass the channel name, either CamelCased or under_scored, and an optional list of channel actions as arguments.
5
+
6
+ Example:
7
+ ========
8
+ rails generate channel Chat speak
9
+
10
+ creates a Chat channel class, test and JavaScript asset:
11
+ Channel: app/channels/chat_channel.rb
12
+ Test: test/channels/chat_channel_test.rb
13
+ Assets: app/javascript/channels/chat_channel.js
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module Generators
5
+ class ChannelGenerator < NamedBase
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ argument :actions, type: :array, default: [], banner: "method method"
9
+
10
+ class_option :assets, type: :boolean
11
+
12
+ check_class_collision suffix: "Channel"
13
+
14
+ hook_for :test_framework
15
+
16
+ def create_channel_file
17
+ template "channel.rb", File.join("app/channels", class_path, "#{file_name}_channel.rb")
18
+
19
+ if options[:assets]
20
+ if behavior == :invoke
21
+ template "javascript/index.js", "app/javascript/channels/index.js"
22
+ template "javascript/consumer.js", "app/javascript/channels/consumer.js"
23
+ end
24
+
25
+ js_template "javascript/channel", File.join("app/javascript/channels", class_path, "#{file_name}_channel")
26
+ end
27
+
28
+ generate_application_cable_files
29
+ end
30
+
31
+ private
32
+ def file_name
33
+ @_file_name ||= super.sub(/_channel\z/i, "")
34
+ end
35
+
36
+ # FIXME: Change these files to symlinks once RubyGems 2.5.0 is required.
37
+ def generate_application_cable_files
38
+ return if behavior != :invoke
39
+
40
+ files = [
41
+ "application_cable/channel.rb",
42
+ "application_cable/connection.rb"
43
+ ]
44
+
45
+ files.each do |name|
46
+ path = File.join("app/channels/", name)
47
+ template(name, path) if !File.exist?(path)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -0,0 +1,16 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Channel < ApplicationCable::Channel
3
+ def subscribed
4
+ # stream_from "some_channel"
5
+ end
6
+
7
+ def unsubscribed
8
+ # Any cleanup needed when channel is unsubscribed
9
+ end
10
+ <% actions.each do |action| -%>
11
+
12
+ def <%= action %>
13
+ end
14
+ <% end -%>
15
+ end
16
+ <% end -%>
@@ -0,0 +1,20 @@
1
+ import consumer from "./consumer"
2
+
3
+ consumer.subscriptions.create("<%= class_name %>Channel", {
4
+ connected() {
5
+ // Called when the subscription is ready for use on the server
6
+ },
7
+
8
+ disconnected() {
9
+ // Called when the subscription has been terminated by the server
10
+ },
11
+
12
+ received(data) {
13
+ // Called when there's incoming data on the websocket for this channel
14
+ }<%= actions.any? ? ",\n" : '' %>
15
+ <% actions.each do |action| -%>
16
+ <%=action %>: function() {
17
+ return this.perform('<%= action %>');
18
+ }<%= action == actions[-1] ? '' : ",\n" %>
19
+ <% end -%>
20
+ });
@@ -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 `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 ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: actioncable
3
+ version: !ruby/object:Gem::Version
4
+ version: 6.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Pratik Naik
8
+ - David Heinemeier Hansson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-08-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: actionpack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 6.0.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 6.0.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: nio4r
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '2.0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '2.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: websocket-driver
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 0.6.1
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: 0.6.1
56
+ description: Structure many real-time application concerns into channels over a single
57
+ WebSocket connection.
58
+ email:
59
+ - pratiknaik@gmail.com
60
+ - david@loudthinking.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - CHANGELOG.md
66
+ - MIT-LICENSE
67
+ - README.md
68
+ - app/assets/javascripts/action_cable.js
69
+ - lib/action_cable.rb
70
+ - lib/action_cable/channel.rb
71
+ - lib/action_cable/channel/base.rb
72
+ - lib/action_cable/channel/broadcasting.rb
73
+ - lib/action_cable/channel/callbacks.rb
74
+ - lib/action_cable/channel/naming.rb
75
+ - lib/action_cable/channel/periodic_timers.rb
76
+ - lib/action_cable/channel/streams.rb
77
+ - lib/action_cable/channel/test_case.rb
78
+ - lib/action_cable/connection.rb
79
+ - lib/action_cable/connection/authorization.rb
80
+ - lib/action_cable/connection/base.rb
81
+ - lib/action_cable/connection/client_socket.rb
82
+ - lib/action_cable/connection/identification.rb
83
+ - lib/action_cable/connection/internal_channel.rb
84
+ - lib/action_cable/connection/message_buffer.rb
85
+ - lib/action_cable/connection/stream.rb
86
+ - lib/action_cable/connection/stream_event_loop.rb
87
+ - lib/action_cable/connection/subscriptions.rb
88
+ - lib/action_cable/connection/tagged_logger_proxy.rb
89
+ - lib/action_cable/connection/test_case.rb
90
+ - lib/action_cable/connection/web_socket.rb
91
+ - lib/action_cable/engine.rb
92
+ - lib/action_cable/gem_version.rb
93
+ - lib/action_cable/helpers/action_cable_helper.rb
94
+ - lib/action_cable/remote_connections.rb
95
+ - lib/action_cable/server.rb
96
+ - lib/action_cable/server/base.rb
97
+ - lib/action_cable/server/broadcasting.rb
98
+ - lib/action_cable/server/configuration.rb
99
+ - lib/action_cable/server/connections.rb
100
+ - lib/action_cable/server/worker.rb
101
+ - lib/action_cable/server/worker/active_record_connection_management.rb
102
+ - lib/action_cable/subscription_adapter.rb
103
+ - lib/action_cable/subscription_adapter/async.rb
104
+ - lib/action_cable/subscription_adapter/base.rb
105
+ - lib/action_cable/subscription_adapter/channel_prefix.rb
106
+ - lib/action_cable/subscription_adapter/inline.rb
107
+ - lib/action_cable/subscription_adapter/postgresql.rb
108
+ - lib/action_cable/subscription_adapter/redis.rb
109
+ - lib/action_cable/subscription_adapter/subscriber_map.rb
110
+ - lib/action_cable/subscription_adapter/test.rb
111
+ - lib/action_cable/test_case.rb
112
+ - lib/action_cable/test_helper.rb
113
+ - lib/action_cable/version.rb
114
+ - lib/rails/generators/channel/USAGE
115
+ - lib/rails/generators/channel/channel_generator.rb
116
+ - lib/rails/generators/channel/templates/application_cable/channel.rb.tt
117
+ - lib/rails/generators/channel/templates/application_cable/connection.rb.tt
118
+ - lib/rails/generators/channel/templates/channel.rb.tt
119
+ - lib/rails/generators/channel/templates/javascript/channel.js.tt
120
+ - lib/rails/generators/channel/templates/javascript/consumer.js.tt
121
+ - lib/rails/generators/channel/templates/javascript/index.js.tt
122
+ - lib/rails/generators/test_unit/channel_generator.rb
123
+ - lib/rails/generators/test_unit/templates/channel_test.rb.tt
124
+ homepage: https://rubyonrails.org
125
+ licenses:
126
+ - MIT
127
+ metadata:
128
+ source_code_uri: https://github.com/rails/rails/tree/v6.0.0/actioncable
129
+ changelog_uri: https://github.com/rails/rails/blob/v6.0.0/actioncable/CHANGELOG.md
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 2.5.0
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubygems_version: 3.0.1
146
+ signing_key:
147
+ specification_version: 4
148
+ summary: WebSocket framework for Rails.
149
+ test_files: []