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 */
/*global window, rJS, jIO, btoa */
(function (window, rJS, jIO, btoa) {
/*global window, rJS, btoa */
(function (window, rJS, btoa) {
"use strict";
......@@ -8,9 +8,10 @@
// 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("makeJioReplicate", "makeJioReplicate")
/* Render the gadget.
......@@ -28,17 +29,16 @@
})
/* Create a new jIO replicate storage.
/* Use the given remote configuration to get a jIO replicate storage.
* Parameters:
* - state: query, local_sub_storage
* - fields: the jIO configuration fields from the form,
* identical to the ones used in the configurators
* 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
*/
.declareMethod("createJioReplicate", function () {
.declareMethod("getRemoteConfiguration", function () {
var gadget = this,
remote_sub_storage,
fields = gadget.element.querySelector(".connect-form").elements;
......@@ -69,16 +69,11 @@
remote_sub_storage = JSON.parse(fields.custom_configuration.value);
break;
}
gadget.state.storage = jIO.createJIO({
type: "replicate",
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.makeJioReplicate(remote_sub_storage, gadget.state.room)
.push(function (jio_storage) {
gadget.state.storage = jio_storage;
return gadget.joinNewRoom(gadget.state.room);
});
})
......@@ -103,13 +98,13 @@
})
// Call createJioReplicate when the form is submitted.
// Call getRemoteConfiguration when the form is submitted.
.onEvent("submit", function (event) {
var gadget = this;
if (event.target.className === "connect-form") {
return gadget.createJioReplicate(event);
return gadget.getRemoteConfiguration(event);
}
});
}(window, rJS, jIO, btoa));
\ No newline at end of file
}(window, rJS, btoa));
\ No newline at end of file
......@@ -26,6 +26,9 @@
</script>
</head>
<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-left-panel">
<h3 class="center">Contacts</h3>
......
......@@ -212,11 +212,12 @@
// i.e. {quiet_room: 3, busy_room: 429}
message_count_dict: {},
// a dict of room names to an object with keys corresponding to
// their delayRefresh promise queues, i.e. queue: new RSVP.Queue()
// their POLL_DELAY_LIST indices, i.e. index: 3, and
// whether each is currently running refreshChat, i.e. lock: true
delay_refresh_dict: {},
// the index of the stored polling interval in POLL_DELAY_LIST
delay_refresh_index: 0,
// the stored promise queue to run delayRefresh
delay_refresh_queue: new RSVP.Queue(),
// 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
favicon_alert: false,
......@@ -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.
* Parameters: all properties in gadget.state
* Effects:
......@@ -464,21 +505,9 @@
.appendChild(room_gadget.element);
return room_gadget.changeState({
room: room,
local_sub_storage: gadget.state.local_sub_storage,
default_jio_type: gadget.state.default_jio_type,
default_erp5_url: gadget.state.default_erp5_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"]
]
}
default_dav_url: gadget.state.default_dav_url
});
})
.push(function () {
......@@ -487,11 +516,6 @@
.push(function () {
gadget.state.message_list_dict[room] = [];
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;
return gadget.changeState({room: room, is_chat: false});
});
......@@ -589,7 +613,8 @@
author: message.name,
date_ms: getTime(message),
room: message.room,
description: message.room,
// XXX to index rooms using ERP5 queries, uncomment the following
// description: message.room,
content: JSON.stringify(message)
}]);
});
......@@ -602,7 +627,7 @@
* - poll_delay_index: the index in POLL_DELAY_LIST of
* the time in milliseconds to wait before refreshing again
* 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:
* - call refreshChat and wait a while before calling it again
*/
......@@ -647,23 +672,18 @@
* - so, do nothing
*/
.push(function () {
if (poll_delay_index < gadget.state.delay_refresh_dict[room].index
&& !gadget.state.delay_refresh_dict[room].lock) {
gadget.state.delay_refresh_dict[room].queue.cancel();
if (poll_delay_index < gadget.state.delay_refresh_index
&& !gadget.state.delay_refresh_lock) {
gadget.state.delay_refresh_queue.cancel();
}
if (poll_delay_index <= gadget.state.delay_refresh_dict[room].index) {
gadget.state.delay_refresh_dict[room] = {
// delayRefresh() is immediately called after this line
// and can be cancelled to overwrite longer intervals
queue: new RSVP.Queue()
.push(function () {
return gadget.delayRefresh(room, poll_delay_index + 1);
}),
// increase the polling interval over time
index: poll_delay_index + 1,
// only refreshChat() should modify the locks
lock: gadget.state.delay_refresh_dict[room].lock
};
if (poll_delay_index <= gadget.state.delay_refresh_index) {
// delayRefresh() is immediately called after this line
// and can be cancelled to overwrite longer intervals
gadget.state.delay_refresh_queue = new RSVP.Queue()
.push(function () {
return gadget.delayRefresh(room, poll_delay_index + 1);
});
gadget.state.delay_refresh_index = poll_delay_index + 1;
}
});
})
......@@ -694,10 +714,10 @@
// multiple calls to repair() results in unmanageable duplication
// atomic because JavaScript is single threaded,
// 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;
}
gadget.state.delay_refresh_dict[room].lock = true;
gadget.state.delay_refresh_lock = true;
return gadget.getDeclaredGadget("room-gadget-" + room)
.push(function (sub_gadget) {
......@@ -761,9 +781,9 @@
// release the lock no matter what errors occur
.push(function () {
gadget.state.delay_refresh_dict[room].lock = false;
gadget.state.delay_refresh_lock = false;
}, function () {
gadget.state.delay_refresh_dict[room].lock = false;
gadget.state.delay_refresh_lock = false;
});
})
......@@ -922,4 +942,4 @@
});
});
}(window, document, RSVP, rJS, Handlebars, promiseEventListener));
\ No newline at end of file
}(window, document, RSVP, rJS, Handlebars, promiseEventListener));
<!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