diff options
Diffstat (limited to 'actioncable')
18 files changed, 101 insertions, 167 deletions
diff --git a/actioncable/CHANGELOG.md b/actioncable/CHANGELOG.md index 42edbd6954..6fc2f17d32 100644 --- a/actioncable/CHANGELOG.md +++ b/actioncable/CHANGELOG.md @@ -1,118 +1,3 @@ -* Add `:action_cable_connection` and `:action_cable_channel` load hooks. - You can use them to extend `ActionCable::Connection::Base` and `ActionCable::Channel::Base` - functionality: - ```ruby - ActiveSupport.on_load(:action_cable_channel) do - # do something in the context of ActionCable::Channel::Base - end - ``` - - *Vladimir Dementyev* - -* Add `Channel::Base#broadcast_to`. - - You can now call `broadcast_to` within a channel action, which equals to - the `self.class.broadcast_to`. - - *Vladimir Dementyev* - -* Make `Channel::Base.broadcasting_for` a public API. - - You can use `.broadcasting_for` to generate a unique stream identifier within - a channel for the specified target (e.g. Active Record model): - - ```ruby - ChatChannel.broadcasting_for(model) # => "chat:<model.to_gid_param>" - ``` - - *Vladimir Dementyev* - - -## Rails 6.0.0.beta1 (January 18, 2019) ## - -* [Rename npm package](https://github.com/rails/rails/pull/34905) from - [`actioncable`](https://www.npmjs.com/package/actioncable) to - [`@rails/actioncable`](https://www.npmjs.com/package/@rails/actioncable). - - *Javan Makhmali* - -* Merge [`action-cable-testing`](https://github.com/palkan/action-cable-testing) to Rails. - - *Vladimir Dementyev* - -* The JavaScript WebSocket client will no longer try to reconnect - when you call `reject_unauthorized_connection` on the connection. - - *Mick Staugaard* - -* `ActionCable.Connection#getState` now references the configurable - `ActionCable.adapters.WebSocket` property rather than the `WebSocket` global - variable, matching the behavior of `ActionCable.Connection#open`. - - *Richard Macklin* - -* The ActionCable javascript package has been converted from CoffeeScript - to ES2015, and we now publish the source code in the npm distribution. - - This allows ActionCable users to depend on the javascript source code - rather than the compiled code, which can produce smaller javascript bundles. - - This change includes some breaking changes to optional parts of the - ActionCable javascript API: - - - Configuration of the WebSocket adapter and logger adapter have been moved - from properties of `ActionCable` to properties of `ActionCable.adapters`. - If you are currently configuring these adapters you will need to make - these changes when upgrading: - - ```diff - - ActionCable.WebSocket = MyWebSocket - + ActionCable.adapters.WebSocket = MyWebSocket - ``` - ```diff - - ActionCable.logger = myLogger - + ActionCable.adapters.logger = myLogger - ``` - - - The `ActionCable.startDebugging()` and `ActionCable.stopDebugging()` - methods have been removed and replaced with the property - `ActionCable.logger.enabled`. If you are currently using these methods you - will need to make these changes when upgrading: - - ```diff - - ActionCable.startDebugging() - + ActionCable.logger.enabled = true - ``` - ```diff - - ActionCable.stopDebugging() - + ActionCable.logger.enabled = false - ``` - - *Richard Macklin* - -* Add `id` option to redis adapter so now you can distinguish - ActionCable's redis connections among others. Also, you can set - custom id in options. - - Before: - ``` - $ redis-cli client list - id=669 addr=127.0.0.1:46442 fd=8 name= age=18 ... - ``` - - After: - ``` - $ redis-cli client list - id=673 addr=127.0.0.1:46516 fd=8 name=ActionCable-PID-19413 age=2 ... - ``` - - *Ilia Kasianenko* - -* Rails 6 requires Ruby 2.5.0 or newer. - - *Jeremy Daer*, *Kasper Timm Hansen* - - -Please check [5-2-stable](https://github.com/rails/rails/blob/5-2-stable/actioncable/CHANGELOG.md) for previous changes. +Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/actioncable/CHANGELOG.md) for previous changes. diff --git a/actioncable/README.md b/actioncable/README.md index 60c879e1f4..38eb251f42 100644 --- a/actioncable/README.md +++ b/actioncable/README.md @@ -13,7 +13,7 @@ You can read more about Action Cable in the [Action Cable Overview](https://edge API documentation is at: -* http://api.rubyonrails.org +* https://api.rubyonrails.org Bug reports for the Ruby on Rails project can be filed here: diff --git a/actioncable/actioncable.gemspec b/actioncable/actioncable.gemspec index 29836f012f..7aefb67c51 100644 --- a/actioncable/actioncable.gemspec +++ b/actioncable/actioncable.gemspec @@ -15,7 +15,7 @@ Gem::Specification.new do |s| s.author = ["Pratik Naik", "David Heinemeier Hansson"] s.email = ["pratiknaik@gmail.com", "david@loudthinking.com"] - s.homepage = "http://rubyonrails.org" + s.homepage = "https://rubyonrails.org" s.files = Dir["CHANGELOG.md", "MIT-LICENSE", "README.md", "lib/**/*", "app/assets/javascripts/action_cable.js"] s.require_path = "lib" diff --git a/actioncable/app/assets/javascripts/action_cable.js b/actioncable/app/assets/javascripts/action_cable.js index 280adbfa83..8349361405 100644 --- a/actioncable/app/assets/javascripts/action_cable.js +++ b/actioncable/app/assets/javascripts/action_cable.js @@ -28,6 +28,22 @@ throw new TypeError("Cannot call a class as a function"); } }; + var createClass = function() { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + return function(Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); var now = function now() { return new Date().getTime(); }; @@ -432,7 +448,7 @@ var Consumer = function() { function Consumer(url) { classCallCheck(this, Consumer); - this.url = url; + this._url = url; this.subscriptions = new Subscriptions(this); this.connection = new Connection(this); } @@ -452,19 +468,18 @@ return this.connection.open(); } }; + createClass(Consumer, [ { + key: "url", + get: function get$$1() { + return createWebSocketURL(this._url); + } + } ]); return Consumer; }(); - function createConsumer() { - var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getConfig("url") || INTERNAL.default_mount_path; - return new Consumer(createWebSocketURL(url)); - } - function getConfig(name) { - var element = document.head.querySelector("meta[name='action-cable-" + name + "']"); - if (element) { - return element.getAttribute("content"); - } - } function createWebSocketURL(url) { + if (typeof url === "function") { + url = url(); + } if (url && !/^wss?:/i.test(url)) { var a = document.createElement("a"); a.href = url; @@ -475,6 +490,16 @@ return url; } } + function createConsumer() { + var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getConfig("url") || INTERNAL.default_mount_path; + return new Consumer(url); + } + function getConfig(name) { + var element = document.head.querySelector("meta[name='action-cable-" + name + "']"); + if (element) { + return element.getAttribute("content"); + } + } exports.Connection = Connection; exports.ConnectionMonitor = ConnectionMonitor; exports.Consumer = Consumer; @@ -482,10 +507,10 @@ exports.Subscription = Subscription; exports.Subscriptions = Subscriptions; exports.adapters = adapters; + exports.createWebSocketURL = createWebSocketURL; exports.logger = logger; exports.createConsumer = createConsumer; exports.getConfig = getConfig; - exports.createWebSocketURL = createWebSocketURL; Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/actioncable/app/javascript/action_cable/consumer.js b/actioncable/app/javascript/action_cable/consumer.js index e8440f39f5..e2e0dea8b5 100644 --- a/actioncable/app/javascript/action_cable/consumer.js +++ b/actioncable/app/javascript/action_cable/consumer.js @@ -29,11 +29,15 @@ import Subscriptions from "./subscriptions" export default class Consumer { constructor(url) { - this.url = url + this._url = url this.subscriptions = new Subscriptions(this) this.connection = new Connection(this) } + get url() { + return createWebSocketURL(this._url) + } + send(data) { return this.connection.send(data) } @@ -52,3 +56,20 @@ export default class Consumer { } } } + +export function createWebSocketURL(url) { + if (typeof url === "function") { + url = url() + } + + if (url && !/^wss?:/i.test(url)) { + const a = document.createElement("a") + a.href = url + // Fix populating Location properties in IE. Otherwise, protocol will be blank. + a.href = a.href + a.protocol = a.protocol.replace("http", "ws") + return a.href + } else { + return url + } +} diff --git a/actioncable/app/javascript/action_cable/index.js b/actioncable/app/javascript/action_cable/index.js index 659418396f..848b5631d6 100644 --- a/actioncable/app/javascript/action_cable/index.js +++ b/actioncable/app/javascript/action_cable/index.js @@ -1,6 +1,6 @@ import Connection from "./connection" import ConnectionMonitor from "./connection_monitor" -import Consumer from "./consumer" +import Consumer, { createWebSocketURL } from "./consumer" import INTERNAL from "./internal" import Subscription from "./subscription" import Subscriptions from "./subscriptions" @@ -15,11 +15,12 @@ export { Subscription, Subscriptions, adapters, + createWebSocketURL, logger, } export function createConsumer(url = getConfig("url") || INTERNAL.default_mount_path) { - return new Consumer(createWebSocketURL(url)) + return new Consumer(url) } export function getConfig(name) { @@ -28,16 +29,3 @@ export function getConfig(name) { return element.getAttribute("content") } } - -export function createWebSocketURL(url) { - if (url && !/^wss?:/i.test(url)) { - const a = document.createElement("a") - a.href = url - // Fix populating Location properties in IE. Otherwise, protocol will be blank. - a.href = a.href - a.protocol = a.protocol.replace("http", "ws") - return a.href - } else { - return url - } -} diff --git a/actioncable/karma.conf.js b/actioncable/karma.conf.js index 845b38d74f..83e9c98af1 100644 --- a/actioncable/karma.conf.js +++ b/actioncable/karma.conf.js @@ -52,9 +52,9 @@ if (process.env.CI) { } function buildId() { - const { TRAVIS_BUILD_NUMBER, TRAVIS_BUILD_ID } = process.env - return TRAVIS_BUILD_NUMBER && TRAVIS_BUILD_ID - ? `TRAVIS #${TRAVIS_BUILD_NUMBER} (${TRAVIS_BUILD_ID})` + const { BUILDKITE_JOB_ID } = process.env + return BUILDKITE_JOB_ID + ? `Buildkite ${BUILDKITE_JOB_ID}` : "" } } diff --git a/actioncable/lib/action_cable/connection/test_case.rb b/actioncable/lib/action_cable/connection/test_case.rb index 8d25a55c8a..f1673fea08 100644 --- a/actioncable/lib/action_cable/connection/test_case.rb +++ b/actioncable/lib/action_cable/connection/test_case.rb @@ -176,7 +176,7 @@ module ActionCable # # Accepts request path as the first argument and the following request options: # - # - params – url parameters (Hash) + # - params – URL parameters (Hash) # - headers – request headers (Hash) # - session – session data (Hash) # - env – additional Rack env configuration (Hash) diff --git a/actioncable/lib/action_cable/gem_version.rb b/actioncable/lib/action_cable/gem_version.rb index 5082827417..6e7053e32e 100644 --- a/actioncable/lib/action_cable/gem_version.rb +++ b/actioncable/lib/action_cable/gem_version.rb @@ -8,9 +8,9 @@ module ActionCable module VERSION MAJOR = 6 - MINOR = 0 + MINOR = 1 TINY = 0 - PRE = "beta1" + PRE = "alpha" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/actioncable/lib/action_cable/server/base.rb b/actioncable/lib/action_cable/server/base.rb index 2b9e1cba3b..98b3743175 100644 --- a/actioncable/lib/action_cable/server/base.rb +++ b/actioncable/lib/action_cable/server/base.rb @@ -12,14 +12,17 @@ module ActionCable include ActionCable::Server::Broadcasting include ActionCable::Server::Connections - cattr_accessor :config, instance_accessor: true, default: ActionCable::Server::Configuration.new + cattr_accessor :config, instance_accessor: false, default: ActionCable::Server::Configuration.new + + attr_reader :config def self.logger; config.logger; end delegate :logger, to: :config attr_reader :mutex - def initialize + def initialize(config: self.class.config) + @config = config @mutex = Monitor.new @remote_connections = @event_loop = @worker_pool = @pubsub = nil end diff --git a/actioncable/lib/action_cable/subscription_adapter/postgresql.rb b/actioncable/lib/action_cable/subscription_adapter/postgresql.rb index 50ec438c3a..1d60bed4af 100644 --- a/actioncable/lib/action_cable/subscription_adapter/postgresql.rb +++ b/actioncable/lib/action_cable/subscription_adapter/postgresql.rb @@ -8,6 +8,8 @@ require "digest/sha1" module ActionCable module SubscriptionAdapter class PostgreSQL < Base # :nodoc: + prepend ChannelPrefix + def initialize(*) super @listener = nil diff --git a/actioncable/lib/action_cable/subscription_adapter/redis.rb b/actioncable/lib/action_cable/subscription_adapter/redis.rb index ad8fa52760..b4a9385c87 100644 --- a/actioncable/lib/action_cable/subscription_adapter/redis.rb +++ b/actioncable/lib/action_cable/subscription_adapter/redis.rb @@ -5,6 +5,8 @@ require "thread" gem "redis", ">= 3", "< 5" require "redis" +require "active_support/core_ext/hash/except" + module ActionCable module SubscriptionAdapter class Redis < Base # :nodoc: @@ -14,7 +16,7 @@ module ActionCable # This is needed, for example, when using Makara proxies for distributed Redis. cattr_accessor :redis_connector, default: ->(config) do config[:id] ||= "ActionCable-PID-#{$$}" - ::Redis.new(config.slice(:url, :host, :port, :db, :password, :id)) + ::Redis.new(config.except(:adapter, :channel_prefix)) end def initialize(*) diff --git a/actioncable/package.json b/actioncable/package.json index 801fcc0c22..723aa63c81 100644 --- a/actioncable/package.json +++ b/actioncable/package.json @@ -1,6 +1,6 @@ { "name": "@rails/actioncable", - "version": "6.0.0-beta1", + "version": "6.1.0-alpha", "description": "WebSocket framework for Ruby on Rails.", "main": "app/assets/javascripts/action_cable.js", "files": [ diff --git a/actioncable/test/javascript/src/unit/action_cable_test.js b/actioncable/test/javascript/src/unit/action_cable_test.js index 83426fa32e..c46f9878d2 100644 --- a/actioncable/test/javascript/src/unit/action_cable_test.js +++ b/actioncable/test/javascript/src/unit/action_cable_test.js @@ -41,5 +41,17 @@ module("ActionCable", () => { assert.equal(consumer.url, testURL) }) + + test("dynamically computes URL from function", assert => { + let dynamicURL = testURL + const generateURL = () => { + return dynamicURL + } + const consumer = ActionCable.createConsumer(generateURL) + assert.equal(consumer.url, testURL) + + dynamicURL = `${testURL}foo` + assert.equal(consumer.url, `${testURL}foo`) + }) }) }) diff --git a/actioncable/test/subscription_adapter/channel_prefix.rb b/actioncable/test/subscription_adapter/channel_prefix.rb index 3071facd9d..475e6cfd3a 100644 --- a/actioncable/test/subscription_adapter/channel_prefix.rb +++ b/actioncable/test/subscription_adapter/channel_prefix.rb @@ -2,17 +2,9 @@ require "test_helper" -class ActionCable::Server::WithIndependentConfig < ActionCable::Server::Base - # ActionCable::Server::Base defines config as a class variable. - # Need config to be an instance variable here as we're testing 2 separate configs - def config - @config ||= ActionCable::Server::Configuration.new - end -end - module ChannelPrefixTest def test_channel_prefix - server2 = ActionCable::Server::WithIndependentConfig.new + server2 = ActionCable::Server::Base.new(config: ActionCable::Server::Configuration.new) server2.config.cable = alt_cable_config server2.config.logger = Logger.new(StringIO.new).tap { |l| l.level = Logger::UNKNOWN } diff --git a/actioncable/test/subscription_adapter/postgresql_test.rb b/actioncable/test/subscription_adapter/postgresql_test.rb index 5fb26a8896..4348eb1b1e 100644 --- a/actioncable/test/subscription_adapter/postgresql_test.rb +++ b/actioncable/test/subscription_adapter/postgresql_test.rb @@ -2,11 +2,13 @@ require "test_helper" require_relative "common" +require_relative "channel_prefix" require "active_record" class PostgresqlAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest + include ChannelPrefixTest def setup database_config = { "adapter" => "postgresql", "database" => "activerecord_unittest" } diff --git a/actioncable/test/subscription_adapter/redis_test.rb b/actioncable/test/subscription_adapter/redis_test.rb index 35840a4036..d4eb89719f 100644 --- a/actioncable/test/subscription_adapter/redis_test.rb +++ b/actioncable/test/subscription_adapter/redis_test.rb @@ -34,11 +34,11 @@ class RedisAdapterTest::AlternateConfiguration < RedisAdapterTest end class RedisAdapterTest::Connector < ActionCable::TestCase - test "slices url, host, port, db, password and id from config" do + test "excludes adapter and channel prefix" do config = { url: 1, host: 2, port: 3, db: 4, password: 5, id: "Some custom ID" } assert_called_with ::Redis, :new, [ config ] do - connect config.merge(other: "unrelated", stuff: "here") + connect config.merge(adapter: "redis", channel_prefix: "custom") end end diff --git a/actioncable/test/test_helper.rb b/actioncable/test/test_helper.rb index c924f1e475..033f034b0c 100644 --- a/actioncable/test/test_helper.rb +++ b/actioncable/test/test_helper.rb @@ -41,3 +41,5 @@ class ActionCable::TestCase < ActiveSupport::TestCase end end end + +require_relative "../../tools/test_common" |