actioncable
Advanced tools
Comparing version 5.0.0 to 5.0.1-rc1
@@ -0,1 +1,54 @@ | ||
## Rails 5.0.1.rc1 (December 01, 2016) ## | ||
* Permit same-origin connections by default. | ||
New option `config.action_cable.allow_same_origin_as_host = false` | ||
to disable. | ||
*Dávid Halász*, *Matthew Draper* | ||
* Fixed and added a workaround to avoid race condition, when one | ||
thread closed the IO, when an another thread was still trying read | ||
from IO on a connection. | ||
*Matthew Draper* | ||
* Shutdown pubsub connection before classes are reloaded, to avoid | ||
hangups caused by pubsub still holding reference to Active Record | ||
connection from the pool, and Active Record trying to cleanup the pool. | ||
*Jon Moss* | ||
* Prevent race where the client could receive and act upon a | ||
subscription confirmation before the channel's `subscribed` method | ||
completed. | ||
Fixes #25381. | ||
*Vladimir Dementyev* | ||
* Buffer writes to websocket connections, to avoid blocking threads | ||
that could be doing more useful things. | ||
*Matthew Draper*, *Tinco Andringa* | ||
* Invocation of channel action is now prevented, if subscription | ||
connection was rejected. | ||
Fixes #23757. | ||
*Jon Moss* | ||
* Protect against concurrent writes to a websocket connection from | ||
multiple threads; the underlying OS write is not always threadsafe. | ||
*Tinco Andringa* | ||
* Close hijacked socket when connection is shut down. | ||
Fixes #25613. | ||
*Tinco Andringa* | ||
## Rails 5.0.0 (June 30, 2016) ## | ||
@@ -2,0 +55,0 @@ |
(function() { | ||
var slice = [].slice; | ||
(function() { | ||
(function() { | ||
var slice = [].slice; | ||
this.ActionCable = { | ||
INTERNAL: { | ||
"message_types": { | ||
"welcome": "welcome", | ||
"ping": "ping", | ||
"confirmation": "confirm_subscription", | ||
"rejection": "reject_subscription" | ||
}, | ||
"default_mount_path": "/cable", | ||
"protocols": ["actioncable-v1-json", "actioncable-unsupported"] | ||
}, | ||
createConsumer: function(url) { | ||
var ref; | ||
if (url == null) { | ||
url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path; | ||
} | ||
return new ActionCable.Consumer(this.createWebSocketURL(url)); | ||
}, | ||
getConfig: function(name) { | ||
var element; | ||
element = document.head.querySelector("meta[name='action-cable-" + name + "']"); | ||
return element != null ? element.getAttribute("content") : void 0; | ||
}, | ||
createWebSocketURL: function(url) { | ||
var a; | ||
if (url && !/^wss?:/i.test(url)) { | ||
a = document.createElement("a"); | ||
a.href = url; | ||
a.href = a.href; | ||
a.protocol = a.protocol.replace("http", "ws"); | ||
return a.href; | ||
} else { | ||
return url; | ||
} | ||
}, | ||
startDebugging: function() { | ||
return this.debugging = true; | ||
}, | ||
stopDebugging: function() { | ||
return this.debugging = null; | ||
}, | ||
log: function() { | ||
var messages; | ||
messages = 1 <= arguments.length ? slice.call(arguments, 0) : []; | ||
if (this.debugging) { | ||
messages.push(Date.now()); | ||
return console.log.apply(console, ["[ActionCable]"].concat(slice.call(messages))); | ||
} | ||
} | ||
}; | ||
this.ActionCable = { | ||
INTERNAL: { | ||
"message_types": { | ||
"welcome": "welcome", | ||
"ping": "ping", | ||
"confirmation": "confirm_subscription", | ||
"rejection": "reject_subscription" | ||
}, | ||
"default_mount_path": "/cable", | ||
"protocols": ["actioncable-v1-json", "actioncable-unsupported"] | ||
}, | ||
createConsumer: function(url) { | ||
var ref; | ||
if (url == null) { | ||
url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path; | ||
} | ||
return new ActionCable.Consumer(this.createWebSocketURL(url)); | ||
}, | ||
getConfig: function(name) { | ||
var element; | ||
element = document.head.querySelector("meta[name='action-cable-" + name + "']"); | ||
return element != null ? element.getAttribute("content") : void 0; | ||
}, | ||
createWebSocketURL: function(url) { | ||
var a; | ||
if (url && !/^wss?:/i.test(url)) { | ||
a = document.createElement("a"); | ||
a.href = url; | ||
a.href = a.href; | ||
a.protocol = a.protocol.replace("http", "ws"); | ||
return a.href; | ||
} else { | ||
return url; | ||
} | ||
}, | ||
startDebugging: function() { | ||
return this.debugging = true; | ||
}, | ||
stopDebugging: function() { | ||
return this.debugging = null; | ||
}, | ||
log: function() { | ||
var messages; | ||
messages = 1 <= arguments.length ? slice.call(arguments, 0) : []; | ||
if (this.debugging) { | ||
messages.push(Date.now()); | ||
return console.log.apply(console, ["[ActionCable]"].concat(slice.call(messages))); | ||
} | ||
} | ||
}; | ||
if (typeof window !== "undefined" && window !== null) { | ||
window.ActionCable = this.ActionCable; | ||
} | ||
}).call(this); | ||
}).call(this); | ||
if (typeof module !== "undefined" && module !== null) { | ||
module.exports = this.ActionCable; | ||
} | ||
var ActionCable = this.ActionCable; | ||
}).call(this); | ||
(function() { | ||
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; | ||
(function() { | ||
(function() { | ||
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; | ||
ActionCable.ConnectionMonitor = (function() { | ||
var clamp, now, secondsSince; | ||
ActionCable.ConnectionMonitor = (function() { | ||
var clamp, now, secondsSince; | ||
ConnectionMonitor.pollInterval = { | ||
min: 3, | ||
max: 30 | ||
}; | ||
ConnectionMonitor.pollInterval = { | ||
min: 3, | ||
max: 30 | ||
}; | ||
ConnectionMonitor.staleThreshold = 6; | ||
ConnectionMonitor.staleThreshold = 6; | ||
function ConnectionMonitor(connection) { | ||
this.connection = connection; | ||
this.visibilityDidChange = bind(this.visibilityDidChange, this); | ||
this.reconnectAttempts = 0; | ||
} | ||
function ConnectionMonitor(connection) { | ||
this.connection = connection; | ||
this.visibilityDidChange = bind(this.visibilityDidChange, this); | ||
this.reconnectAttempts = 0; | ||
} | ||
ConnectionMonitor.prototype.start = function() { | ||
if (!this.isRunning()) { | ||
this.startedAt = now(); | ||
delete this.stoppedAt; | ||
this.startPolling(); | ||
document.addEventListener("visibilitychange", this.visibilityDidChange); | ||
return ActionCable.log("ConnectionMonitor started. pollInterval = " + (this.getPollInterval()) + " ms"); | ||
} | ||
}; | ||
ConnectionMonitor.prototype.start = function() { | ||
if (!this.isRunning()) { | ||
this.startedAt = now(); | ||
delete this.stoppedAt; | ||
this.startPolling(); | ||
document.addEventListener("visibilitychange", this.visibilityDidChange); | ||
return ActionCable.log("ConnectionMonitor started. pollInterval = " + (this.getPollInterval()) + " ms"); | ||
} | ||
}; | ||
ConnectionMonitor.prototype.stop = function() { | ||
if (this.isRunning()) { | ||
this.stoppedAt = now(); | ||
this.stopPolling(); | ||
document.removeEventListener("visibilitychange", this.visibilityDidChange); | ||
return ActionCable.log("ConnectionMonitor stopped"); | ||
} | ||
}; | ||
ConnectionMonitor.prototype.stop = function() { | ||
if (this.isRunning()) { | ||
this.stoppedAt = now(); | ||
this.stopPolling(); | ||
document.removeEventListener("visibilitychange", this.visibilityDidChange); | ||
return ActionCable.log("ConnectionMonitor stopped"); | ||
} | ||
}; | ||
ConnectionMonitor.prototype.isRunning = function() { | ||
return (this.startedAt != null) && (this.stoppedAt == null); | ||
}; | ||
ConnectionMonitor.prototype.isRunning = function() { | ||
return (this.startedAt != null) && (this.stoppedAt == null); | ||
}; | ||
ConnectionMonitor.prototype.recordPing = function() { | ||
return this.pingedAt = now(); | ||
}; | ||
ConnectionMonitor.prototype.recordPing = function() { | ||
return this.pingedAt = now(); | ||
}; | ||
ConnectionMonitor.prototype.recordConnect = function() { | ||
this.reconnectAttempts = 0; | ||
this.recordPing(); | ||
delete this.disconnectedAt; | ||
return ActionCable.log("ConnectionMonitor recorded connect"); | ||
}; | ||
ConnectionMonitor.prototype.recordConnect = function() { | ||
this.reconnectAttempts = 0; | ||
this.recordPing(); | ||
delete this.disconnectedAt; | ||
return ActionCable.log("ConnectionMonitor recorded connect"); | ||
}; | ||
ConnectionMonitor.prototype.recordDisconnect = function() { | ||
this.disconnectedAt = now(); | ||
return ActionCable.log("ConnectionMonitor recorded disconnect"); | ||
}; | ||
ConnectionMonitor.prototype.recordDisconnect = function() { | ||
this.disconnectedAt = now(); | ||
return ActionCable.log("ConnectionMonitor recorded disconnect"); | ||
}; | ||
ConnectionMonitor.prototype.startPolling = function() { | ||
this.stopPolling(); | ||
return this.poll(); | ||
}; | ||
ConnectionMonitor.prototype.startPolling = function() { | ||
this.stopPolling(); | ||
return this.poll(); | ||
}; | ||
ConnectionMonitor.prototype.stopPolling = function() { | ||
return clearTimeout(this.pollTimeout); | ||
}; | ||
ConnectionMonitor.prototype.stopPolling = function() { | ||
return clearTimeout(this.pollTimeout); | ||
}; | ||
ConnectionMonitor.prototype.poll = function() { | ||
return this.pollTimeout = setTimeout((function(_this) { | ||
return function() { | ||
_this.reconnectIfStale(); | ||
return _this.poll(); | ||
ConnectionMonitor.prototype.poll = function() { | ||
return this.pollTimeout = setTimeout((function(_this) { | ||
return function() { | ||
_this.reconnectIfStale(); | ||
return _this.poll(); | ||
}; | ||
})(this), this.getPollInterval()); | ||
}; | ||
})(this), this.getPollInterval()); | ||
}; | ||
ConnectionMonitor.prototype.getPollInterval = function() { | ||
var interval, max, min, ref; | ||
ref = this.constructor.pollInterval, min = ref.min, max = ref.max; | ||
interval = 5 * Math.log(this.reconnectAttempts + 1); | ||
return Math.round(clamp(interval, min, max) * 1000); | ||
}; | ||
ConnectionMonitor.prototype.getPollInterval = function() { | ||
var interval, max, min, ref; | ||
ref = this.constructor.pollInterval, min = ref.min, max = ref.max; | ||
interval = 5 * Math.log(this.reconnectAttempts + 1); | ||
return Math.round(clamp(interval, min, max) * 1000); | ||
}; | ||
ConnectionMonitor.prototype.reconnectIfStale = function() { | ||
if (this.connectionIsStale()) { | ||
ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = " + this.reconnectAttempts + ", pollInterval = " + (this.getPollInterval()) + " ms, time disconnected = " + (secondsSince(this.disconnectedAt)) + " s, stale threshold = " + this.constructor.staleThreshold + " s"); | ||
this.reconnectAttempts++; | ||
if (this.disconnectedRecently()) { | ||
return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect"); | ||
} else { | ||
ActionCable.log("ConnectionMonitor reopening"); | ||
return this.connection.reopen(); | ||
} | ||
} | ||
}; | ||
ConnectionMonitor.prototype.reconnectIfStale = function() { | ||
if (this.connectionIsStale()) { | ||
ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = " + this.reconnectAttempts + ", pollInterval = " + (this.getPollInterval()) + " ms, time disconnected = " + (secondsSince(this.disconnectedAt)) + " s, stale threshold = " + this.constructor.staleThreshold + " s"); | ||
this.reconnectAttempts++; | ||
if (this.disconnectedRecently()) { | ||
return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect"); | ||
} else { | ||
ActionCable.log("ConnectionMonitor reopening"); | ||
return this.connection.reopen(); | ||
} | ||
} | ||
}; | ||
ConnectionMonitor.prototype.connectionIsStale = function() { | ||
var ref; | ||
return secondsSince((ref = this.pingedAt) != null ? ref : this.startedAt) > this.constructor.staleThreshold; | ||
}; | ||
ConnectionMonitor.prototype.connectionIsStale = function() { | ||
var ref; | ||
return secondsSince((ref = this.pingedAt) != null ? ref : this.startedAt) > this.constructor.staleThreshold; | ||
}; | ||
ConnectionMonitor.prototype.disconnectedRecently = function() { | ||
return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; | ||
}; | ||
ConnectionMonitor.prototype.disconnectedRecently = function() { | ||
return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; | ||
}; | ||
ConnectionMonitor.prototype.visibilityDidChange = function() { | ||
if (document.visibilityState === "visible") { | ||
return setTimeout((function(_this) { | ||
return function() { | ||
if (_this.connectionIsStale() || !_this.connection.isOpen()) { | ||
ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState); | ||
return _this.connection.reopen(); | ||
} | ||
}; | ||
})(this), 200); | ||
} | ||
}; | ||
ConnectionMonitor.prototype.visibilityDidChange = function() { | ||
if (document.visibilityState === "visible") { | ||
return setTimeout((function(_this) { | ||
return function() { | ||
if (_this.connectionIsStale() || !_this.connection.isOpen()) { | ||
ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState); | ||
return _this.connection.reopen(); | ||
} | ||
}; | ||
})(this), 200); | ||
} | ||
}; | ||
now = function() { | ||
return new Date().getTime(); | ||
}; | ||
now = function() { | ||
return new Date().getTime(); | ||
}; | ||
secondsSince = function(time) { | ||
return (now() - time) / 1000; | ||
}; | ||
secondsSince = function(time) { | ||
return (now() - time) / 1000; | ||
}; | ||
clamp = function(number, min, max) { | ||
return Math.max(min, Math.min(max, number)); | ||
}; | ||
clamp = function(number, min, max) { | ||
return Math.max(min, Math.min(max, number)); | ||
}; | ||
return ConnectionMonitor; | ||
return ConnectionMonitor; | ||
})(); | ||
})(); | ||
}).call(this); | ||
(function() { | ||
var i, message_types, protocols, ref, supportedProtocols, unsupportedProtocol, | ||
slice = [].slice, | ||
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | ||
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; | ||
}).call(this); | ||
(function() { | ||
var i, message_types, protocols, ref, supportedProtocols, unsupportedProtocol, | ||
slice = [].slice, | ||
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | ||
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; | ||
ref = ActionCable.INTERNAL, message_types = ref.message_types, protocols = ref.protocols; | ||
ref = ActionCable.INTERNAL, message_types = ref.message_types, protocols = ref.protocols; | ||
supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++]; | ||
supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++]; | ||
ActionCable.Connection = (function() { | ||
Connection.reopenDelay = 500; | ||
ActionCable.Connection = (function() { | ||
Connection.reopenDelay = 500; | ||
function Connection(consumer) { | ||
this.consumer = consumer; | ||
this.open = bind(this.open, this); | ||
this.subscriptions = this.consumer.subscriptions; | ||
this.monitor = new ActionCable.ConnectionMonitor(this); | ||
this.disconnected = true; | ||
} | ||
function Connection(consumer) { | ||
this.consumer = consumer; | ||
this.open = bind(this.open, this); | ||
this.subscriptions = this.consumer.subscriptions; | ||
this.monitor = new ActionCable.ConnectionMonitor(this); | ||
this.disconnected = true; | ||
} | ||
Connection.prototype.send = function(data) { | ||
if (this.isOpen()) { | ||
this.webSocket.send(JSON.stringify(data)); | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
Connection.prototype.send = function(data) { | ||
if (this.isOpen()) { | ||
this.webSocket.send(JSON.stringify(data)); | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
Connection.prototype.open = function() { | ||
if (this.isActive()) { | ||
ActionCable.log("Attempted to open WebSocket, but existing socket is " + (this.getState())); | ||
throw new Error("Existing connection must be closed before opening"); | ||
} else { | ||
ActionCable.log("Opening WebSocket, current state is " + (this.getState()) + ", subprotocols: " + protocols); | ||
if (this.webSocket != null) { | ||
this.uninstallEventHandlers(); | ||
} | ||
this.webSocket = new WebSocket(this.consumer.url, protocols); | ||
this.installEventHandlers(); | ||
this.monitor.start(); | ||
return true; | ||
} | ||
}; | ||
Connection.prototype.open = function() { | ||
if (this.isActive()) { | ||
ActionCable.log("Attempted to open WebSocket, but existing socket is " + (this.getState())); | ||
throw new Error("Existing connection must be closed before opening"); | ||
} else { | ||
ActionCable.log("Opening WebSocket, current state is " + (this.getState()) + ", subprotocols: " + protocols); | ||
if (this.webSocket != null) { | ||
this.uninstallEventHandlers(); | ||
} | ||
this.webSocket = new WebSocket(this.consumer.url, protocols); | ||
this.installEventHandlers(); | ||
this.monitor.start(); | ||
return true; | ||
} | ||
}; | ||
Connection.prototype.close = function(arg) { | ||
var allowReconnect, ref1; | ||
allowReconnect = (arg != null ? arg : { | ||
allowReconnect: true | ||
}).allowReconnect; | ||
if (!allowReconnect) { | ||
this.monitor.stop(); | ||
} | ||
if (this.isActive()) { | ||
return (ref1 = this.webSocket) != null ? ref1.close() : void 0; | ||
} | ||
}; | ||
Connection.prototype.close = function(arg) { | ||
var allowReconnect, ref1; | ||
allowReconnect = (arg != null ? arg : { | ||
allowReconnect: true | ||
}).allowReconnect; | ||
if (!allowReconnect) { | ||
this.monitor.stop(); | ||
} | ||
if (this.isActive()) { | ||
return (ref1 = this.webSocket) != null ? ref1.close() : void 0; | ||
} | ||
}; | ||
Connection.prototype.reopen = function() { | ||
var error, error1; | ||
ActionCable.log("Reopening WebSocket, current state is " + (this.getState())); | ||
if (this.isActive()) { | ||
try { | ||
return this.close(); | ||
} catch (error1) { | ||
error = error1; | ||
return ActionCable.log("Failed to reopen WebSocket", error); | ||
} finally { | ||
ActionCable.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms"); | ||
setTimeout(this.open, this.constructor.reopenDelay); | ||
} | ||
} else { | ||
return this.open(); | ||
} | ||
}; | ||
Connection.prototype.reopen = function() { | ||
var error, error1; | ||
ActionCable.log("Reopening WebSocket, current state is " + (this.getState())); | ||
if (this.isActive()) { | ||
try { | ||
return this.close(); | ||
} catch (error1) { | ||
error = error1; | ||
return ActionCable.log("Failed to reopen WebSocket", error); | ||
} finally { | ||
ActionCable.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms"); | ||
setTimeout(this.open, this.constructor.reopenDelay); | ||
} | ||
} else { | ||
return this.open(); | ||
} | ||
}; | ||
Connection.prototype.getProtocol = function() { | ||
var ref1; | ||
return (ref1 = this.webSocket) != null ? ref1.protocol : void 0; | ||
}; | ||
Connection.prototype.getProtocol = function() { | ||
var ref1; | ||
return (ref1 = this.webSocket) != null ? ref1.protocol : void 0; | ||
}; | ||
Connection.prototype.isOpen = function() { | ||
return this.isState("open"); | ||
}; | ||
Connection.prototype.isOpen = function() { | ||
return this.isState("open"); | ||
}; | ||
Connection.prototype.isActive = function() { | ||
return this.isState("open", "connecting"); | ||
}; | ||
Connection.prototype.isActive = function() { | ||
return this.isState("open", "connecting"); | ||
}; | ||
Connection.prototype.isProtocolSupported = function() { | ||
var ref1; | ||
return ref1 = this.getProtocol(), indexOf.call(supportedProtocols, ref1) >= 0; | ||
}; | ||
Connection.prototype.isProtocolSupported = function() { | ||
var ref1; | ||
return ref1 = this.getProtocol(), indexOf.call(supportedProtocols, ref1) >= 0; | ||
}; | ||
Connection.prototype.isState = function() { | ||
var ref1, states; | ||
states = 1 <= arguments.length ? slice.call(arguments, 0) : []; | ||
return ref1 = this.getState(), indexOf.call(states, ref1) >= 0; | ||
}; | ||
Connection.prototype.isState = function() { | ||
var ref1, states; | ||
states = 1 <= arguments.length ? slice.call(arguments, 0) : []; | ||
return ref1 = this.getState(), indexOf.call(states, ref1) >= 0; | ||
}; | ||
Connection.prototype.getState = function() { | ||
var ref1, state, value; | ||
for (state in WebSocket) { | ||
value = WebSocket[state]; | ||
if (value === ((ref1 = this.webSocket) != null ? ref1.readyState : void 0)) { | ||
return state.toLowerCase(); | ||
} | ||
} | ||
return null; | ||
}; | ||
Connection.prototype.getState = function() { | ||
var ref1, state, value; | ||
for (state in WebSocket) { | ||
value = WebSocket[state]; | ||
if (value === ((ref1 = this.webSocket) != null ? ref1.readyState : void 0)) { | ||
return state.toLowerCase(); | ||
} | ||
} | ||
return null; | ||
}; | ||
Connection.prototype.installEventHandlers = function() { | ||
var eventName, handler; | ||
for (eventName in this.events) { | ||
handler = this.events[eventName].bind(this); | ||
this.webSocket["on" + eventName] = handler; | ||
} | ||
}; | ||
Connection.prototype.installEventHandlers = function() { | ||
var eventName, handler; | ||
for (eventName in this.events) { | ||
handler = this.events[eventName].bind(this); | ||
this.webSocket["on" + eventName] = handler; | ||
} | ||
}; | ||
Connection.prototype.uninstallEventHandlers = function() { | ||
var eventName; | ||
for (eventName in this.events) { | ||
this.webSocket["on" + eventName] = function() {}; | ||
} | ||
}; | ||
Connection.prototype.uninstallEventHandlers = function() { | ||
var eventName; | ||
for (eventName in this.events) { | ||
this.webSocket["on" + eventName] = function() {}; | ||
} | ||
}; | ||
Connection.prototype.events = { | ||
message: function(event) { | ||
var identifier, message, ref1, type; | ||
if (!this.isProtocolSupported()) { | ||
return; | ||
} | ||
ref1 = JSON.parse(event.data), identifier = ref1.identifier, message = ref1.message, type = ref1.type; | ||
switch (type) { | ||
case message_types.welcome: | ||
this.monitor.recordConnect(); | ||
return this.subscriptions.reload(); | ||
case message_types.ping: | ||
return this.monitor.recordPing(); | ||
case message_types.confirmation: | ||
return this.subscriptions.notify(identifier, "connected"); | ||
case message_types.rejection: | ||
return this.subscriptions.reject(identifier); | ||
default: | ||
return this.subscriptions.notify(identifier, "received", message); | ||
} | ||
}, | ||
open: function() { | ||
ActionCable.log("WebSocket onopen event, using '" + (this.getProtocol()) + "' subprotocol"); | ||
this.disconnected = false; | ||
if (!this.isProtocolSupported()) { | ||
ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting."); | ||
return this.close({ | ||
allowReconnect: false | ||
}); | ||
} | ||
}, | ||
close: function(event) { | ||
ActionCable.log("WebSocket onclose event"); | ||
if (this.disconnected) { | ||
return; | ||
} | ||
this.disconnected = true; | ||
this.monitor.recordDisconnect(); | ||
return this.subscriptions.notifyAll("disconnected", { | ||
willAttemptReconnect: this.monitor.isRunning() | ||
}); | ||
}, | ||
error: function() { | ||
return ActionCable.log("WebSocket onerror event"); | ||
} | ||
}; | ||
Connection.prototype.events = { | ||
message: function(event) { | ||
var identifier, message, ref1, type; | ||
if (!this.isProtocolSupported()) { | ||
return; | ||
} | ||
ref1 = JSON.parse(event.data), identifier = ref1.identifier, message = ref1.message, type = ref1.type; | ||
switch (type) { | ||
case message_types.welcome: | ||
this.monitor.recordConnect(); | ||
return this.subscriptions.reload(); | ||
case message_types.ping: | ||
return this.monitor.recordPing(); | ||
case message_types.confirmation: | ||
return this.subscriptions.notify(identifier, "connected"); | ||
case message_types.rejection: | ||
return this.subscriptions.reject(identifier); | ||
default: | ||
return this.subscriptions.notify(identifier, "received", message); | ||
} | ||
}, | ||
open: function() { | ||
ActionCable.log("WebSocket onopen event, using '" + (this.getProtocol()) + "' subprotocol"); | ||
this.disconnected = false; | ||
if (!this.isProtocolSupported()) { | ||
ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting."); | ||
return this.close({ | ||
allowReconnect: false | ||
}); | ||
} | ||
}, | ||
close: function(event) { | ||
ActionCable.log("WebSocket onclose event"); | ||
if (this.disconnected) { | ||
return; | ||
} | ||
this.disconnected = true; | ||
this.monitor.recordDisconnect(); | ||
return this.subscriptions.notifyAll("disconnected", { | ||
willAttemptReconnect: this.monitor.isRunning() | ||
}); | ||
}, | ||
error: function() { | ||
return ActionCable.log("WebSocket onerror event"); | ||
} | ||
}; | ||
return Connection; | ||
return Connection; | ||
})(); | ||
})(); | ||
}).call(this); | ||
(function() { | ||
var slice = [].slice; | ||
}).call(this); | ||
(function() { | ||
var slice = [].slice; | ||
ActionCable.Subscriptions = (function() { | ||
function Subscriptions(consumer) { | ||
this.consumer = consumer; | ||
this.subscriptions = []; | ||
} | ||
ActionCable.Subscriptions = (function() { | ||
function Subscriptions(consumer) { | ||
this.consumer = consumer; | ||
this.subscriptions = []; | ||
} | ||
Subscriptions.prototype.create = function(channelName, mixin) { | ||
var channel, params, subscription; | ||
channel = channelName; | ||
params = typeof channel === "object" ? channel : { | ||
channel: channel | ||
}; | ||
subscription = new ActionCable.Subscription(this.consumer, params, mixin); | ||
return this.add(subscription); | ||
}; | ||
Subscriptions.prototype.create = function(channelName, mixin) { | ||
var channel, params, subscription; | ||
channel = channelName; | ||
params = typeof channel === "object" ? channel : { | ||
channel: channel | ||
}; | ||
subscription = new ActionCable.Subscription(this.consumer, params, mixin); | ||
return this.add(subscription); | ||
}; | ||
Subscriptions.prototype.add = function(subscription) { | ||
this.subscriptions.push(subscription); | ||
this.consumer.ensureActiveConnection(); | ||
this.notify(subscription, "initialized"); | ||
this.sendCommand(subscription, "subscribe"); | ||
return subscription; | ||
}; | ||
Subscriptions.prototype.add = function(subscription) { | ||
this.subscriptions.push(subscription); | ||
this.consumer.ensureActiveConnection(); | ||
this.notify(subscription, "initialized"); | ||
this.sendCommand(subscription, "subscribe"); | ||
return subscription; | ||
}; | ||
Subscriptions.prototype.remove = function(subscription) { | ||
this.forget(subscription); | ||
if (!this.findAll(subscription.identifier).length) { | ||
this.sendCommand(subscription, "unsubscribe"); | ||
} | ||
return subscription; | ||
}; | ||
Subscriptions.prototype.remove = function(subscription) { | ||
this.forget(subscription); | ||
if (!this.findAll(subscription.identifier).length) { | ||
this.sendCommand(subscription, "unsubscribe"); | ||
} | ||
return subscription; | ||
}; | ||
Subscriptions.prototype.reject = function(identifier) { | ||
var i, len, ref, results, subscription; | ||
ref = this.findAll(identifier); | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
subscription = ref[i]; | ||
this.forget(subscription); | ||
this.notify(subscription, "rejected"); | ||
results.push(subscription); | ||
} | ||
return results; | ||
}; | ||
Subscriptions.prototype.reject = function(identifier) { | ||
var i, len, ref, results, subscription; | ||
ref = this.findAll(identifier); | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
subscription = ref[i]; | ||
this.forget(subscription); | ||
this.notify(subscription, "rejected"); | ||
results.push(subscription); | ||
} | ||
return results; | ||
}; | ||
Subscriptions.prototype.forget = function(subscription) { | ||
var s; | ||
this.subscriptions = (function() { | ||
var i, len, ref, results; | ||
ref = this.subscriptions; | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
s = ref[i]; | ||
if (s !== subscription) { | ||
results.push(s); | ||
Subscriptions.prototype.forget = function(subscription) { | ||
var s; | ||
this.subscriptions = (function() { | ||
var i, len, ref, results; | ||
ref = this.subscriptions; | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
s = ref[i]; | ||
if (s !== subscription) { | ||
results.push(s); | ||
} | ||
} | ||
return results; | ||
}).call(this); | ||
return subscription; | ||
}; | ||
Subscriptions.prototype.findAll = function(identifier) { | ||
var i, len, ref, results, s; | ||
ref = this.subscriptions; | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
s = ref[i]; | ||
if (s.identifier === identifier) { | ||
results.push(s); | ||
} | ||
} | ||
} | ||
return results; | ||
}).call(this); | ||
return subscription; | ||
}; | ||
return results; | ||
}; | ||
Subscriptions.prototype.findAll = function(identifier) { | ||
var i, len, ref, results, s; | ||
ref = this.subscriptions; | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
s = ref[i]; | ||
if (s.identifier === identifier) { | ||
results.push(s); | ||
} | ||
} | ||
return results; | ||
}; | ||
Subscriptions.prototype.reload = function() { | ||
var i, len, ref, results, subscription; | ||
ref = this.subscriptions; | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
subscription = ref[i]; | ||
results.push(this.sendCommand(subscription, "subscribe")); | ||
} | ||
return results; | ||
}; | ||
Subscriptions.prototype.reload = function() { | ||
var i, len, ref, results, subscription; | ||
ref = this.subscriptions; | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
subscription = ref[i]; | ||
results.push(this.sendCommand(subscription, "subscribe")); | ||
} | ||
return results; | ||
}; | ||
Subscriptions.prototype.notifyAll = function() { | ||
var args, callbackName, i, len, ref, results, subscription; | ||
callbackName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; | ||
ref = this.subscriptions; | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
subscription = ref[i]; | ||
results.push(this.notify.apply(this, [subscription, callbackName].concat(slice.call(args)))); | ||
} | ||
return results; | ||
}; | ||
Subscriptions.prototype.notifyAll = function() { | ||
var args, callbackName, i, len, ref, results, subscription; | ||
callbackName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; | ||
ref = this.subscriptions; | ||
results = []; | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
subscription = ref[i]; | ||
results.push(this.notify.apply(this, [subscription, callbackName].concat(slice.call(args)))); | ||
} | ||
return results; | ||
}; | ||
Subscriptions.prototype.notify = function() { | ||
var args, callbackName, i, len, results, subscription, subscriptions; | ||
subscription = arguments[0], callbackName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; | ||
if (typeof subscription === "string") { | ||
subscriptions = this.findAll(subscription); | ||
} else { | ||
subscriptions = [subscription]; | ||
} | ||
results = []; | ||
for (i = 0, len = subscriptions.length; i < len; i++) { | ||
subscription = subscriptions[i]; | ||
results.push(typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : void 0); | ||
} | ||
return results; | ||
}; | ||
Subscriptions.prototype.notify = function() { | ||
var args, callbackName, i, len, results, subscription, subscriptions; | ||
subscription = arguments[0], callbackName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; | ||
if (typeof subscription === "string") { | ||
subscriptions = this.findAll(subscription); | ||
} else { | ||
subscriptions = [subscription]; | ||
} | ||
results = []; | ||
for (i = 0, len = subscriptions.length; i < len; i++) { | ||
subscription = subscriptions[i]; | ||
results.push(typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : void 0); | ||
} | ||
return results; | ||
}; | ||
Subscriptions.prototype.sendCommand = function(subscription, command) { | ||
var identifier; | ||
identifier = subscription.identifier; | ||
return this.consumer.send({ | ||
command: command, | ||
identifier: identifier | ||
}); | ||
}; | ||
Subscriptions.prototype.sendCommand = function(subscription, command) { | ||
var identifier; | ||
identifier = subscription.identifier; | ||
return this.consumer.send({ | ||
command: command, | ||
identifier: identifier | ||
}); | ||
}; | ||
return Subscriptions; | ||
return Subscriptions; | ||
})(); | ||
})(); | ||
}).call(this); | ||
(function() { | ||
ActionCable.Subscription = (function() { | ||
var extend; | ||
}).call(this); | ||
(function() { | ||
ActionCable.Subscription = (function() { | ||
var extend; | ||
function Subscription(consumer, params, mixin) { | ||
this.consumer = consumer; | ||
if (params == null) { | ||
params = {}; | ||
} | ||
this.identifier = JSON.stringify(params); | ||
extend(this, mixin); | ||
} | ||
function Subscription(consumer, params, mixin) { | ||
this.consumer = consumer; | ||
if (params == null) { | ||
params = {}; | ||
} | ||
this.identifier = JSON.stringify(params); | ||
extend(this, mixin); | ||
} | ||
Subscription.prototype.perform = function(action, data) { | ||
if (data == null) { | ||
data = {}; | ||
} | ||
data.action = action; | ||
return this.send(data); | ||
}; | ||
Subscription.prototype.perform = function(action, data) { | ||
if (data == null) { | ||
data = {}; | ||
} | ||
data.action = action; | ||
return this.send(data); | ||
}; | ||
Subscription.prototype.send = function(data) { | ||
return this.consumer.send({ | ||
command: "message", | ||
identifier: this.identifier, | ||
data: JSON.stringify(data) | ||
}); | ||
}; | ||
Subscription.prototype.send = function(data) { | ||
return this.consumer.send({ | ||
command: "message", | ||
identifier: this.identifier, | ||
data: JSON.stringify(data) | ||
}); | ||
}; | ||
Subscription.prototype.unsubscribe = function() { | ||
return this.consumer.subscriptions.remove(this); | ||
}; | ||
Subscription.prototype.unsubscribe = function() { | ||
return this.consumer.subscriptions.remove(this); | ||
}; | ||
extend = function(object, properties) { | ||
var key, value; | ||
if (properties != null) { | ||
for (key in properties) { | ||
value = properties[key]; | ||
object[key] = value; | ||
} | ||
} | ||
return object; | ||
}; | ||
extend = function(object, properties) { | ||
var key, value; | ||
if (properties != null) { | ||
for (key in properties) { | ||
value = properties[key]; | ||
object[key] = value; | ||
} | ||
} | ||
return object; | ||
}; | ||
return Subscription; | ||
return Subscription; | ||
})(); | ||
})(); | ||
}).call(this); | ||
(function() { | ||
ActionCable.Consumer = (function() { | ||
function Consumer(url) { | ||
this.url = url; | ||
this.subscriptions = new ActionCable.Subscriptions(this); | ||
this.connection = new ActionCable.Connection(this); | ||
} | ||
}).call(this); | ||
(function() { | ||
ActionCable.Consumer = (function() { | ||
function Consumer(url) { | ||
this.url = url; | ||
this.subscriptions = new ActionCable.Subscriptions(this); | ||
this.connection = new ActionCable.Connection(this); | ||
} | ||
Consumer.prototype.send = function(data) { | ||
return this.connection.send(data); | ||
}; | ||
Consumer.prototype.send = function(data) { | ||
return this.connection.send(data); | ||
}; | ||
Consumer.prototype.connect = function() { | ||
return this.connection.open(); | ||
}; | ||
Consumer.prototype.connect = function() { | ||
return this.connection.open(); | ||
}; | ||
Consumer.prototype.disconnect = function() { | ||
return this.connection.close({ | ||
allowReconnect: false | ||
}); | ||
}; | ||
Consumer.prototype.disconnect = function() { | ||
return this.connection.close({ | ||
allowReconnect: false | ||
}); | ||
}; | ||
Consumer.prototype.ensureActiveConnection = function() { | ||
if (!this.connection.isActive()) { | ||
return this.connection.open(); | ||
} | ||
}; | ||
Consumer.prototype.ensureActiveConnection = function() { | ||
if (!this.connection.isActive()) { | ||
return this.connection.open(); | ||
} | ||
}; | ||
return Consumer; | ||
return Consumer; | ||
})(); | ||
})(); | ||
}).call(this); | ||
}).call(this); | ||
if (typeof module === "object" && module.exports) { | ||
module.exports = ActionCable; | ||
} else if (typeof define === "function" && define.amd) { | ||
define(ActionCable); | ||
} | ||
}).call(this); |
{ | ||
"name": "actioncable", | ||
"version": "5.0.0", | ||
"version": "5.0.1-rc1", | ||
"description": "WebSocket framework for Ruby on Rails.", | ||
@@ -5,0 +5,0 @@ "main": "lib/assets/compiled/action_cable.js", |
@@ -326,4 +326,7 @@ # Action Cable – Integrated WebSockets for Rails | ||
Action Cable will only accept requests from specified origins, which are passed to the server config as an array. The origins can be instances of strings or regular expressions, against which a check for match will be performed. | ||
Action Cable will only accept requests from specific origins. | ||
By default, only an origin matching the cable server itself will be permitted. | ||
Additional origins can be specified using strings or regular expressions, provided in an array. | ||
```ruby | ||
@@ -335,3 +338,3 @@ Rails.application.config.action_cable.allowed_request_origins = ['http://rubyonrails.com', /http:\/\/ruby.*/] | ||
To disable and allow requests from any origin: | ||
To disable protection and allow requests from any origin: | ||
@@ -342,2 +345,9 @@ ```ruby | ||
To disable automatic access for same-origin requests, and strictly allow | ||
only the configured origins: | ||
```ruby | ||
Rails.application.config.action_cable.allow_same_origin_as_host = false | ||
``` | ||
### Consumer Configuration | ||
@@ -344,0 +354,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
45826
520
556
1
1