Commit f5c87f9c authored by Eugene Shen's avatar Eugene Shen

Use replicate storage and request smaller bundles

Store all chats as Text Posts using ERP5 in a replicate storage.
Synchronize divergent chats through a three-step process:
1. send doubler (request a request from the host)
   receive request (get dict of host's last-seen messages)
2. send archive (give all new messages to the host)
   receive doubler (get after host is fully updated)
3. send request (give dict of your last-seen messages)
   receive archive (get all new messages from all peers)

This means that Space Chat now synchronizes correctly even when
peers disconnect from each other, and all chat messages will
eventually be stored on ERP5 as soon as one peer reconnects.
parent bb0d31e5
......@@ -89,7 +89,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>adapter.js</string> </value>
<value> <string>adapter_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -89,7 +89,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>fast_priority_queue.js</string> </value>
<value> <string>fast_priority_queue_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -90,7 +90,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_chat.css</string> </value>
<value> <string>gadget_erp5_chat_css</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -93,7 +93,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_chat.html</string> </value>
<value> <string>gadget_erp5_chat_html</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -15,8 +15,28 @@
})
.push(function (my_gadget) {
return my_gadget.createJio({
type: "indexeddb",
database: "officejs_chat"
type: "replicate",
query: {
query: 'portal_type: "Text Post"',
limit: [0, 1000000000]
},
local_sub_storage: {
type: "query",
sub_storage: {
type: "uuid",
sub_storage: {
type: "indexeddb",
database: "officejs_chat"
}
}
},
remote_sub_storage: {
type: "erp5",
url: "https://softinst75770.host.vifib.net/erp5/web_site_module/web_chat/hateoas/",
default_view_reference: "view"
},
conflict_handling: 2,
use_remote_post: true
});
});
})
......
......@@ -68,6 +68,7 @@
<value>
<tuple>
<string>classification/collaborative/team</string>
<string>contributor/person_module/1</string>
</tuple>
</value>
</item>
......@@ -89,7 +90,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_chat.js</string> </value>
<value> <string>gadget_erp5_chat_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -94,7 +94,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_chat_login.html</string> </value>
<value> <string>gadget_erp5_chat_login_html</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -90,7 +90,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_chat_login.js</string> </value>
<value> <string>gadget_erp5_chat_login_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -12,6 +12,8 @@
</head>
<body>
<h3>Chat List</h3>
<p class="error">
</p>
<div class="chat">
</div>
<form class="send-form">
......
......@@ -94,7 +94,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_chat_panel.html</string> </value>
<value> <string>gadget_erp5_chat_panel_html</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -2,8 +2,12 @@
/* Abstract Data Types:
* message is a JSON object representing a message with all its metadata.
* message_string is JSON.stringify(message) for sending over WebRTC.
* chat is messageToChat(message) for displaying an element in the chat log.
* Message Types:
* message is a typical message, with an author and timestamp.
* notification is a system-generated message, with no author.
* bundle is a list of new messages to be added to the local archive.
* request is a dictionary of the times of the last messages of each peer.
*/
/* Program Workflow:
......@@ -26,7 +30,7 @@
*/
/* Summary:
* - getLocalArchive takes the archive, calls storeList on each message
* - getLocalArchive takes archive, calls storeList and appendChat on each
* - sendLocalArchive sends the list to peer
* - getRemoteArchive gets a list from peer, calls storeArchive on each
* - deployMessage sends a message to peer, calls getMessage
......@@ -41,12 +45,63 @@
console.log(error);
}
function logQueue(action) {
return new RSVP.Queue()
.push(function () {
return action;
})
.push(null, logError);
}
function pollUntilNotNull(
my_gadget, delay_ms, timeout_ms,
nullableFunction, callbackFunction) {
if (callbackFunction === undefined) {
callbackFunction = function () {};
}
return new RSVP.Queue()
.push(function () {
return nullableFunction();
})
.push(function (my_result) {
if (my_result !== null) {
return callbackFunction(my_result);
} else {
return RSVP.any([
RSVP.timeout(timeout_ms),
promiseDoWhile(function () {
return new RSVP.Queue()
.push(function () {
return RSVP.delay(delay_ms);
})
.push(function () {
return nullableFunction();
})
.push(function (my_result) {
if (my_result === null) {
return null;
} else {
return callbackFunction(my_result);
}
})
.push(function (nullable) {
return nullable === null;
})
.push(null, logError);
})
]);
}
});
}
function getTime(message) {
return new Date(message.time).getTime();
}
function sameMessage(lhs, rhs) {
return JSON.stringify(lhs) === JSON.stringify(rhs);
return lhs !== undefined && rhs !== undefined && lhs.name === rhs.name &&
lhs.content === rhs.content && lhs.folder === rhs.folder &&
lhs.room === rhs.room && getTime(lhs) === getTime(rhs);
}
function stringEndsWith(string, suffix) {
......@@ -88,15 +143,16 @@
}
// Create new message from its type and content
function createMessage(gadget, type, content) {
function createMessage(gadget, type, content, peer_source) {
return {
type: type,
name: gadget.state_parameter_dict.name,
folder: gadget.state_parameter_dict.folder,
room: gadget.state_parameter_dict.room,
time: new Date(),
content: content
};
content: content,
peer_source: peer_source
}
}
// Translate message to chat, in some HTML element
......@@ -154,6 +210,11 @@
// Add message to the list and append chat to chat box
function storeList(gadget, message) {
var last_time = gadget.state_parameter_dict.last_message_dict[message.name];
if (last_time === undefined || last_time < getTime(message)) {
gadget.state_parameter_dict.last_message_dict[message.name] =
getTime(message);
}
gadget.state_parameter_dict.message_list.push(message);
}
......@@ -224,12 +285,15 @@
return new RSVP.Queue()
.push(function () {
gadget.state_parameter_dict = {
initialized: null,
notified_join: false,
name: null,
folder: null,
room: null,
message_list: [],
alert_icon: "http://icons.iconarchive.com/icons/iconarchive/"
+ "red-orb-alphabet/128/Exclamation-mark-icon.png",
guest_amount: 0,
last_message_dict: {},
alert_icon: "https://pricespy.co.nz/favicon.ico",
default_icon: "https://softinst75770.host.vifib.net/"
+ "erp5/web_site_module/web_chat/favicon.ico"
};
......@@ -249,17 +313,16 @@
.querySelector("input").onfocus = function () {
return changeFavicon(gadget.state_parameter_dict.default_icon);
};
return gadget.jioApply('put', "/");
})
.push(function () {
return gadget.getLocalArchive();
return gadget.jioApply('repair');
})
.push(null, logError)
.push(function () {
return gadget.sendLocalArchive();
return gadget.getLocalArchive();
})
.push(function () {
return gadget.deployMessage(
"notification", gadget.state_parameter_dict.name + " has joined.");
return gadget.requestRequest();
})
.push(null, logError);
})
......@@ -270,51 +333,64 @@
// Get all messages stored in archive and add them to the list in order,
// using storeList because the messages are already in the archive
.declareMethod('getLocalArchive', function () {
console.log('get local');
var gadget = this;
return new RSVP.Queue()
.push(function () {
return gadget.jioApply('allAttachments', "/");
return gadget.jioApply('allDocs');
})
.push(function (attachment_list) {
.push(function (document_list) {
var list = document_list.data.rows;
var promise_list = [];
for (var id in attachment_list) {
if (attachment_list.hasOwnProperty(id)) {
promise_list.push(gadget.jioApply('getAttachment', "/", id));
}
for (var i = 0, i_len = list.length; i < i_len; i++) {
promise_list.push(gadget.jioApply('get', list[i].id));
}
return RSVP.all(promise_list);
})
.push(function (promise_list) {
var message_string_list = [];
for (var i = 0, i_len = promise_list.length; i < i_len; i++) {
message_string_list.push(promiseReadAsText(promise_list[i]));
}
return RSVP.all(message_string_list);
})
.push(function (message_string_list) {
.push(function (message_list) {
var message_queue = new FastPriorityQueue(messageTimeCompare(true));
for (var i = 0, i_len = message_string_list.length; i < i_len; i++) {
message_queue.add(JSON.parse(message_string_list[i]));
for (var i = 0, i_len = message_list.length; i < i_len; i++) {
try {
var message = JSON.parse(message_list[i].content);
if (message && typeof message === "object") {
message_queue.add(message);
}
} catch (error) {}
}
var last_message;
while (!message_queue.isEmpty()) {
var message = message_queue.poll();
var message_dict = gadget.state_parameter_dict.last_message_dict;
if (message.folder === gadget.state_parameter_dict.folder &&
message.room === gadget.state_parameter_dict.room &&
!sameMessage(last_message, message)) {
!sameMessage(last_message, message) &&
(message_dict[message.name] === undefined ||
message_dict[message.name] < getTime(message))) {
last_message = message;
storeList(gadget, message);
appendChat(gadget, messageToChat(message));
}
}
gadget.state_parameter_dict.initialized = true;
})
.push(null, logError);
})
// Send all messages in the list, in sorted order, to peer
.declareMethod('sendLocalArchive', function () {
// Send all requested messages in the list, in sorted order, to peer
.declareMethod('sendLocalArchive', function (request) {
console.log('send archive');
var gadget = this;
return gadget.sendMessage(JSON.stringify(createMessage(
gadget, "bundle", gadget.state_parameter_dict.message_list)));
var request_list = [];
var list = gadget.state_parameter_dict.message_list;
for (var i = 0, i_len = list.length; i < i_len; i++) {
if (!(list[i].name in request.content) ||
request.content[list[i].name] < getTime(list[i])) {
request_list.push(list[i]);
}
}
console.log(request_list);
return logQueue(gadget.sendMessage(createMessage(
gadget, "bundle", request_list, request.peer_source)));
})
// Get all new messages from the sorted list of peer,
......@@ -322,6 +398,7 @@
// and refresh, dedupe, and resort the list using refreshChat
.declareMethod('getRemoteArchive', function (bundle) {
var gadget = this;
console.log('get archive');
return new RSVP.Queue()
.push(function () {
var list = gadget.state_parameter_dict.message_list;
......@@ -340,13 +417,20 @@
}
return RSVP.all(promise_list);
})
.push(function () {
if (!gadget.state_parameter_dict.notified_join) {
gadget.state_parameter_dict.notified_join = true;
return gadget.deployMessage("notification",
gadget.state_parameter_dict.name + " has joined.");
}
})
.push(function () {
return refreshChat(gadget);
})
.push(null, logError);
})
// Create new message and send it to peer
// Create new message and send it to peer
.declareMethod('deployMessage', function (type, content) {
var gadget = this;
var message = createMessage(gadget, type, content);
......@@ -356,7 +440,7 @@
})
.push(function () {
changeFavicon(gadget.state_parameter_dict.default_icon);
return gadget.sendMessage(JSON.stringify(message));
return gadget.sendMessage(message);
})
.push(null, logError);
})
......@@ -367,7 +451,7 @@
changeFavicon(gadget.state_parameter_dict.alert_icon);
storeList(gadget, message);
appendChat(gadget, messageToChat(message));
return gadget.storeArchive(message);
return logQueue(gadget.storeArchive(message));
})
// Store message in the archive
......@@ -375,8 +459,34 @@
var gadget = this;
var id = message.folder + "_" + message.room + "_"
+ message.name + "_" + getTime(message).toString();
return gadget.jioApply('putAttachment', "/", id,
new Blob([JSON.stringify(message)], {type: "text"}));
return logQueue(gadget.jioApply('put', id, {
portal_type: "Text Post",
parent_relative_url: "post_text_module",
reference: id, // XXX use uuid here
author: message.name,
date_ms: getTime(message),
content: JSON.stringify(message)
}));
})
// Ask a peer to send over a request
.declareMethod('requestRequest', function () {
console.log('send doubler');
var gadget = this;
return logQueue(gadget.sendMessage(createMessage(gadget, "doubler", "")));
})
// Send a request to update the local archive
.declareMethod('sendRequest', function () {
console.log('send request');
var gadget = this;
return pollUntilNotNull(gadget, 1000, 30000, function () {
return gadget.state_parameter_dict.initialized;
}, function () {
console.log(JSON.stringify(gadget.state_parameter_dict.last_message_dict));
return gadget.sendMessage(createMessage(
gadget, "request", gadget.state_parameter_dict.last_message_dict));
});
})
// Listen for new chats
......@@ -405,9 +515,8 @@
return promiseEventListener(window, "beforeunload", true);
})
.push(function () {
return gadget.sendMessage(JSON.stringify(
createMessage(gadget, "notification",
gadget.state_parameter_dict.name + " has quit.")));
return gadget.sendMessage(createMessage(gadget, "notification",
gadget.state_parameter_dict.name + " has quit."));
});
});
......
......@@ -90,7 +90,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_chat_panel.js</string> </value>
<value> <string>gadget_erp5_chat_panel_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -11,13 +11,12 @@
<script src="gadget_erp5_chat_webrtc.js"></script>
</head>
<body>
<p class="timeout-alert">
</p>
<form class="dropbox-form">
<label>Automatically connect via Dropbox</label>
<br />
<a class="dropbox-login">
Log in to Dropbox!
</a>
<br />
<input type="submit" value="Authenticate!" />
</form>
......@@ -61,5 +60,9 @@
<br />
<input type="submit" value="Paste it!" />
</form>
<div data-gadget-url="gadget_erp5_chat_panel.html"
data-gadget-scope="chat_gadget"
data-gadget-sandbox="public" class="chat-panel"></div>
</body>
</html>
\ No newline at end of file
......@@ -94,7 +94,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_chat_webrtc.html</string> </value>
<value> <string>gadget_erp5_chat_webrtc_html</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
......@@ -6,6 +6,14 @@
console.log(error);
}
function logQueue(action) {
return new RSVP.Queue()
.push(function () {
return action;
})
.push(null, logError);
}
function showElementByClass(my_gadget, query) {
my_gadget.state_parameter_dict.element
.querySelector(query).style.display = "block";
......@@ -17,12 +25,21 @@
}
function pollUntilNotNull(
delay_ms, timeout_ms, nullableFunction, callbackFunction) {
my_gadget, delay_ms, timeout_ms,
nullableFunction, callbackFunction) {
if (callbackFunction === undefined) {
callbackFunction = function () {};
}
return RSVP.any([
RSVP.timeout(timeout_ms),
RSVP.Queue()
.push(function () {
return RSVP.delay(timeout_ms);
})
.push(function () {
my_gadget.state_parameter_dict.element
.querySelector(".timeout-alert").textContent =
"Timed out after " + timeout_ms + " ms.";
}),
promiseDoWhile(function () {
return new RSVP.Queue()
.push(function () {
......@@ -127,14 +144,14 @@
var folder = param_dict.folder;
var name = param_dict.name;
var content = param_dict.content;
return dropbox_gadget.putAttachment(
folder, name, new Blob([content], {type: "text"}));
return logQueue(dropbox_gadget.putAttachment(
folder, name, new Blob([content], {type: "text"})));
}
function removeDropboxContent(dropbox_gadget, param_dict) {
var folder = param_dict.folder;
var name = param_dict.name;
return dropbox_gadget.removeAttachment(folder, name);
return logQueue(dropbox_gadget.removeAttachment(folder, name));
}
function authenticateDropbox(my_gadget) {
......@@ -159,7 +176,6 @@
}
];
if (my_gadget.state_parameter_dict.role === "host") {
hideElementByClass(my_gadget, ".dropbox-form");
return authenticateHost.apply(undefined, dropbox_params);
} else if (my_gadget.state_parameter_dict.role === "guest") {
return authenticateGuest.apply(undefined, dropbox_params);
......@@ -186,7 +202,7 @@
.push(function () {
// Must use double quotation marks in query string!
return erp5_gadget.allDocs({
limit: [0, 300],
limit: [0, 1000000],
query: 'portal_type: "Webrtc Room"',
sort_on: [["last_modified", "descending"]],
select_list: ["title"]
......@@ -215,8 +231,9 @@
function resetErp5Content(erp5_gadget, param_dict) {
var folder = param_dict.folder;
var url = param_dict.url;
return erp5_gadget.putAttachment(folder, url + "WebrtcRoom_resetContent",
new Blob([JSON.stringify({folder: folder})]));
return logQueue(erp5_gadget.putAttachment(folder,
url + "WebrtcRoom_resetContent",
new Blob([JSON.stringify({folder: folder})])));
}
function getErp5Content(erp5_gadget, param_dict) {
......@@ -248,17 +265,18 @@
var folder = param_dict.folder;
var name = param_dict.name;
var url = param_dict.url;
return erp5_gadget.putAttachment(folder, url + "WebrtcRoom_putContent",
new Blob([JSON.stringify(
{folder: folder, name: name, content: content})]));
return logQueue(erp5_gadget.putAttachment(folder,
url + "WebrtcRoom_putContent", new Blob([JSON.stringify(
{folder: folder, name: name, content: content})])));
}
function removeErp5Content(erp5_gadget, param_dict) {
var folder = param_dict.folder;
var name = param_dict.name;
var url = param_dict.url;
return erp5_gadget.putAttachment(folder, url + "WebrtcRoom_deleteContent",
new Blob([JSON.stringify({folder: folder, name: name})]));
return logQueue(erp5_gadget.putAttachment(folder,
url + "WebrtcRoom_deleteContent",
new Blob([JSON.stringify({folder: folder, name: name})])));
}
function authenticateErp5(my_gadget) {
......@@ -300,7 +318,6 @@
}
];
if (my_gadget.state_parameter_dict.role === "host") {
hideElementByClass(my_gadget, ".erp5-form");
return authenticateHost.apply(undefined, erp5_params);
} else if (my_gadget.state_parameter_dict.role === "guest") {
return authenticateGuest.apply(undefined, erp5_params);
......@@ -317,11 +334,13 @@
var jio_gadget;
return new RSVP.Queue()
.push(function () {
my_gadget.state_parameter_dict.element
.querySelector(".timeout-alert").textContent = "";
return my_gadget.getDeclaredGadget(jio_gadget_name);
})
.push(function (storage_gadget) {
jio_gadget = storage_gadget;
return pollUntilNotNull(500, 3600000, function () {
return pollUntilNotNull(my_gadget, 500, 3600000, function () {
return jio_function_dict.getOffer(
jio_gadget, {folder: folder, room: room, url: url});
}, function (offer_name) {
......@@ -329,7 +348,7 @@
});
})
.push(function () {
return pollUntilNotNull(50, 30000, function () {
return pollUntilNotNull(my_gadget, 50, 30000, function () {
if (my_gadget.state_parameter_dict.offer_ready === true) {
my_gadget.state_parameter_dict.offer_ready = false;
return true;
......@@ -342,7 +361,7 @@
jio_gadget, {folder: folder, url: url});
})
.push(function () {
return pollUntilNotNull(50, 5000, function () {
return pollUntilNotNull(my_gadget, 50, 5000, function () {
return jio_function_dict.getContent(
jio_gadget, {folder: folder, name: "offer_" + name, url: url});
}, function (guest_offer) {
......@@ -356,7 +375,7 @@
}
})
.push(function () {
return pollUntilNotNull(50, 10000, function () {
return pollUntilNotNull(my_gadget, 50, 10000, function () {
return my_gadget.state_parameter_dict.candidate;
}, function (host_answer) {
return jio_function_dict.putContent(jio_gadget, {
......@@ -385,11 +404,13 @@
var jio_gadget;
return new RSVP.Queue()
.push(function () {
my_gadget.state_parameter_dict.element
.querySelector(".timeout-alert").textContent = "";
return my_gadget.getDeclaredGadget(jio_gadget_name);
})
.push(function (storage_gadget) {
jio_gadget = storage_gadget;
return pollUntilNotNull(50, 15000, function () {
return pollUntilNotNull(my_gadget, 50, 15000, function () {
return my_gadget.state_parameter_dict.candidate;
}, function (guest_offer) {
name = room + "_" + my_gadget.state_parameter_dict.name + ".txt";
......@@ -399,7 +420,7 @@
});
})
.push(function () {
return pollUntilNotNull(50, 30000, function () {
return pollUntilNotNull(my_gadget, 50, 30000, function () {
return jio_function_dict.getContent(
jio_gadget, {folder: folder, name: "answer_" + name, url: url});
}, function (host_answer) {
......@@ -484,6 +505,20 @@
my_gadget.state_parameter_dict.candidate = candidate;
my_gadget.state_parameter_dict.element
.querySelector(form_selector).textContent = candidate;
};
if (my_gadget.state_parameter_dict.role === "host") {
peer_connection.oniceconnectionstatechange = function() {
if (peer_connection.iceConnectionState === "connected") {
my_gadget.state_parameter_dict.guest_amount += 1;
} else if (peer_connection.iceConnectionState === "disconnected") {
my_gadget.state_parameter_dict.guest_amount -= 1;
} else if (peer_connection.iceConnectionState === "failed") {
if (my_gadget.state_parameter_dict.role === "guest") {
window.location.reload();
}
}
console.log("connected guests: " + my_gadget.state_parameter_dict.guest_amount);
};
}
}
......@@ -492,16 +527,17 @@
data_channel.onopen = function () {
return new RSVP.Queue()
.push(function () {
my_gadget.state_parameter_dict.connected = true;
showElementByClass(my_gadget, ".chat-panel");
if (my_gadget.state_parameter_dict.role === "guest") {
hideElementByClass(my_gadget, ".dropbox-form");
hideElementByClass(my_gadget, ".erp5-form");
hideElementByClass(my_gadget, ".guest-offer-form");
hideElementByClass(my_gadget, ".timeout-alert");
}
return my_gadget.declareGadget(
"gadget_erp5_chat_panel.html", {scope: "chat_gadget"});
return my_gadget.getDeclaredGadget("chat_gadget");
})
.push(function (chat_gadget) {
my_gadget.state_parameter_dict.connected = true;
chat_gadget.state_parameter_dict.name =
my_gadget.state_parameter_dict.name;
chat_gadget.state_parameter_dict.folder =
......@@ -534,6 +570,7 @@
var message = JSON.parse(my_event.data);
return new RSVP.Queue()
.push(function () {
message.peer_source = my_event.srcElement;
return my_gadget.getDeclaredGadget("chat_gadget");
})
.push(function (chat_gadget) {
......@@ -544,26 +581,39 @@
})
.push(function () {
if (my_gadget.state_parameter_dict.role === "host") {
return my_gadget.sendMessage(
my_event.data, my_event.srcElement);
return my_gadget.sendMessage(message);
} else if (my_gadget.state_parameter_dict.role === "guest") {
return;
}
})
.push(null, logError);
} else if (message.type === "bundle") {
return new RSVP.Queue()
.push(function () {
if (my_gadget.state_parameter_dict.role === "host") {
my_gadget.state_parameter_dict.archive_amount += 1;
console.log("guest amount: " + my_gadget.state_parameter_dict.guest_amount);
console.log("archive amount: " + my_gadget.state_parameter_dict.archive_amount);
if (my_gadget.state_parameter_dict.archive_amount >=
my_gadget.state_parameter_dict.guest_amount) {
my_gadget.state_parameter_dict.archive_amount = 0;
return new RSVP.Queue()
.push(function () {
return chat_gadget.getRemoteArchive(message);
})
.push(function () {
return chat_gadget.requestRequest();
});
} else {
return chat_gadget.getRemoteArchive(message);
})
.push(function () {
if (my_gadget.state_parameter_dict.role === "host") {
return chat_gadget.sendLocalArchive();
} else {
return;
}
})
.push(null, logError);
}
} else {
return chat_gadget.getRemoteArchive(message);
}
} else if (message.type === "request") {
console.log("get request");
return chat_gadget.sendLocalArchive(message);
} else if (message.type === "doubler") {
console.log("get doubler");
return chat_gadget.sendRequest();
}
})
.push(null, logError);
......@@ -615,6 +665,8 @@
offer_ready: false,
data_channel_list: [],
peer_connection_list: [],
guest_amount: 0,
archive_amount: 0,
// full path including user folder, e.g. "/Apps/OfficeJS Chat/nexedi/"
dropbox_folder: "/Apps/OfficeJS Chat",
erp5_url: "https://softinst75770.host.vifib.net/erp5/"
......@@ -647,22 +699,33 @@
.push(null, logError);
})
.allowPublicAcquisition('sendMessage', function (message_string) {
.allowPublicAcquisition('sendMessage', function (param_dict) {
var gadget = this;
return gadget.sendMessage(message_string);
return gadget.sendMessage.apply(gadget, param_dict);
})
.declareMethod('sendMessage', function (message_string, source) {
.declareMethod('sendMessage', function (message) {
var gadget = this;
var source = message.peer_source;
var message_string = JSON.stringify(message);
var channel_list = gadget.state_parameter_dict.data_channel_list;
return new RSVP.Queue()
.push(function () {
if (gadget.state_parameter_dict.role === "host") {
promise_list = [];
for (var i = 0, i_len = channel_list.length; i < i_len; i++) {
var channel = channel_list[i];
if (channel.readyState === "open" && channel !== source) {
promise_list.push(channel.send(message_string));
if (message.type === "bundle") {
for (var i = 0, i_len = channel_list.length; i < i_len; i++) {
var channel = channel_list[i];
if (channel.readyState === "open" && channel === source) {
return channel.send(message_string);
}
}
} else {
promise_list = [];
for (var i = 0, i_len = channel_list.length; i < i_len; i++) {
var channel = channel_list[i];
if (channel.readyState === "open" && channel !== source) {
promise_list.push(channel.send(message_string));
}
}
}
return RSVP.all(promise_list);
......@@ -685,6 +748,7 @@
folder = folder + "/";
}
gadget.state_parameter_dict.dropbox_folder += folder;
hideElementByClass(gadget, ".chat-panel");
hideElementByClass(gadget, ".host-answer-form");
hideElementByClass(gadget, ".guest-answer-form");
if (gadget.state_parameter_dict.role === "host") {
......
......@@ -90,7 +90,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_chat_webrtc.js</string> </value>
<value> <string>gadget_erp5_chat_webrtc_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
......
web_page_module/adapter.js
web_page_module/fast_priority_queue.js
web_page_module/adapter_js
web_page_module/fast_priority_queue_js
web_page_module/gadget_erp5_chat*
web_site_module/web_chat/**
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment