mirror of https://github.com/rails/rails
feat(js): Dynamic ActionCable URL (#35579)
* Failing test case * feat: Dynamic Url Generation Change createWebSocketURL to be a closure that allows url to be evaluated at the time the webSocket is established * refactor: createWebSocketURL to Consumer, remove need for closure Move initial call to createWebSocketURL in createConsumer * docs: Add documentation for dynamic url and string args to createConsumer Co-Authored-By: rmacklin <rmacklin@users.noreply.github.com> [Ryan Castner, rmacklin]
This commit is contained in:
parent
ba4e74e1b7
commit
6d488a22d3
|
@ -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,18 +468,14 @@
|
|||
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) {
|
||||
var webSocketURL = typeof url === "function" ? url() : url;
|
||||
if (webSocketURL && !/^wss?:/i.test(webSocketURL)) {
|
||||
|
@ -476,6 +488,16 @@
|
|||
return webSocketURL;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -484,9 +506,9 @@
|
|||
exports.Subscriptions = Subscriptions;
|
||||
exports.adapters = adapters;
|
||||
exports.logger = logger;
|
||||
exports.createWebSocketURL = createWebSocketURL;
|
||||
exports.createConsumer = createConsumer;
|
||||
exports.getConfig = getConfig;
|
||||
exports.createWebSocketURL = createWebSocketURL;
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
|
|
@ -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,18 @@ export default class Consumer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createWebSocketURL(url) {
|
||||
const webSocketURL = typeof url === "function" ? url() : url
|
||||
|
||||
if (webSocketURL && !/^wss?:/i.test(webSocketURL)) {
|
||||
const a = document.createElement("a")
|
||||
a.href = webSocketURL
|
||||
// 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 webSocketURL
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
@ -16,10 +16,11 @@ export {
|
|||
Subscriptions,
|
||||
adapters,
|
||||
logger,
|
||||
createWebSocketURL,
|
||||
}
|
||||
|
||||
export function createConsumer(url = getConfig("url") || INTERNAL.default_mount_path) {
|
||||
return new Consumer(createWebSocketURL(url))
|
||||
return new Consumer(url)
|
||||
}
|
||||
|
||||
export function getConfig(name) {
|
||||
|
@ -28,18 +29,3 @@ export function getConfig(name) {
|
|||
return element.getAttribute("content")
|
||||
}
|
||||
}
|
||||
|
||||
export function createWebSocketURL(url) {
|
||||
const webSocketURL = typeof url === "function" ? url() : url
|
||||
|
||||
if (webSocketURL && !/^wss?:/i.test(webSocketURL)) {
|
||||
const a = document.createElement("a")
|
||||
a.href = webSocketURL
|
||||
// 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 webSocketURL
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,11 +43,14 @@ module("ActionCable", () => {
|
|||
})
|
||||
|
||||
test("uses function to generate URL", assert => {
|
||||
let dynamicURL = testURL
|
||||
const generateURL = () => {
|
||||
return testURL
|
||||
return dynamicURL
|
||||
}
|
||||
|
||||
dynamicURL = `${testURL}foo`
|
||||
const consumer = ActionCable.createConsumer(generateURL)
|
||||
assert.equal(consumer.url, testURL)
|
||||
assert.equal(consumer.url, `${testURL}foo`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -190,6 +190,23 @@ This will ready a consumer that'll connect against `/cable` on your server by de
|
|||
The connection won't be established until you've also specified at least one subscription
|
||||
you're interested in having.
|
||||
|
||||
The consumer can optionally take an argument that specifies the url to connect to. This
|
||||
can be a string, or a function that returns a string that will be called when the
|
||||
WebSocket is opened.
|
||||
|
||||
```js
|
||||
// Specify a different url to connect to
|
||||
createConsumer('https://ws.example.com/cable')
|
||||
|
||||
// Use a function to dynamically generate the url
|
||||
createConsumer(getWebSocketURL)
|
||||
|
||||
function getWebSocketURL {
|
||||
const token = localStorage.get('auth-token')
|
||||
return `https://ws.example.com/cable?token=${token}`
|
||||
}
|
||||
```
|
||||
|
||||
#### Subscriber
|
||||
|
||||
A consumer becomes a subscriber by creating a subscription to a given channel:
|
||||
|
|
Loading…
Reference in New Issue