Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
272 lines
6.7 KiB
JavaScript
Executable file
272 lines
6.7 KiB
JavaScript
Executable file
'use strict';
|
|
|
|
/* global Cache */
|
|
/* global ICEStore */
|
|
|
|
/**
|
|
* Module to handle ICE data across different parts of the application
|
|
* This module just know about the internal representation and how
|
|
* to deal with share ICE information (which has different format).
|
|
*/
|
|
|
|
(function ICEData(exports) {
|
|
|
|
if (exports.ICEData) {
|
|
return;
|
|
}
|
|
|
|
var localIceContacts = [];
|
|
var ICE_CONTACTS_KEY = 'ice-contacts';
|
|
var onChangeCallbacks = [];
|
|
var onChangeAttached = false;
|
|
var pendingChanges = [];
|
|
var performingChange = false;
|
|
|
|
/**
|
|
* Loads the local formated data into an internal
|
|
* representation.
|
|
* @return (Promise) fullfill when the load finish.
|
|
*/
|
|
function load() {
|
|
var iceContactsIds = [
|
|
{
|
|
id: undefined,
|
|
active: false
|
|
},
|
|
{
|
|
id: undefined,
|
|
active: false
|
|
}
|
|
];
|
|
|
|
return new Promise(function(resolve) {
|
|
window.asyncStorage.getItem(ICE_CONTACTS_KEY, function(data) {
|
|
if (data) {
|
|
if (data[0]) {
|
|
iceContactsIds[0] = data[0];
|
|
}
|
|
if (data[1]) {
|
|
iceContactsIds[1] = data[1];
|
|
}
|
|
}
|
|
localIceContacts = iceContactsIds;
|
|
resolve(localIceContacts);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Set the value of an ICE contact, both in local and in the
|
|
* datastore
|
|
* @param id (string) contact id
|
|
* @param pos (int) current position (0,1)
|
|
* @param active (boolean) ice contact is active or not
|
|
*/
|
|
function setICEContact(id, pos, active) {
|
|
active = active || false;
|
|
|
|
Cache.evict();
|
|
|
|
// Save locally
|
|
localIceContacts[pos] = {
|
|
id: id,
|
|
active: active
|
|
};
|
|
return setIceContactsItem(localIceContacts).then(() => {
|
|
// Save in the datastore
|
|
return modifyICEInDS();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Set the values for ICE contacts, both in local and in the
|
|
* datastore
|
|
* @param iceContactList the list with ids of ICE Contacts to be set
|
|
*/
|
|
function setICEContacts(iceContactList) {
|
|
if (!Array.isArray(iceContactList)) {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
// Save locally
|
|
localIceContacts = [
|
|
{
|
|
id: iceContactList[0],
|
|
active: !!iceContactList[0]
|
|
},
|
|
{
|
|
id: iceContactList[1],
|
|
active: !!iceContactList
|
|
}
|
|
];
|
|
|
|
return setIceContactsItem(localIceContacts).then(() => {
|
|
// Save in the datastore
|
|
return modifyICEInDS();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Clone the current local ice contacts into the datastore,
|
|
* considering the active flag.
|
|
* @return (Promise) fullfill when data saved in DS
|
|
*/
|
|
function modifyICEInDS() {
|
|
var contacts = [];
|
|
localIceContacts.forEach(function(iceContact) {
|
|
if (iceContact.id && iceContact.active) {
|
|
contacts.push(iceContact.id);
|
|
}
|
|
});
|
|
|
|
return ICEStore.setContacts(contacts);
|
|
}
|
|
|
|
/**
|
|
* Given a specific contact id removes it from the
|
|
* ice list, if present or disabled
|
|
* @param id (String) contact id
|
|
* @return (Promise) fullfill when data modified in DS
|
|
*/
|
|
function removeICEContact(id) {
|
|
var contact = localIceContacts.find(function(x) {
|
|
return x.id === id;
|
|
});
|
|
|
|
if (!contact) {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
var index = localIceContacts.indexOf(contact);
|
|
localIceContacts[index].id = null;
|
|
localIceContacts[index].active = false;
|
|
|
|
setIceContactsItem(localIceContacts).then(function() {
|
|
return modifyICEInDS().then(() => {
|
|
notifyCallbacks(localIceContacts);
|
|
});
|
|
}).then(resolve, reject);
|
|
});
|
|
}
|
|
|
|
function setIceContactsItem(iceContactsList) {
|
|
return new Promise(function(resolve, reject) {
|
|
window.asyncStorage.setItem(ICE_CONTACTS_KEY, iceContactsList,
|
|
resolve, reject);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Adds an observer to be called when an ice contact
|
|
* changed. We can add multiple listeners, since we will
|
|
* need to react in several parts of the app to this changes.
|
|
* Also the listener removes a contact id in case we are performing
|
|
* a delete. In case of modification we don't do anythying as we
|
|
* store just ids.
|
|
* Listener will be attached just once, but we can keep adding
|
|
* callbacks.
|
|
* @param fn (Function) callback to call when ice contact change
|
|
*/
|
|
function listenForChanges(fn) {
|
|
return new Promise(function(resolve) {
|
|
if (!onChangeAttached) {
|
|
load().then(function() {
|
|
document.addEventListener('contactChanged', onChangeEvent);
|
|
onChangeAttached = true;
|
|
});
|
|
}
|
|
|
|
if (typeof fn === 'function') {
|
|
onChangeCallbacks.push(fn);
|
|
}
|
|
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
function notifyCallbacks(data) {
|
|
onChangeCallbacks.forEach(function(fn) {
|
|
fn(data);
|
|
});
|
|
}
|
|
|
|
function handleChangeEvent(evt) {
|
|
// Figure out if we got a change in a ICE contact
|
|
var contact = localIceContacts.find(function(x) {
|
|
return x.id === evt.detail.contactID;
|
|
});
|
|
|
|
if (!contact) {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
// If it's a delete update all the storages
|
|
if (evt.detail.reason === 'remove') {
|
|
return removeICEContact(contact.id);
|
|
} else {
|
|
notifyCallbacks(localIceContacts);
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
|
|
function onChangeEvent(evt) {
|
|
// We should refresh the iceContacts before determining if it is necessary
|
|
// to notify or not
|
|
pendingChanges.push(evt);
|
|
if (!performingChange) {
|
|
performChange();
|
|
}
|
|
}
|
|
|
|
// We perform any change sequentially to avoid any race condition while
|
|
// saving to disc the ICE state.
|
|
function performChange() {
|
|
performingChange = true;
|
|
var evt = pendingChanges.pop();
|
|
|
|
if (!evt) {
|
|
performingChange = false;
|
|
return;
|
|
}
|
|
|
|
function callback() {
|
|
handleChangeEvent(evt).then(performChange);
|
|
}
|
|
|
|
load().then(callback, callback);
|
|
}
|
|
|
|
function getActiveIceContacts() {
|
|
return new Promise(function(resolve, reject) {
|
|
load().then(function() {
|
|
var result = [];
|
|
localIceContacts.forEach(function(aContact) {
|
|
if (aContact.active && aContact.id) {
|
|
result.push(aContact.id);
|
|
}
|
|
resolve(result);
|
|
});
|
|
}, reject);
|
|
});
|
|
}
|
|
|
|
function stopListenForChanges() {
|
|
document.removeEventListener('contactChanged', onChangeEvent);
|
|
onChangeCallbacks = [];
|
|
onChangeAttached = false;
|
|
}
|
|
|
|
exports.ICEData = {
|
|
load: load,
|
|
setICEContact: setICEContact,
|
|
setICEContacts: setICEContacts,
|
|
removeICEContact: removeICEContact,
|
|
get iceContacts() { return localIceContacts; },
|
|
getActiveIceContacts: getActiveIceContacts,
|
|
listenForChanges: listenForChanges,
|
|
stopListenForChanges: stopListenForChanges
|
|
};
|
|
|
|
|
|
})(window);
|