tildefriends/packages/cory/libchat/libchat.js
2016-08-29 15:17:36 +00:00

161 lines
3.7 KiB
JavaScript

"use strict";
//! {"category": "libraries"}
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;
this._maxHistory = 64;
}
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(function(error) {
self._callbacks.splice(i, 1);
// XXX: Send it to the other connections?
print(error);
});
} 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];
}
_pushMessage(conversation, message) {
let history = this._getConversation(conversation || "").history;
history.push(message);
if (history.length > this._maxHistory) {
history.splice(0, history.length - this._maxHistory);
}
}
notifyMessageReceived(conversation, message) {
let fullMessage = {action: "message", conversation: conversation || "", message: message};
this._pushMessage(conversation, fullMessage);
this._invokeCallback(fullMessage);
}
notifyPresenceChanged(conversation, user, state) {
let leaving = state == "unavailable";
let participants = this._getConversation(conversation).participants;
let index = participants.indexOf(user);
let different = true;
if (leaving) {
participants.splice(index, 1);
} else if (index == -1) {
participants.push(user);
} else {
different = false;
}
let message = {
action: "presence",
conversation: conversation,
user: user,
presence: state,
};
if (different) {
this._pushMessage(conversation, message);
}
this._invokeCallback(message);
}
notifyParticipantList(conversation, participants) {
let current = this._getConversation(conversation).participants;
for (let i in current) {
if (!participants[i]) {
this.notifyPresenceChanged(conversation, i, "unavailable");
}
}
for (let i in participants) {
this.notifyPresenceChanged(conversation, i, participants[i]);
}
}
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;
}
}