Skip to content

Instantly share code, notes, and snippets.

@igordata
Created February 10, 2018 14:08
Show Gist options
  • Save igordata/7466fb54e617ef054a1cbe7215a355c9 to your computer and use it in GitHub Desktop.
Save igordata/7466fb54e617ef054a1cbe7215a355c9 to your computer and use it in GitHub Desktop.
centrifugo
function rtmClass() {
var rtm = this;
rtm.centrifuge = null;
rtm.worker = null;
/*
event handlers
*/
rtm.handlers = [];
rtm.on = function (event, handler) {
if (typeof rtm.handlers[event] === 'undefined') {
rtm.handlers[event] = [];
}
rtm.handlers[event].push(handler);
};
/*
/ event handlers
*/
rtm.onMessage = function (msg) {
console.log('iminomMessage');
console.log(msg);
var event = msg.data.type;
if (typeof msg.data.options !== 'undefined') {
rtm.processOptions(msg.data.options);
}
if (typeof rtm.handlers[event] === 'undefined') {
return false;
}
if (rtm.handlers[event].length == 0) {
return false;
}
for (var i = rtm.handlers[event].length; i--;) {
rtm.handlers[event][i](msg.data.data);
}
}
rtm.callbacks = {
"message": rtm.onMessage,
"join": function (message) {
},
"leave": function (message) {
},
"subscribe": function (context) {
},
"error": function (error) {
},
"unsubscribe": function (context) {
}
};
rtm.centrifugeInit = function (channels) {
rtm.centrifuge.startAuthBatching();
for (var i = channels.length; i--;) {
rtm.centrifuge.subscribe(channels[i], rtm.callbacks);
}
if (JohnSnow.channels) {
for (var i = JohnSnow.channels.length; i--;) {
rtm.centrifuge.subscribe(JohnSnow.channels[i], rtm.callbacks);
}
}
rtm.centrifuge.stopAuthBatching();
rtm.centrifuge.connect();
};
/**
* Used to init rtm class and connect to centrifuge
*/
rtm.init = function () {
/* если есть вебворкер - цепляемся и слушаем его. Если нету - напрямую к центрифуге. */
try {
if (Notification.permission !== "granted") {
Notification.requestPermission();
}
} catch (err) {
}
rtm.worker = rtm.createWorker();
if (rtm.worker.w) {
console.log('rtm: webworker mode');
return true;
} else {
console.log('rtm: direct mode');
apirequest({
url: '/api/rtm/subscribe',
onSuccess: function (reply) {
rtm.centrifuge = new Centrifuge({
url: '/centrifugo',
user: reply.getData('user'),
timestamp: reply.getData('timestamp'),
token: reply.getData('token'),
authEndpoint: '/api/rtm/auth',
transports: [
'websocket', 'xdr-streaming', 'xhr-streaming',
'eventsource', 'iframe-eventsource', 'iframe-htmlfile',
'xdr-polling', 'xhr-polling', 'iframe-xhr-polling', 'jsonp-polling'
]
/* transports: [
'xdr-polling', 'xhr-polling'
]*/
});
rtm.centrifugeInit(reply.getData('channels'));
}
});
return true;
}
};
/*
counter
*/
rtm.counter = {};
rtm.counter.increment = function (name) {
var counters = $('span.rtm-counter-' + name);
$(counters).each(function () {
var counter = $(this);
var cur = parseInt(counter.text());
if (isNaN(cur)) {
cur = 0;
}
cur++;
rtm.counter.setVal(counter, cur);
});
};
rtm.counter.decrement = function (name) {
var counters = $('span.rtm-counter-' + name);
$(counters).each(function () {
var counter = $(this);
var cur = parseInt(counter.text());
if (isNaN(cur)) {
cur = 1;
}
cur--;
if (cur == 0) {
cur = '';
}
rtm.counter.setVal(counter, cur);
})
};
rtm.counter.reset = function (name) {
$('span.rtm-counter-' + name).each(function () {
rtm.counter.setVal($(this), '');
});
};
rtm.counter.setVal = function (counter, value) {
$(counter).animate({opacity: 0.01}, 100, function () {
// Animation complete.
counter.text(value);
$(counter).animate({opacity: 1}, 400);
});
};
/*
/ counter
*/
rtm.processOptions = function (options) {
for (var key in options) {
switch (key) {
case 'counter increment':
rtm.counter.increment(options[key]);
break;
case 'counter reset':
rtm.counter.reset(options[key]);
break;
case 'notice':
rtm.notice(options[key]);
break;
}
}
};
rtm.navigate = function (options) {
if (typeof options !== 'object') {
options = {url: options};
}
var defaults = {
url: '/',
name: '_blank'
}
var settings = $.extend({}, defaults, options);
window.open(options.url, options.name);
};
/*
rtm notice
*/
rtm.notice = function (options) {
if (typeof options !== 'object') {
options = {text: options};
}
var defaults = {
html: false,
header: false,
text: '',
type: 'info',
image: false,
url: false
};
var settings = $.extend({}, defaults, options);
try {
if (typeof Notification !== 'undefined') {
if (Notification.permission !== "granted") {
Notification.requestPermission();
} else {
var notification = new Notification(settings.header, {
icon: settings.image,
body: settings.text,
});
notification.onclick = function () {
window.open(settings.url);
};
}
}
return;
} catch (err) {
}
var notice = $('<div class="notice" style="dispdlay: none;"></div>');
notice.addClass(settings.type);
if (settings.url) {
notice.data('url', settings.url);
}
var body = $('<div class="body"></div>');
var header = $('<div class="header"></div>');
if (settings.header) {
if (settings.html) {
header.html(settings.header);
} else {
header.text(settings.header);
}
}
var text = $('<div class="text"></div>');
if (settings.text) {
if (settings.html) {
text.html(settings.text);
} else {
text.text(settings.text);
}
}
var message = $('<div class="message"></div>');
message.append(header);
message.append(text);
body.append(message);
if (settings.image) {
body.prepend('<img class="image" src="' + settings.image + '" style="dispdlay: none;">');
}
notice.append(body);
$('#rtm-notifications').append(notice);
notice.hide().slideDown();
//notice.find('img.image').slideDown();
setTimeout(function () {
rtm.noticeHide(notice);
}, 5000);
};
rtm.noticeHide = function (notice) {
notice = $(notice);
notice.height(notice.height());
var body = $(notice).children().first();
body.fadeOut(200, function () {
notice.slideUp(75).remove();
});
};
/*
/ rtm notice
*/
function Worker() {
var worker = this;
function init() {
if (typeof SharedWorker === 'undefined') {
console.log('Cant create shared worker - typeof SharedWorker is undefined. Fallback!');
return false;
}
try {
sw = new SharedWorker("/rtm/ww.js");
sw.port.addEventListener("message", function (msg) {
console.log('Shared worker new message: ', msg);
if (worker.onMessage) {
worker.onMessage(msg);
}
}, false);
window.addEventListener("beforeunload", function (e) {
worker.bye();
});
sw.port.start();
return sw;
} catch (err) {
console.log(err);
return false;
}
};
worker.onMessage = null;
worker.w = init();
worker.messageRaw = function (message) {
if (!worker.w) {
console.log('Shared worker is false');
return false;
}
if (!worker.w.port) {
console.log('Shared worker have no port');
return false;
}
console.log('Sending message to shared worker', message);
return worker.w.port.postMessage(message);
};
worker.message = function (message) {
return worker.messageRaw({type: 'message', data: message});
};
worker.command = function (command, data) {
if (typeof command === 'undefined') {
return false;
}
if (typeof data === 'undefined') {
data = {};
}
return worker.messageRaw({type: 'command', command: command, data: data});
};
worker.ping = function () {
worker.command('ping');
};
worker.bye = function () {
worker.command('bye');
};
worker.subscribe = function (channels) {
if (typeof channels === 'undefined') {
return false;
}
if (channels.length == 0) {
return false;
}
worker.command('subscribe', channels);
}
};
rtm.createWorker = function () {
var worker = new Worker();
worker.onMessage = rtm.onMessage;
if (JohnSnow.channels && JohnSnow.channels.length > 0) {
worker.subscribe(JohnSnow.channels);
}
return worker;
}
};
var rtm = new rtmClass();
$(document).ready(function () {
rtm.init();
setInterval(function () {
rtm.worker.ping();
}, 28000);
$('body').append('<div id="rtm-notifications" oncontextmenu="return false;"></div>');
$('#rtm-notifications').on('mousedown', 'div.notice', function (e) {
e = e || window.event;
var notice = $(this);
if (e.which != 3) {
var url = notice.data('url');
if (url) {
if (e.which == 1) {
location.href = url;
} else {
var win = window.open(url, '_blank');
}
}
}
rtm.noticeHide(notice);
});
rtm.on('navigate', function (data) {
rtm.navigate(data);
});
/*
rtm.notice({header: 'header', type: 'info', text: 'info'});
rtm.notice({header: 'header', type: 'success', text: 'success'});
rtm.notice({header: 'header', type: 'warning', text: 'warning'});
rtm.notice({header: 'header', type: 'error', text: 'error'});
*/
rtm.on('dialogs message', function (data) {
if (typeof JohnSnow.dialog !== 'undefined' && JohnSnow.dialog.id == data.message.dialog) {
/* мы в том диалоге, в который пришло сообщение */
clearTimeout(dialogsRemoveTypingTimer);
$('#messages').find('.typing').remove();
var prevMsg = $('#messages').find('div.message').last();
// рисуем в диалог
var html = '';
html += '<div id="message-' + data.message.id + '" class="message"';
if (JohnSnow.user.id == data.message.user) {
html += 'onclick="dialog.message.check(' + data.message.id + ')"><div class="pull-left check-box"><input class="check" type="checkbox" value="' + data.message.id + '"></div>';
} else {
html += '><div class="pull-left check-box"></div>';
}
html += '<div class="receiver pull-left">';
if (prevMsg.data('user') != data.message.user) {
html += '<a href="/user/' + data.message.user + '"><img src="' + data.sender.avatar + '"></a>';
}
html += '</div>\
<div class="body pull-left">';
if (prevMsg.data('user') != data.message.user) {
html += '<div class="name"><a href="/user/' + data.message.user + '">' + data.sender.nickname + '</a></div>';
}
html += '<div class="html">' + data.message.html + '</div>\
</div>\
<div class="pull-right date">' + data.message.created_formated + '</div>\
</div>';
var message = $(html);
message.data('id', data.message.id);
message.data('user', data.message.user);
$('#messages').append(message);
if (JohnSnow.dialog.type == 'private' && data.message.user == JohnSnow.user.id) {
/* отмечаем непрочитанными свои новые сообщения, собеседнику они не рисуются непрочитанными, а сразу прочитанными */
message.addClass('unread');
}
dialog.scrollDown();
if (data.message.user != JohnSnow.user.id && JohnSnow.dialog.type == 'private') {
/* отправляеем сообщение о прочитанности: собственные сообщения игнорируем, сообщаем только в приватные диалоги */
dialog.message.read(data.message.dialog, data.message.id);
}
} else {
/* в списке диалогов меняем последнее сообщение */
var dialogTR = $('#dialog-' + data.message.dialog);
if (dialogTR.length) {
dialogTR.find('.last-message-avatar').html('<a class="avatar" href="/user/' + data.message.user + '"><img src="' + data.sender.avatar + '"></a>').parent().addClass('new');
dialogTR.find('.message').text(data.message.text);
}
if (data.message.user == JohnSnow.user.id) {
return false;
}
/*
rtm.notice({
header: data.sender.nickname,
type: 'info',
text: data.message.text,
image: data.sender.avatar,
url: '/dialog/' + data.message.dialog
});
*/
// апаем счётчик
if (typeof JohnSnow.dialogs !== 'undefined' && typeof JohnSnow.dialogs.unread !== 'undefined') {
var found = false;
if (JohnSnow.dialogs.unread.length == 0) {
// явно что-то новое
rtm.counter.increment('dialogs');
} else {
for (var i = JohnSnow.dialogs.unread.length; i--;) {
if (JohnSnow.dialogs.unread[i] == data.message.dialog) {
found = JohnSnow.dialogs.unread[i];
break;
}
}
}
if (found) {
// такой диалог мы уже знаем, что есть новые.
} else {
// мы не нашли такой диалог в непрочитанных диалогах. Апаем счётчик и заносим.
rtm.counter.increment('dialogs');
JohnSnow.dialogs.unread.push(data.message.dialog);
}
}
}
});
rtm.on('dialogs read', function (data) {
if (typeof JohnSnow.dialogs !== 'undefined' && typeof JohnSnow.dialogs.unread !== 'undefined') {
for (var i = JohnSnow.dialogs.unread.length; i--;) {
if (JohnSnow.dialogs.unread[i] == data.dialog) {
JohnSnow.dialogs.unread.splice(i, 1);
rtm.counter.decrement('dialogs');
break;
}
}
}
});
var dialogsRemoveTypingTimer = 0;
rtm.on('dialogs typing', function (data) {
if (typeof JohnSnow.dialog === 'undefined') {
return false;
}
if (JohnSnow.dialog.id != data.dialog) {
return false;
}
clearTimeout(dialogsRemoveTypingTimer);
dialogsRemoveTypingTimer = setTimeout(function () {
$('#messages').find('.typing').remove();
dialog.scrollDown();
}, 3000);
$('#messages').find('.typing').remove();
$('#messages').append('<div class="message typing" data-user="' + data.sender.id + '">\
<div class="receiver pull-left"><a href="/user/' + data.sender.id + '"><img src="' + data.sender.avatar + '"></a></div>\
<div class="body pull-left"><div class="name"><a href="/user/' + data.sender.id + '">' + data.sender.nickname + '</a> печатает&hellip;</div></div>\
</div>');
dialog.scrollDown();
});
rtm.on('dialogs interlocutor read', function (data) {
if (typeof JohnSnow.dialog !== 'undefined' && JohnSnow.dialog.id == data.dialog) {
var messages = $('#messages div.message');
if (messages.length > 0) {
for (var i = messages.length; i--;) {
if ($(messages[i]).data('id') <= data.message) {
$(messages[i]).removeClass('unread');
}
}
}
}
});
rtm.on('dialogs messages deleted', function (data) {
if (typeof JohnSnow.dialog !== 'undefined' && JohnSnow.dialog.id == data.dialog) {
if (data.messages.length > 0) {
for (var i = data.messages.length; i--;) {
$('#message-' + data.messages[i] + ' div.html').html('<span class="deleted">Собеседник удалил сообщение</span>');
}
}
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment