A detachable multi-protocol chat client is starting to come together.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3232 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
4fe5e9e39e
commit
09a283fdbc
@ -4,6 +4,7 @@ var gFocus = true;
|
|||||||
var gUnread = 0;
|
var gUnread = 0;
|
||||||
var gPresence = {};
|
var gPresence = {};
|
||||||
let gSessions = {};
|
let gSessions = {};
|
||||||
|
let gState = {};
|
||||||
let gCurrentConversation;
|
let gCurrentConversation;
|
||||||
|
|
||||||
function updateTitle() {
|
function updateTitle() {
|
||||||
@ -11,6 +12,7 @@ function updateTitle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let kAccountsKey = JSON.stringify(["accounts", core.user.name]);
|
let kAccountsKey = JSON.stringify(["accounts", core.user.name]);
|
||||||
|
let kStateKey = JSON.stringify(["state", core.user.name]);
|
||||||
|
|
||||||
function runCommand(data) {
|
function runCommand(data) {
|
||||||
if (data.action == "addAccount") {
|
if (data.action == "addAccount") {
|
||||||
@ -27,12 +29,18 @@ function runCommand(data) {
|
|||||||
} else if (data.action == "disconnect") {
|
} else if (data.action == "disconnect") {
|
||||||
disconnect(data.id);
|
disconnect(data.id);
|
||||||
} else if (data.action == "window") {
|
} else if (data.action == "window") {
|
||||||
gCurrentConversation = gSessions[data.account].conversations[data.conversation];
|
setWindow(data.account, data.conversation);
|
||||||
updateConversation();
|
|
||||||
updateWindows();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWindow(accountId, conversation) {
|
||||||
|
gState.window = {account: accountId, conversation: conversation};
|
||||||
|
database.set(kStateKey, JSON.stringify(gState));
|
||||||
|
gCurrentConversation = gSessions[accountId].conversations[conversation];
|
||||||
|
updateConversation();
|
||||||
|
updateWindows();
|
||||||
|
}
|
||||||
|
|
||||||
function addAccount() {
|
function addAccount() {
|
||||||
return database.get(kAccountsKey).then(function(data) {
|
return database.get(kAccountsKey).then(function(data) {
|
||||||
let accounts = data ? JSON.parse(data) : [];
|
let accounts = data ? JSON.parse(data) : [];
|
||||||
@ -152,10 +160,11 @@ function connect(id) {
|
|||||||
self.session = session;
|
self.session = session;
|
||||||
gSessions[id] = session;
|
gSessions[id] = session;
|
||||||
session.conversations = {};
|
session.conversations = {};
|
||||||
getConversation(session, {});
|
session.account = account;
|
||||||
|
getConversation(session, null);
|
||||||
session.getConversations().then(function(conversations) {
|
session.getConversations().then(function(conversations) {
|
||||||
for (let j in conversations) {
|
for (let j in conversations) {
|
||||||
getConversation(session, {conversation: conversations[j]});
|
getConversation(session, conversations[j]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -208,13 +217,18 @@ function updateConversation() {
|
|||||||
]).then(function(data) {
|
]).then(function(data) {
|
||||||
let history = data[0];
|
let history = data[0];
|
||||||
let participants = data[1];
|
let participants = data[1];
|
||||||
gCurrentConversation.messages = history;
|
gCurrentConversation.messages = history || [];
|
||||||
gCurrentConversation.participants = participants;
|
gCurrentConversation.participants = participants || [];
|
||||||
terminal.cork();
|
terminal.cork();
|
||||||
terminal.select("terminal");
|
terminal.select("terminal");
|
||||||
terminal.clear();
|
terminal.clear();
|
||||||
for (var i in gCurrentConversation.messages) {
|
for (var i in gCurrentConversation.messages) {
|
||||||
printMessage(gCurrentConversation.messages[i]);
|
let message = gCurrentConversation.messages[i];
|
||||||
|
if (message.action == "message") {
|
||||||
|
printMessage(message.message);
|
||||||
|
} else {
|
||||||
|
terminal.print(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateUsers();
|
updateUsers();
|
||||||
terminal.uncork();
|
terminal.uncork();
|
||||||
@ -255,65 +269,81 @@ terminal.select("terminal");
|
|||||||
terminal.print("~Friends Chat");
|
terminal.print("~Friends Chat");
|
||||||
terminal.uncork();
|
terminal.uncork();
|
||||||
|
|
||||||
function getConversation(session, message) {
|
function getConversation(session, conversationName) {
|
||||||
let result;
|
let result;
|
||||||
for (var i in gSessions) {
|
let key = conversationName || "";
|
||||||
if (session == gSessions[i]) {
|
if (!session.conversations) {
|
||||||
let key = message.conversation || message.from || "";
|
session.conversations = {};
|
||||||
if (!session.conversations[key]) {
|
}
|
||||||
session.conversations[key] = {
|
if (!session.conversations[key]) {
|
||||||
session: session,
|
session.conversations[key] = {
|
||||||
name: key,
|
session: session,
|
||||||
messages: [],
|
name: key,
|
||||||
sendMessage: function(message) {
|
messages: [],
|
||||||
return session.sendMessage(key, message);
|
sendMessage: function(message) {
|
||||||
},
|
return session.sendMessage(key, message);
|
||||||
};
|
},
|
||||||
updateWindows();
|
};
|
||||||
|
updateWindows();
|
||||||
|
}
|
||||||
|
result = session.conversations[key];
|
||||||
|
if (result) {
|
||||||
|
if (!gCurrentConversation) {
|
||||||
|
if (!gState.window) {
|
||||||
|
setWindow(session.account.id, key);
|
||||||
|
} else if (gState.window.account = session.account.id && gState.window.conversation == key) {
|
||||||
|
setWindow(session.account.id, key);
|
||||||
}
|
}
|
||||||
result = session.conversations[key];
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result && !gCurrentConversation) {
|
|
||||||
gCurrentConversation = result;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function printToConversation(conversation, message, notify) {
|
||||||
|
if (conversation == gCurrentConversation) {
|
||||||
|
if (message.action == "message") {
|
||||||
|
printMessage(message.message);
|
||||||
|
} else {
|
||||||
|
terminal.print(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (conversation) {
|
||||||
|
conversation.messages.push(message);
|
||||||
|
}
|
||||||
|
if (notify && !gFocus) {
|
||||||
|
gUnread++;
|
||||||
|
updateTitle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function chatCallback(event) {
|
function chatCallback(event) {
|
||||||
try {
|
try {
|
||||||
if (event.action == "message") {
|
if (event.action == "message") {
|
||||||
let conversation = getConversation(this.session, event);
|
let conversation = getConversation(this.session, event.conversation);
|
||||||
if (conversation == gCurrentConversation) {
|
printToConversation(conversation, event);
|
||||||
printMessage(event);
|
|
||||||
}
|
|
||||||
conversation.messages.push(event);
|
|
||||||
|
|
||||||
if (!gFocus) {
|
|
||||||
gUnread++;
|
|
||||||
updateTitle();
|
|
||||||
}
|
|
||||||
} else if (event.action == "presence") {
|
} else if (event.action == "presence") {
|
||||||
let conversation = event.jid.split('/', 2)[0];
|
let conversation = getConversation(this.session, event.conversation);
|
||||||
if (gCurrentConversation.name == conversation) {
|
let index = conversation.participants.indexOf(event.user);
|
||||||
let index = gCurrentConversation.participants.indexOf(event.name);
|
if (event.presence == "unavailable") {
|
||||||
if (event.type == "unavailable") {
|
if (index != -1) {
|
||||||
if (index != -1) {
|
conversation.participants.splice(index, 1);
|
||||||
gCurrentConversation.participants.splice(index, 1);
|
if (conversation == gCurrentConversation) {
|
||||||
updateUsers();
|
updateUsers();
|
||||||
terminal.print(new Date().toString(), ": ", event.name + " has left the room.");
|
|
||||||
}
|
}
|
||||||
} else {
|
printToConversation(conversation, [new Date().toString(), ": ", event.user + " has left the room."]);
|
||||||
if (index == -1) {
|
}
|
||||||
gCurrentConversation.participants.push(event.name);
|
} else {
|
||||||
|
if (index == -1) {
|
||||||
|
conversation.participants.push(event.user);
|
||||||
|
if (conversation == gCurrentConversation) {
|
||||||
updateUsers();
|
updateUsers();
|
||||||
terminal.print(new Date().toString(), ": ", event.name + " has joined the room.");
|
|
||||||
}
|
}
|
||||||
|
printToConversation(conversation, [new Date().toString(), ": ", event.user + " has joined the room."]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
terminal.print("Unhandled event: ", JSON.stringify(event));
|
let conversation = getConversation(this.session, event.conversation);
|
||||||
|
printToConversation(conversation, ["Unhandled event: ", JSON.stringify(event)]);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
terminal.print("chatCallback: ", error);
|
terminal.print("chatCallback: ", error);
|
||||||
@ -391,8 +421,9 @@ core.register("blur", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Connect all accounts on start.
|
// Connect all accounts on start.
|
||||||
Promise.all([database.get(kAccountsKey), core.getPackages()]).then(function(results) {
|
Promise.all([database.get(kAccountsKey), database.get(kStateKey)]).then(function(results) {
|
||||||
let accounts = results[0] ? JSON.parse(results[0]) : [];
|
let accounts = results[0] ? JSON.parse(results[0]) : [];
|
||||||
|
gState = results[1] ? JSON.parse(results[1]) : gState;
|
||||||
for (let i in accounts) {
|
for (let i in accounts) {
|
||||||
connect(accounts[i].id);
|
connect(accounts[i].id);
|
||||||
}
|
}
|
||||||
|
140
packages/cory/irc/irc.js
Normal file
140
packages/cory/irc/irc.js
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
//! {
|
||||||
|
//! "permissions": [
|
||||||
|
//! "network"
|
||||||
|
//! ],
|
||||||
|
//! "chat": {
|
||||||
|
//! "version": 1,
|
||||||
|
//! "settings": [
|
||||||
|
//! {"name": "user", "type": "text"},
|
||||||
|
//! {"name": "realName", "type": "text"},
|
||||||
|
//! {"name": "password", "type": "password"},
|
||||||
|
//! {"name": "nick", "type": "text"},
|
||||||
|
//! {"name": "server", "type": "text"},
|
||||||
|
//! {"name": "port", "type": "text"},
|
||||||
|
//! {"name": "autoJoinChannels", "type": "text"}
|
||||||
|
//! ]
|
||||||
|
//! },
|
||||||
|
//! "require": [
|
||||||
|
//! "libchat"
|
||||||
|
//! ]
|
||||||
|
//! }
|
||||||
|
|
||||||
|
let ChatService = require("libchat").ChatService;
|
||||||
|
|
||||||
|
class IrcService {
|
||||||
|
constructor(options) {
|
||||||
|
let self = this;
|
||||||
|
self._service = new ChatService(options.callback);
|
||||||
|
self._name = options.name;
|
||||||
|
self._nick = options.nick;
|
||||||
|
|
||||||
|
network.newConnection().then(function(socket) {
|
||||||
|
self._socket = socket;
|
||||||
|
return self._connect(options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_send(line) {
|
||||||
|
return this._socket.write(line + "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
_receivedLine(originalLine) {
|
||||||
|
try {
|
||||||
|
let line = originalLine;
|
||||||
|
let prefix;
|
||||||
|
if (line.charAt(0) == ":") {
|
||||||
|
let space = line.indexOf(" ");
|
||||||
|
prefix = line.substring(1, space);
|
||||||
|
line = line.substring(space + 1);
|
||||||
|
}
|
||||||
|
let lineNoPrefix = line;
|
||||||
|
let remainder;
|
||||||
|
let colon = line.indexOf(" :");
|
||||||
|
if (colon != -1) {
|
||||||
|
remainder = line.substring(colon + 2);
|
||||||
|
line = line.substring(0, colon);
|
||||||
|
}
|
||||||
|
let parts = line.split(" ");
|
||||||
|
if (remainder) {
|
||||||
|
parts.push(remainder);
|
||||||
|
}
|
||||||
|
|
||||||
|
let conversation = "";
|
||||||
|
if (parts[0] == "PRIVMSG" || parts[0] == "NOTICE") {
|
||||||
|
// Is it a channel type?
|
||||||
|
if ("&#!+.".indexOf(parts[1].charAt(0)) != -1) {
|
||||||
|
conversation = parts[1];
|
||||||
|
} else {
|
||||||
|
conversation = prefix.split('!')[0];
|
||||||
|
}
|
||||||
|
this._service.notifyMessageReceived(conversation, {
|
||||||
|
from: prefix.split('!')[0],
|
||||||
|
message: parts[parts.length - 1],
|
||||||
|
type: parts[0],
|
||||||
|
});
|
||||||
|
} else if (parts[0] == "PING") {
|
||||||
|
parts[0] = "PONG";
|
||||||
|
this._send(parts.join(" "));
|
||||||
|
} else if (parts[0] == "JOIN") {
|
||||||
|
let person = prefix.split('!')[0];
|
||||||
|
let conversation = parts[1];
|
||||||
|
this._service.notifyPresenceChanged(conversation, person, "present");
|
||||||
|
} else if (parts[0] == "JOIN") {
|
||||||
|
let person = prefix.split('!')[0];
|
||||||
|
let conversation = parts[1];
|
||||||
|
this._service.notifyPresenceChanged(conversation, person, "unavailable");
|
||||||
|
} else {
|
||||||
|
this._service.notifyMessageReceived("", {from: prefix, message: lineNoPrefix});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this._service.reportError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_connect(options) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
let readBuffer = "";
|
||||||
|
self._socket.read(function(data) {
|
||||||
|
if (data) {
|
||||||
|
readBuffer += data;
|
||||||
|
let end = readBuffer.indexOf("\n");
|
||||||
|
while (end != -1) {
|
||||||
|
let line = readBuffer.substring(0, end);
|
||||||
|
if (line.charAt(line.length - 1) == "\r") {
|
||||||
|
line = line.substring(0, line.length - 1);
|
||||||
|
}
|
||||||
|
readBuffer = readBuffer.substring(end + 1);
|
||||||
|
self._receivedLine(line);
|
||||||
|
end = readBuffer.indexOf("\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self._service.notifyStateChanged("disconnected");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return self._socket.connect(options.server, options.port).then(function() {
|
||||||
|
self._service.notifyStateChanged("connected");
|
||||||
|
self._send("USER " + options.user + " 0 * :" + options.realName);
|
||||||
|
self._send("NICK " + options.nick);
|
||||||
|
}).catch(self._service.reportError);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(target, text) {
|
||||||
|
if (!target) {
|
||||||
|
this._socket.write(text + "\r\n");
|
||||||
|
} else {
|
||||||
|
this._socket.write("PRIVMSG " + target + " :" + text + "\r\n");
|
||||||
|
}
|
||||||
|
this._service.notifyMessageReceived(target || "", {from: self._nick, message: text, timestamp: new Date().toString()});
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
this._send("QUIT");
|
||||||
|
this._socket.close();
|
||||||
|
this._service.notifyStateChanged("disconnected");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ChatService.handleMessages(IrcService);
|
126
packages/cory/libchat/libchat.js
Normal file
126
packages/cory/libchat/libchat.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.ChatService = class {
|
||||||
|
static handleMessages(serviceClass) {
|
||||||
|
let self = this;
|
||||||
|
let sessions = {};
|
||||||
|
|
||||||
|
core.register("onMessage", function(sender, options) {
|
||||||
|
let service = sessions[options.name];
|
||||||
|
if (!service) {
|
||||||
|
service = new serviceClass(options);
|
||||||
|
sessions[options.name] = service;
|
||||||
|
} else {
|
||||||
|
service._service.addCallback(options.callback);
|
||||||
|
}
|
||||||
|
return service._service.makeInterface(service);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(callback) {
|
||||||
|
this._callbacks = [callback];
|
||||||
|
this._conversations = {};
|
||||||
|
this._state = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInterface(service) {
|
||||||
|
let self = this;
|
||||||
|
return {
|
||||||
|
sendMessage: service.sendMessage.bind(service),
|
||||||
|
disconnect: service.disconnect.bind(service),
|
||||||
|
|
||||||
|
getConversations: self.getConversations.bind(self),
|
||||||
|
getHistory: self.getHistory.bind(self),
|
||||||
|
getParticipants: self.getParticipants.bind(self),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
addCallback(callback) {
|
||||||
|
if (this._callbacks.indexOf(callback) == -1) {
|
||||||
|
this._callbacks.push(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_getConversation(conversation) {
|
||||||
|
if (!this._conversations[conversation]) {
|
||||||
|
this._conversations[conversation] = {history: [], participants: []};
|
||||||
|
}
|
||||||
|
return this._conversations[conversation];
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyMessageReceived(conversation, message) {
|
||||||
|
let fullMessage = {action: "message", conversation: conversation || "", message: message};
|
||||||
|
this._getConversation(conversation || "").history.push(fullMessage);
|
||||||
|
this._invokeCallback(fullMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyPresenceChanged(conversation, user, state) {
|
||||||
|
let leaving = state == "unavailable";
|
||||||
|
let participants = this._getConversation(conversation).participants;
|
||||||
|
let index = participants.indexOf(user);
|
||||||
|
if (leaving) {
|
||||||
|
participants.splice(index, 1);
|
||||||
|
} else if (index == -1) {
|
||||||
|
participants.push(user);
|
||||||
|
}
|
||||||
|
this._invokeCallback({
|
||||||
|
action: "presence",
|
||||||
|
conversation: conversation,
|
||||||
|
user: user,
|
||||||
|
presence: state,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyStateChanged(state) {
|
||||||
|
this._state = state;
|
||||||
|
this._invokeCallback({action: state});
|
||||||
|
}
|
||||||
|
|
||||||
|
reportError(error) {
|
||||||
|
this._invokeCallback({
|
||||||
|
action: "error",
|
||||||
|
error: error,
|
||||||
|
}).catch(function(error) {
|
||||||
|
print(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isConversation(conversation) {
|
||||||
|
return this._conversations[conversation] != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getConversations() {
|
||||||
|
return Object.keys(this._conversations);
|
||||||
|
}
|
||||||
|
|
||||||
|
getHistory(conversation) {
|
||||||
|
let result;
|
||||||
|
if (this._conversations[conversation]) {
|
||||||
|
result = this._conversations[conversation].history;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
getParticipants(conversation) {
|
||||||
|
let result;
|
||||||
|
if (this._conversations[conversation]) {
|
||||||
|
result = this._conversations[conversation].participants;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,10 @@
|
|||||||
//! {"name": "resource", "type": "text", "default": "tildefriends"},
|
//! {"name": "resource", "type": "text", "default": "tildefriends"},
|
||||||
//! {"name": "server", "type": "text"}
|
//! {"name": "server", "type": "text"}
|
||||||
//! ]
|
//! ]
|
||||||
//! }
|
//! },
|
||||||
|
//! "require": [
|
||||||
|
//! "libchat"
|
||||||
|
//! ]
|
||||||
//! }
|
//! }
|
||||||
|
|
||||||
// md5.js
|
// md5.js
|
||||||
@ -678,57 +681,23 @@ XmlStanzaParser.prototype.parseNode = function(node) {
|
|||||||
|
|
||||||
// end xmpp.js
|
// end xmpp.js
|
||||||
|
|
||||||
|
let ChatService = require("libchat").ChatService;
|
||||||
|
|
||||||
var gPingCount = 0;
|
var gPingCount = 0;
|
||||||
|
|
||||||
class XmppService {
|
class XmppService {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
let self = this;
|
let self = this;
|
||||||
self._callbacks = [options.callback];
|
self._service = new ChatService(options.callback);
|
||||||
self._conversations = {};
|
|
||||||
|
|
||||||
network.newConnection().then(function(socket) {
|
network.newConnection().then(function(socket) {
|
||||||
self._socket = socket;
|
self._socket = socket;
|
||||||
return self._connect(options);
|
return self._connect(options);
|
||||||
}).catch(self._reportError);
|
}).catch(self._service.reportError);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage(to, message) {
|
sendMessage(to, message) {
|
||||||
this._socket.write("<message type='groupchat' to='" + xmlEncode(to) + "'><body>" + xmlEncode(message) + "</body></message>");
|
this._socket.write("<message type='groupchat' to='" + xmlEncode(to) + "'><body>" + xmlEncode(message) + "</body></message>").catch(this._service.reportError);
|
||||||
}
|
|
||||||
|
|
||||||
getConversations() {
|
|
||||||
return Object.keys(this._conversations);
|
|
||||||
}
|
|
||||||
|
|
||||||
getParticipants(conversation) {
|
|
||||||
let result;
|
|
||||||
if (this._conversations[conversation]) {
|
|
||||||
result = this._conversations[conversation].participants;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
getHistory(conversation) {
|
|
||||||
let result;
|
|
||||||
if (this._conversations[conversation]) {
|
|
||||||
result = this._conversations[conversation].history;
|
|
||||||
}
|
|
||||||
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) {
|
_connect(options) {
|
||||||
@ -755,9 +724,7 @@ class XmppService {
|
|||||||
let password = options.password;
|
let password = options.password;
|
||||||
let server = options.server;
|
let server = options.server;
|
||||||
self._socket.connect("jabber.troubleimpact.com", 5222).then(function() {
|
self._socket.connect("jabber.troubleimpact.com", 5222).then(function() {
|
||||||
print("actually connected");
|
self._service.notifyStateChanged("connected");
|
||||||
self.invokeCallback({action: "connected"});
|
|
||||||
print("wtf");
|
|
||||||
var parse = new XmlStanzaParser(1);
|
var parse = new XmlStanzaParser(1);
|
||||||
self._socket.write("<?xml version='1.0'?>");
|
self._socket.write("<?xml version='1.0'?>");
|
||||||
self._socket.write("<stream:stream to='" + xmlEncode(server) + "' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>");
|
self._socket.write("<stream:stream to='" + xmlEncode(server) + "' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>");
|
||||||
@ -768,7 +735,7 @@ class XmppService {
|
|||||||
self._socket.read(function(data) {
|
self._socket.read(function(data) {
|
||||||
try {
|
try {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
self.invokeCallback({action: "disconnected"});
|
self._service.notifyStateChanged("disconnected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
parse.parse(data).forEach(function(stanza) {
|
parse.parse(data).forEach(function(stanza) {
|
||||||
@ -800,19 +767,26 @@ class XmppService {
|
|||||||
} else if (stanza.attributes.id == "session0") {
|
} else if (stanza.attributes.id == "session0") {
|
||||||
self._socket.write("<presence to='chadhappyfuntime@conference.jabber.troubleimpact.com/" + userName + "'><priority>1</priority><x xmlns='http://jabber.org/protocol/muc'/></presence>");
|
self._socket.write("<presence to='chadhappyfuntime@conference.jabber.troubleimpact.com/" + userName + "'><priority>1</priority><x xmlns='http://jabber.org/protocol/muc'/></presence>");
|
||||||
self._schedulePing();
|
self._schedulePing();
|
||||||
self._conversations["chadhappyfuntime@conference.jabber.troubleimpact.com"] = {participants: [], history: []};
|
//self._conversations["chadhappyfuntime@conference.jabber.troubleimpact.com"] = {participants: [], history: []};
|
||||||
} else if (stanza.children.length && stanza.children[0].name == "ping") {
|
} else if (stanza.children.length && stanza.children[0].name == "ping") {
|
||||||
// Ping response.
|
// Ping response.
|
||||||
} else {
|
} else {
|
||||||
self.invokeCallback({
|
self._service.notifyMessageReceived(null, {unknown: stanza});
|
||||||
action: "unknown",
|
|
||||||
stanza: stanza,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else if (stanza.name == "message") {
|
} else if (stanza.name == "message") {
|
||||||
let message = self._convertMessage(stanza);
|
let message = self._convertMessage(stanza);
|
||||||
self._conversations[message.conversation].history.push(message);
|
let conversation = stanza.attributes.from;
|
||||||
self.invokeCallback(message);
|
if (conversation && conversation.indexOf('/') != -1) {
|
||||||
|
conversation = conversation.split("/")[1];
|
||||||
|
}
|
||||||
|
if (stanza.attributes.type == "groupchat") {
|
||||||
|
if (self._service.isConversation(stanza.attributes.to.split("/")[0])) {
|
||||||
|
conversation = stanza.attributes.to.split("/")[0];
|
||||||
|
} else if (self._service.isConversation(stanza.attributes.from.split("/")[0])) {
|
||||||
|
conversation = stanza.attributes.from.split("/")[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self._service.notifyMessageReceived(conversation, message);
|
||||||
} else if (stanza.name == "challenge") {
|
} else if (stanza.name == "challenge") {
|
||||||
var challenge = Base64.decode(stanza.text);
|
var challenge = Base64.decode(stanza.text);
|
||||||
var parts = challenge.split(',');
|
var parts = challenge.split(',');
|
||||||
@ -849,33 +823,16 @@ class XmppService {
|
|||||||
} else if (stanza.name == "presence") {
|
} else if (stanza.name == "presence") {
|
||||||
let name = stanza.attributes.from.split('/', 2)[1];
|
let name = stanza.attributes.from.split('/', 2)[1];
|
||||||
let conversation = stanza.attributes.from.split('/', 2)[0];
|
let conversation = stanza.attributes.from.split('/', 2)[0];
|
||||||
let leaving = stanza.attributes.type == "unavailable";
|
self._service.notifyPresenceChanged(conversation, name, stanza.attributes.type);
|
||||||
let index = self._conversations[conversation].participants.indexOf(name);
|
|
||||||
if (leaving) {
|
|
||||||
self._conversations[conversation].participants.splice(index, 1);
|
|
||||||
} else {
|
|
||||||
if (index == -1) {
|
|
||||||
self._conversations[conversation].participants.push(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.invokeCallback({
|
|
||||||
action: "presence",
|
|
||||||
name: name,
|
|
||||||
jid: stanza.attributes.from,
|
|
||||||
type: stanza.attributes.type,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
self.invokeCallback({
|
self._service.notifyMessageReceived(null, {unknown: stanza});
|
||||||
action: "unknown",
|
|
||||||
stanza: stanza,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
self._reportError(error);
|
self._service.reportError(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).catch(self._reportError);
|
}).catch(self._service.reportError);
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect() {
|
disconnect() {
|
||||||
@ -884,15 +841,6 @@ class XmppService {
|
|||||||
delete gSessions[self._name];
|
delete gSessions[self._name];
|
||||||
}
|
}
|
||||||
|
|
||||||
_reportError(error) {
|
|
||||||
this.invokeCallback({
|
|
||||||
action: "error",
|
|
||||||
error: error,
|
|
||||||
}).catch(function(error) {
|
|
||||||
print(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_convertMessage(stanza) {
|
_convertMessage(stanza) {
|
||||||
let self = this;
|
let self = this;
|
||||||
let text;
|
let text;
|
||||||
@ -909,18 +857,8 @@ class XmppService {
|
|||||||
if (from && from.indexOf('/') != -1) {
|
if (from && from.indexOf('/') != -1) {
|
||||||
from = from.split("/")[1];
|
from = from.split("/")[1];
|
||||||
}
|
}
|
||||||
let conversation = from;
|
|
||||||
if (stanza.attributes.type == "groupchat") {
|
|
||||||
if (self._conversations[stanza.attributes.to.split("/")[0]]) {
|
|
||||||
conversation = stanza.attributes.to.split("/")[0];
|
|
||||||
} else if (self._conversations[stanza.attributes.from.split("/")[0]]) {
|
|
||||||
conversation = stanza.attributes.from.split("/")[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let message = {
|
let message = {
|
||||||
action: "message",
|
|
||||||
from: from,
|
from: from,
|
||||||
conversation: conversation,
|
|
||||||
message: text,
|
message: text,
|
||||||
stanza: stanza,
|
stanza: stanza,
|
||||||
timestamp: now,
|
timestamp: now,
|
||||||
@ -937,23 +875,4 @@ class XmppService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let gSessions = {};
|
ChatService.handleMessages(XmppService);
|
||||||
|
|
||||||
core.register("onMessage", function(sender, options) {
|
|
||||||
let service = gSessions[options.name];
|
|
||||||
if (!service) {
|
|
||||||
service = new XmppService(options);
|
|
||||||
gSessions[options.name] = service;
|
|
||||||
} else {
|
|
||||||
if (service._callbacks.indexOf(options.callback) == -1) {
|
|
||||||
service._callbacks.push(options.callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
sendMessage: service.sendMessage.bind(service),
|
|
||||||
getConversations: service.getConversations.bind(service),
|
|
||||||
getHistory: service.getHistory.bind(service),
|
|
||||||
getParticipants: service.getParticipants.bind(service),
|
|
||||||
disconnect: service.disconnect.bind(service),
|
|
||||||
};
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user