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