export class PubSub {
/**
* Heartbeat Interval Handle
*
* @returns Number
*/
heartbeatHandle = null;
/**
* WebSocket
*
* @returns Object
*/
socket = null;
/**
* Config
*
* @returns Object
*/
config = {};
/**
* Subscription handlers
*
* @returns Object
*/
static subHandlers = {};
/**
* Channel point reward handlers
*
* @returns Object
*/
static rewardHandlers = {};
constructor (config) {
this.config = config;
};
/**
* Add a channel point reward handler
*
* @param {String}
* caller
* @param {Function}
* handler
* @returns PubSub
*/
addRewardHandler (caller, handler) {
PubSub.rewardHandlers[caller] = handler;
return this;
};
/**
* Remove a channel point reward handler
*
* @param {String}
* caller
* @returns PubSub
*/
removeRewardHandler (caller) {
delete PubSub.rewardHandlers[caller];
return this;
};
/**
* Add a subscription handler
*
* @param {String}
* caller
* @param {Function}
* handler
* @returns PubSub
*/
addSubHandler (caller, handler) {
PubSub.subHandlers[caller] = handler;
return this;
};
/**
* Remove a subscription handler
*
* @param {String}
* caller
* @param {Function}
* handler
* @returns PubSub
*/
removeSubHandler (caller) {
delete PubSub.subHandlers[caller];
return this;
};
/**
* Connect to WebSocket
*
* @return Void
*/
setupListener () {
if (this.socket && this.socket.readyState != WebSocket.CLOSED) { return; }
this.socket = new WebSocket('wss://pubsub-edge.twitch.tv');
this.socket.onopen = event => {
console.info('PubSub WebSocket connected.');
this.heartbeatHandle = setInterval(() => {
this.socket.send(JSON.stringify({
type : 'PING'
}));
}, 6e4);
this.socket.send(JSON.stringify({
type : 'LISTEN',
nonce : (() => {
var text = '', possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < 15; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
})(),
data : {
topics : [
'channel-points-channel-v1.' + this.config.broadcaster,
'channel-subscribe-events-v1.' + this.config.broadcaster
],
auth_token : this.config.psOauth
}
}));
};
this.socket.onclose = event => {
console.info('PubSub WebSocket closed.');
clearInterval(this.heartbeatHandle);
setTimeout(() => (console.info('PubSub WebSocket reconnecting...'), this.setupListener()), 3e3);
};
this.socket.onerror = console.error;
this.socket.onmessage = event => {
const eventData = JSON.parse(event.data);
if (eventData.type == 'MESSAGE') {
if (eventData.data.topic === 'channel-points-channel-v1.' + this.config.broadcaster) {
const message = JSON.parse(eventData.data.message).data.redemption;
for (var [caller, handler] of Object.entries(PubSub.rewardHandlers)) {
handler(message.user.display_name, message.reward, message.user_input);
}
}
if (eventData.data.topic === 'channel-subscribe-events-v1.' + this.config.broadcaster) {
const message = JSON.parse(eventData.data.message);
for (var [caller, handler] of Object.entries(PubSub.subHandlers)) {
handler(message.display_name, message);
}
}
}
};
};
/**
* Disconnect from websocket
*
* @returns Void
*/
disconnectListener () {
if (!this.socket || this.socket.readyState == WebSocket.CLOSED) { return; }
this.socket.close();
};
};
Here a JS class for pubsub that listens to channel point reward redemption and subscriptions.
Try it out.