diff --git a/core/client.js b/core/client.js index 379d6e5f..3dad049d 100644 --- a/core/client.js +++ b/core/client.js @@ -281,8 +281,10 @@ function setErrorMessage(message) { while (node.firstChild) { node.removeChild(node.firstChild); } - node.appendChild(document.createTextNode(message)); - node.setAttribute("style", "display: inline; color: #dc322f"); + if (message) { + node.appendChild(document.createTextNode(message)); + node.setAttribute("style", "display: inline; color: #dc322f"); + } } function send(command) { @@ -429,11 +431,17 @@ function hashChange() { } function focus() { - send({event: "focus"}); + if (gSocket && gSocket.readyState == gSocket.CLOSED) { + connectSocket(); + } else { + send({event: "focus"}); + } } function blur() { - send({event: "blur"}); + if (gSocket && gSocket.readyState == gSocket.OPEN) { + send({event: "blur"}); + } } function onMessage(event) { @@ -452,6 +460,39 @@ function submitButton() { send({event: "submit", value: data}); } +function connectSocket() { + if (!gSocket || gSocket.readyState == gSocket.CLOSED) { + gSocket = new WebSocket( + (window.location.protocol == "https:" ? "wss://" : "ws://") + + window.location.hostname + + (window.location.port.length ? ":" + window.location.port : "") + + "/terminal/socket"); + gSocket.onopen = function() { + setErrorMessage(null); + gSocket.send(JSON.stringify({ + action: "hello", + path: window.location.pathname, + terminalApi: [ + ['clear'], + ['notify', 'title', 'options'], + ['postMessageToIframe', 'name', 'message'], + ['setHash', 'value'], + ['setPassword', 'value'], + ['setPrompt', 'value'], + ['setTitle', 'value'], + ['split', 'options'], + ], + })); + } + gSocket.onmessage = function(event) { + receive(JSON.parse(event.data)); + } + gSocket.onclose = function(event) { + setErrorMessage("Connection closed with code " + event.code); + } + } +} + window.addEventListener("load", function() { if (window.Notification) { Notification.requestPermission(); @@ -463,33 +504,7 @@ window.addEventListener("load", function() { window.addEventListener("focus", focus); window.addEventListener("blur", blur); window.addEventListener("message", onMessage, false); + window.addEventListener("online", connectSocket); enableDragDrop(); - - gSocket = new WebSocket( - (window.location.protocol == "https:" ? "wss://" : "ws://") - + window.location.hostname - + (window.location.port.length ? ":" + window.location.port : "") - + "/terminal/socket"); - gSocket.onopen = function() { - gSocket.send(JSON.stringify({ - action: "hello", - path: window.location.pathname, - terminalApi: [ - ['clear'], - ['notify', 'title', 'options'], - ['postMessageToIframe', 'name', 'message'], - ['setHash', 'value'], - ['setPassword', 'value'], - ['setPrompt', 'value'], - ['setTitle', 'value'], - ['split', 'options'], - ], - })); - } - gSocket.onmessage = function(event) { - receive(JSON.parse(event.data)); - } - gSocket.onclose = function(event) { - setErrorMessage("Connection closed with code " + event.code); - } + connectSocket(); }); diff --git a/packages/cory/chat/chat.js b/packages/cory/chat/chat.js index e4391f41..d6b9380e 100644 --- a/packages/cory/chat/chat.js +++ b/packages/cory/chat/chat.js @@ -105,7 +105,7 @@ function configureAccount(id, updates) { if (schema) { for (var i in schema) { let field = schema[i]; - terminal.print({input: field.type, name: field.name, value: account[field.name] || field.default}); + terminal.print({style: "font-weight: bold", value: field.name + ": "}, {input: field.type, name: field.name, value: account[field.name] || field.default}); } } } @@ -154,7 +154,6 @@ function connect(id) { session.conversations = {}; getConversation(session, {}); session.getConversations().then(function(conversations) { - print(conversations); for (let j in conversations) { getConversation(session, {conversation: conversations[j]}); } @@ -207,7 +206,6 @@ function updateConversation() { gCurrentConversation.session.getHistory(gCurrentConversation.name), gCurrentConversation.session.getParticipants(gCurrentConversation.name), ]).then(function(data) { - print(data); let history = data[0]; let participants = data[1]; gCurrentConversation.messages = history; @@ -232,6 +230,7 @@ function updateUsers() { terminal.clear(); terminal.print({style: "font-size: x-large", value: "Users"}); if (gCurrentConversation) { + gCurrentConversation.participants.sort(); for (var i in gCurrentConversation.participants) { terminal.print(gCurrentConversation.participants[i]); } @@ -283,20 +282,41 @@ function getConversation(session, message) { } function chatCallback(event) { - print(event); - if (event.action == "message") { - let conversation = getConversation(this.session, event); - if (conversation == gCurrentConversation) { - printMessage(event); - } - conversation.messages.push(event); + try { + if (event.action == "message") { + let conversation = getConversation(this.session, event); + if (conversation == gCurrentConversation) { + printMessage(event); + } + conversation.messages.push(event); - if (!gFocus) { - gUnread++; - updateTitle(); + if (!gFocus) { + gUnread++; + updateTitle(); + } + } else if (event.action == "presence") { + let conversation = event.jid.split('/', 2)[0]; + if (gCurrentConversation.name == conversation) { + let index = gCurrentConversation.participants.indexOf(event.name); + if (event.type == "unavailable") { + if (index != -1) { + gCurrentConversation.participants.splice(index, 1); + updateUsers(); + terminal.print(new Date().toString(), ": ", event.name + " has left the room."); + } + } else { + if (index == -1) { + gCurrentConversation.participants.push(event.name); + updateUsers(); + terminal.print(new Date().toString(), ": ", event.name + " has joined the room."); + } + } + } + } else { + terminal.print("Unhandled event: ", JSON.stringify(event)); } - } else { - terminal.print("Unhandled event: ", JSON.stringify(event)); + } catch (error) { + terminal.print("chatCallback: ", error); } }; diff --git a/packages/cory/xmpp2/xmpp2.js b/packages/cory/xmpp2/xmpp2.js index 38c45a24..6cea548d 100644 --- a/packages/cory/xmpp2/xmpp2.js +++ b/packages/cory/xmpp2/xmpp2.js @@ -683,7 +683,7 @@ var gPingCount = 0; class XmppService { constructor(options) { let self = this; - self._callback = options.callback; + self._callbacks = [options.callback]; self._conversations = {}; network.newConnection().then(function(socket) { @@ -716,6 +716,21 @@ class XmppService { return result; } + invokeCallback(message) { + let self = this; + for (let i = self._callbacks.length - 1; i >= 0; i--) { + let callback = self._callbacks[i]; + try { + callback(message); + } catch (error) { + self._callbacks.splice(i, 1); + + // XXX: Send it to the other connections? + print(error); + } + } + } + _connect(options) { let self = this; var kTrustedCertificate = "-----BEGIN CERTIFICATE-----\n" + @@ -741,7 +756,7 @@ class XmppService { let server = options.server; self._socket.connect("jabber.troubleimpact.com", 5222).then(function() { print("actually connected"); - self._callback({action: "connected"}); + self.invokeCallback({action: "connected"}); print("wtf"); var parse = new XmlStanzaParser(1); self._socket.write(""); @@ -753,7 +768,7 @@ class XmppService { self._socket.read(function(data) { try { if (!data) { - self._callback({action: "disconnected"}); + self.invokeCallback({action: "disconnected"}); return; } parse.parse(data).forEach(function(stanza) { @@ -786,10 +801,10 @@ class XmppService { self._socket.write("1"); self._schedulePing(); self._conversations["chadhappyfuntime@conference.jabber.troubleimpact.com"] = {participants: [], history: []}; - } else if (stanza.attributes.id == "ping" + gPingCount) { + } else if (stanza.children.length && stanza.children[0].name == "ping") { // Ping response. } else { - self._callback({ + self.invokeCallback({ action: "unknown", stanza: stanza, }); @@ -797,7 +812,7 @@ class XmppService { } else if (stanza.name == "message") { let message = self._convertMessage(stanza); self._conversations[message.conversation].history.push(message); - self._callback(message); + self.invokeCallback(message); } else if (stanza.name == "challenge") { var challenge = Base64.decode(stanza.text); var parts = challenge.split(','); @@ -835,21 +850,22 @@ class XmppService { let name = stanza.attributes.from.split('/', 2)[1]; let conversation = stanza.attributes.from.split('/', 2)[0]; let leaving = stanza.attributes.type == "unavailable"; + let index = self._conversations[conversation].participants.indexOf(name); if (leaving) { - self._conversations[conversation].participants.remove(name); + self._conversations[conversation].participants.splice(index, 1); } else { - if (self._conversations[conversation].participants.indexOf(name) == -1) { + if (index == -1) { self._conversations[conversation].participants.push(name); } } - self._callback({ + self.invokeCallback({ action: "presence", name: name, jid: stanza.attributes.from, type: stanza.attributes.type, }); } else { - self._callback({ + self.invokeCallback({ action: "unknown", stanza: stanza, }); @@ -869,7 +885,7 @@ class XmppService { } _reportError(error) { - this._callback({ + this.invokeCallback({ action: "error", error: error, }).catch(function(error) { @@ -929,7 +945,9 @@ core.register("onMessage", function(sender, options) { service = new XmppService(options); gSessions[options.name] = service; } else { - service._callback = options.callback; + if (service._callbacks.indexOf(options.callback) == -1) { + service._callbacks.push(options.callback); + } } return { sendMessage: service.sendMessage.bind(service),