Commit 95fa88f5 authored by Eugene Shen's avatar Eugene Shen

Merge identical replicate storages to reduce repair requests

parent 69670067
/*jslint nomen: true, indent: 2, maxerr: 3, maxlen: 80 */ /*jslint nomen: true, indent: 2, maxerr: 3, maxlen: 80 */
/*global window, rJS, jIO, btoa */ /*global window, rJS, btoa */
(function (window, rJS, jIO, btoa) { (function (window, rJS, btoa) {
"use strict"; "use strict";
...@@ -8,9 +8,10 @@ ...@@ -8,9 +8,10 @@
// State is set in erp5_page_chat_box. // State is set in erp5_page_chat_box.
// The following functions is acquired from erp5_page_chat_box. // The following functions are acquired from erp5_page_chat_box.
.declareAcquiredMethod("joinNewRoom", "joinNewRoom") .declareAcquiredMethod("joinNewRoom", "joinNewRoom")
.declareAcquiredMethod("makeJioReplicate", "makeJioReplicate")
/* Render the gadget. /* Render the gadget.
...@@ -28,17 +29,16 @@ ...@@ -28,17 +29,16 @@
}) })
/* Create a new jIO replicate storage. /* Use the given remote configuration to get a jIO replicate storage.
* Parameters: * Parameters:
* - state: query, local_sub_storage
* - fields: the jIO configuration fields from the form, * - fields: the jIO configuration fields from the form,
* identical to the ones used in the configurators * identical to the ones used in the configurators
* Effects: * Effects:
* - create a new jIO replicate storage with the given configuration * - get the jIO replicate storage with the given remote configuration
* - change to the room corresponding to the new storage * - change to the room corresponding to the new storage
*/ */
.declareMethod("createJioReplicate", function () { .declareMethod("getRemoteConfiguration", function () {
var gadget = this, var gadget = this,
remote_sub_storage, remote_sub_storage,
fields = gadget.element.querySelector(".connect-form").elements; fields = gadget.element.querySelector(".connect-form").elements;
...@@ -69,16 +69,11 @@ ...@@ -69,16 +69,11 @@
remote_sub_storage = JSON.parse(fields.custom_configuration.value); remote_sub_storage = JSON.parse(fields.custom_configuration.value);
break; break;
} }
return gadget.makeJioReplicate(remote_sub_storage, gadget.state.room)
gadget.state.storage = jIO.createJIO({ .push(function (jio_storage) {
type: "replicate", gadget.state.storage = jio_storage;
use_remote_post: true,
conflict_handling: 2,
query: gadget.state.query,
local_sub_storage: gadget.state.local_sub_storage,
remote_sub_storage: remote_sub_storage
});
return gadget.joinNewRoom(gadget.state.room); return gadget.joinNewRoom(gadget.state.room);
});
}) })
...@@ -103,13 +98,13 @@ ...@@ -103,13 +98,13 @@
}) })
// Call createJioReplicate when the form is submitted. // Call getRemoteConfiguration when the form is submitted.
.onEvent("submit", function (event) { .onEvent("submit", function (event) {
var gadget = this; var gadget = this;
if (event.target.className === "connect-form") { if (event.target.className === "connect-form") {
return gadget.createJioReplicate(event); return gadget.getRemoteConfiguration(event);
} }
}); });
}(window, rJS, jIO, btoa)); }(window, rJS, btoa));
\ No newline at end of file \ No newline at end of file
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
</script> </script>
</head> </head>
<body> <body>
<div data-gadget-url="gadget_erp5_page_chat_storage.html"
data-gadget-scope="storage_gadget"
data-gadget-sandbox="public"></div>
<div class="chat-box"> <div class="chat-box">
<div class="chat-left-panel"> <div class="chat-left-panel">
<h3 class="center">Contacts</h3> <h3 class="center">Contacts</h3>
......
...@@ -212,11 +212,12 @@ ...@@ -212,11 +212,12 @@
// i.e. {quiet_room: 3, busy_room: 429} // i.e. {quiet_room: 3, busy_room: 429}
message_count_dict: {}, message_count_dict: {},
// a dict of room names to an object with keys corresponding to // the index of the stored polling interval in POLL_DELAY_LIST
// their delayRefresh promise queues, i.e. queue: new RSVP.Queue() delay_refresh_index: 0,
// their POLL_DELAY_LIST indices, i.e. index: 3, and // the stored promise queue to run delayRefresh
// whether each is currently running refreshChat, i.e. lock: true delay_refresh_queue: new RSVP.Queue(),
delay_refresh_dict: {}, // true if refreshChat is currently being executed, otherwise false
delay_refresh_lock: false,
// true to use alert_icon_url, false to use default_icon_url // true to use alert_icon_url, false to use default_icon_url
favicon_alert: false, favicon_alert: false,
...@@ -263,6 +264,46 @@ ...@@ -263,6 +264,46 @@
}) })
/* Wrap the call to make a jIO replicate storage.
* This function is acquired by gadget_erp5_chat_room.
* Parameters:
* - param_list[0]: the jIO parameters of the remote storage
* - param_list[1]: the name of the room that requested the storage
* Effects:
* - call storage_gadget.createJioReplicate()
* Returns:
* - the jIO replicate storage created with the given parameters
* regardless of whether it was previously or presently created
*/
.allowPublicAcquisition("makeJioReplicate", function (param_list) {
var gadget = this;
return gadget.getDeclaredGadget("storage_gadget")
.push(function (storage_gadget) {
// all_query makes only one replicate storage for one ERP5
var all_query = 'portal_type: "Text Post"',
// room_query makes one replicate storage for every room
// XXX store room in description because description is
// indexed in ERP5, and only indexed properties can be queried
room_query = 'portal_type: "Text Post" AND description: "'
+ param_list[1] + '"';
return storage_gadget.createJioReplicate(
gadget.state.local_sub_storage,
param_list[0],
{
query: all_query,
limit: [0, JIO_QUERY_MAX_LIMIT],
select_list: ["content"],
sort_on: [
["date_ms", "ascending"],
["content", "ascending"]
]
}
);
});
})
/* Render everything again when the current state changes. /* Render everything again when the current state changes.
* Parameters: all properties in gadget.state * Parameters: all properties in gadget.state
* Effects: * Effects:
...@@ -464,21 +505,9 @@ ...@@ -464,21 +505,9 @@
.appendChild(room_gadget.element); .appendChild(room_gadget.element);
return room_gadget.changeState({ return room_gadget.changeState({
room: room, room: room,
local_sub_storage: gadget.state.local_sub_storage,
default_jio_type: gadget.state.default_jio_type, default_jio_type: gadget.state.default_jio_type,
default_erp5_url: gadget.state.default_erp5_url, default_erp5_url: gadget.state.default_erp5_url,
default_dav_url: gadget.state.default_dav_url, default_dav_url: gadget.state.default_dav_url
// XXX store room in description because description is
// indexed in ERP5, and only indexed properties can be queried
query: {
query: 'portal_type: "Text Post" AND description: "' + room + '"',
limit: [0, JIO_QUERY_MAX_LIMIT],
select_list: ["content"],
sort_on: [
["date_ms", "ascending"],
["content", "ascending"]
]
}
}); });
}) })
.push(function () { .push(function () {
...@@ -487,11 +516,6 @@ ...@@ -487,11 +516,6 @@
.push(function () { .push(function () {
gadget.state.message_list_dict[room] = []; gadget.state.message_list_dict[room] = [];
gadget.state.message_count_dict[room] = 0; gadget.state.message_count_dict[room] = 0;
gadget.state.delay_refresh_dict[room] = {
queue: new RSVP.Queue(),
index: 0,
lock: false
};
gadget.state.id_to_name["chat-contact-" + nameToId(room)] = room; gadget.state.id_to_name["chat-contact-" + nameToId(room)] = room;
return gadget.changeState({room: room, is_chat: false}); return gadget.changeState({room: room, is_chat: false});
}); });
...@@ -589,7 +613,8 @@ ...@@ -589,7 +613,8 @@
author: message.name, author: message.name,
date_ms: getTime(message), date_ms: getTime(message),
room: message.room, room: message.room,
description: message.room, // XXX to index rooms using ERP5 queries, uncomment the following
// description: message.room,
content: JSON.stringify(message) content: JSON.stringify(message)
}]); }]);
}); });
...@@ -602,7 +627,7 @@ ...@@ -602,7 +627,7 @@
* - poll_delay_index: the index in POLL_DELAY_LIST of * - poll_delay_index: the index in POLL_DELAY_LIST of
* the time in milliseconds to wait before refreshing again * the time in milliseconds to wait before refreshing again
* Requirements: * Requirements:
* - gadget.state.delay_refresh_dict[room].queue has new RSVP.Queue() in it * - gadget.state.delay_refresh_queue has new RSVP.Queue() in it
* Effects: * Effects:
* - call refreshChat and wait a while before calling it again * - call refreshChat and wait a while before calling it again
*/ */
...@@ -647,23 +672,18 @@ ...@@ -647,23 +672,18 @@
* - so, do nothing * - so, do nothing
*/ */
.push(function () { .push(function () {
if (poll_delay_index < gadget.state.delay_refresh_dict[room].index if (poll_delay_index < gadget.state.delay_refresh_index
&& !gadget.state.delay_refresh_dict[room].lock) { && !gadget.state.delay_refresh_lock) {
gadget.state.delay_refresh_dict[room].queue.cancel(); gadget.state.delay_refresh_queue.cancel();
} }
if (poll_delay_index <= gadget.state.delay_refresh_dict[room].index) { if (poll_delay_index <= gadget.state.delay_refresh_index) {
gadget.state.delay_refresh_dict[room] = {
// delayRefresh() is immediately called after this line // delayRefresh() is immediately called after this line
// and can be cancelled to overwrite longer intervals // and can be cancelled to overwrite longer intervals
queue: new RSVP.Queue() gadget.state.delay_refresh_queue = new RSVP.Queue()
.push(function () { .push(function () {
return gadget.delayRefresh(room, poll_delay_index + 1); return gadget.delayRefresh(room, poll_delay_index + 1);
}), });
// increase the polling interval over time gadget.state.delay_refresh_index = poll_delay_index + 1;
index: poll_delay_index + 1,
// only refreshChat() should modify the locks
lock: gadget.state.delay_refresh_dict[room].lock
};
} }
}); });
}) })
...@@ -694,10 +714,10 @@ ...@@ -694,10 +714,10 @@
// multiple calls to repair() results in unmanageable duplication // multiple calls to repair() results in unmanageable duplication
// atomic because JavaScript is single threaded, // atomic because JavaScript is single threaded,
// so nothing else can run between the following four lines // so nothing else can run between the following four lines
if (gadget.state.delay_refresh_dict[room].lock) { if (gadget.state.delay_refresh_lock) {
return; return;
} }
gadget.state.delay_refresh_dict[room].lock = true; gadget.state.delay_refresh_lock = true;
return gadget.getDeclaredGadget("room-gadget-" + room) return gadget.getDeclaredGadget("room-gadget-" + room)
.push(function (sub_gadget) { .push(function (sub_gadget) {
...@@ -761,9 +781,9 @@ ...@@ -761,9 +781,9 @@
// release the lock no matter what errors occur // release the lock no matter what errors occur
.push(function () { .push(function () {
gadget.state.delay_refresh_dict[room].lock = false; gadget.state.delay_refresh_lock = false;
}, function () { }, function () {
gadget.state.delay_refresh_dict[room].lock = false; gadget.state.delay_refresh_lock = false;
}); });
}) })
......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>OfficeJS Chat Storage</title>
<script src="rsvp.js"></script>
<script src="renderjs.js"></script>
<script src="jiodev.js"></script>
<script src="gadget_erp5_page_chat_storage.js"></script>
</head>
<body>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Page" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>classification/collaborative/team</string>
<string>contributor/person_module/1</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_chat_storage.html</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_page_chat_storage_html</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Page</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>OfficeJS Page Chat Storage</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
/*jslint nomen: true, indent: 2, maxerr: 3, maxlen: 80 */
/*global window, rJS, jIO */
(function (window, rJS, jIO) {
"use strict";
rJS(window)
// initialize dictionary of createJIO parameters to the resulting storages,
// i.e. {"{type: "replicate", local_sub_storage: ...}": JioProxyStorage}
.setState({
jio_storage_dict: []
})
/* Create a jIO replicate storage.
* Parameters:
* - local: the jIO parameters of the local storage
* - remote: the jIO parameters of the remote storage
* - query: the jIO query of the replicate storage, optional
* Effects:
* - if it does not yet exist, create a new jIO replicate storage
* between the given local storage and the given remote storage
* Returns:
* - the jIO replicate storage created with the given parameters
* regardless of whether it was previously or presently created
*/
.declareMethod("createJioReplicate", function (local, remote, query) {
var gadget = this,
param_string,
param_dict = {
type: "replicate",
use_remote_post: true,
conflict_handling: 2,
local_sub_storage: local,
remote_sub_storage: remote
};
if (query !== undefined) {
param_dict.query = query;
}
param_string = JSON.stringify(param_dict);
if (!gadget.state.jio_storage_dict.hasOwnProperty(param_string)) {
gadget.state.jio_storage_dict[param_string] = jIO.createJIO(param_dict);
}
return gadget.state.jio_storage_dict[param_string];
});
}(window, rJS, jIO));
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>classification/collaborative/team</string>
<string>contributor/person_module/1</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_chat_storage.js</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_erp5_page_chat_storage_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Script</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>OfficeJS Page Chat Storage JS</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
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