Skip to content

Instantly share code, notes, and snippets.

@ashgkwd
Created December 29, 2021 10:42
Show Gist options
  • Save ashgkwd/dfb2cb8c721432db5746d7361f2986e1 to your computer and use it in GitHub Desktop.
Save ashgkwd/dfb2cb8c721432db5746d7361f2986e1 to your computer and use it in GitHub Desktop.
Connect to WebSocket opened by ActionCable
export function Cable() {
function _initSocket({
url = "ws://localhost:4080/cable", // Take from config
onOpen,
onClose,
onError,
onMessage,
}) {
Cable.socket = new WebSocket(url);
Cable.socket.onopen = onOpen;
Cable.socket.onclose = onClose;
Cable.socket.onerror = onError;
Cable.socket.onmessage = onMessage;
return Cable.socket;
}
Cable.listeners = [];
Cable.queuedMessages = new Map();
Cable.queuedSubscriptions = [];
Cable.isConnected = false;
Cable.passMessage = (message) => {
Cable.listeners.map((fn) => fn(message));
};
function registerListener(fn) {
Cable.listeners = [];
Cable.listeners.push(fn);
}
function _handleMessage(e) {
const packet = JSON.parse(e.data);
if (packet.type === "ping") return;
if (packet.type === "confirm_subscription")
processMessageQueue(JSON.parse(packet.identifier).channel);
Cable.passMessage(packet.message);
}
function getSocket() {
return (
Cable.socket ||
_initSocket({
onOpen: (e) => {
console.log("WebSocket Opened", e);
Cable.isConnected = true;
processSubscriptionQueue();
},
onClose: (e) => console.log("WebSocket Closed", e),
onError: (e) => console.error("WebSocket Errored", e),
onMessage: _handleMessage,
})
);
}
function processSubscriptionQueue() {
while (Cable.queuedSubscriptions.length) {
subscribeOnSocket(Cable.queuedSubscriptions.shift());
}
}
function processMessageQueue(channel) {
const messages = Cable.queuedMessages.get(channel) || [];
while (messages.length) {
messageOnSocket(channel, messages.shift());
}
}
function messageOnSocket(channel, data) {
Cable.socket.send(
JSON.stringify({
command: "message",
identifier: JSON.stringify({ channel }),
data: JSON.stringify(data),
})
);
}
function subscribeOnSocket(channel) {
console.log("Sending subscription command", channel);
Cable.socket.send(
JSON.stringify({
command: "subscribe",
identifier: JSON.stringify({ channel }),
})
);
}
function queueSubscription(channel) {
Cable.queuedSubscriptions.push(channel);
}
function queueMessage(channel, message) {
const messages = Cable.queuedMessages.get(channel) || [];
messages.push(message);
Cable.queuedMessages.set(channel, messages);
}
function subscribe(channel) {
console.log("Cable subscribing to", channel);
if (Cable.isConnected) subscribeOnSocket(channel);
else queueSubscription(channel);
}
function broadcast(channel, message) {
console.log("Cable broadcasting to", channel, message);
if (Cable.isConnected) messageOnSocket(channel, message);
else queueMessage(channel, message);
}
return {
socket: getSocket(),
subscribe,
broadcast,
registerListener,
};
}
export const cable = Cable();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment