Created
February 10, 2018 14:08
-
-
Save igordata/7466fb54e617ef054a1cbe7215a355c9 to your computer and use it in GitHub Desktop.
centrifugo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> печатает…</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