Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
259
gaia/apps/calendar/js/controllers/periodic_sync.js
Executable file
259
gaia/apps/calendar/js/controllers/periodic_sync.js
Executable file
|
|
@ -0,0 +1,259 @@
|
|||
/**
|
||||
* @fileoverview Period sync controller manages
|
||||
*
|
||||
* 1. Seeding first sync alarm when app starts.
|
||||
* 2. Syncing when a sync alarm fires and issuing a new sync alarm.
|
||||
* 3. Invalidating any existing sync alarms and issuing a new one
|
||||
* when the sync interval changes.
|
||||
*/
|
||||
define(function(require, exports) {
|
||||
'use strict';
|
||||
|
||||
var Responder = require('common/responder');
|
||||
var core = require('core');
|
||||
var debug = require('common/debug')('controllers/periodic_sync');
|
||||
var messageHandler = require('message_handler');
|
||||
|
||||
/**
|
||||
* Cached alarm previously sent to alarms db.
|
||||
* @type {Object}
|
||||
*/
|
||||
var syncAlarm;
|
||||
|
||||
/**
|
||||
* Cached sync value (every x minutes) from scheduling.
|
||||
* @type {Number}
|
||||
*/
|
||||
var prevSyncFrequency;
|
||||
|
||||
/**
|
||||
* Most recently set sync interval (every x minutes).
|
||||
* @type {Number}
|
||||
*/
|
||||
var syncFrequency;
|
||||
|
||||
/**
|
||||
* Cached promise representing pending sync operation.
|
||||
* @type {Promise}
|
||||
*/
|
||||
var syncing;
|
||||
|
||||
/**
|
||||
* Cached promise representing pending schedule operation.
|
||||
* @type {Promise}
|
||||
*/
|
||||
var scheduling;
|
||||
|
||||
var events = new Responder();
|
||||
exports.events = events;
|
||||
|
||||
var accounts;
|
||||
var settings;
|
||||
|
||||
exports.observe = function() {
|
||||
debug('Will start periodic sync controller...');
|
||||
var storeFactory = core.storeFactory;
|
||||
accounts = storeFactory.get('Account');
|
||||
settings = storeFactory.get('Setting');
|
||||
return Promise.all([
|
||||
settings.getValue('syncAlarm'),
|
||||
settings.getValue('syncFrequency')
|
||||
])
|
||||
.then(values => {
|
||||
[syncAlarm, syncFrequency] = values;
|
||||
// Trigger whenever there is a change to the accounts collection
|
||||
// since we need to re-evaluate whether periodic sync is still necessary.
|
||||
accounts.on('persist', onAccountsChange);
|
||||
accounts.on('remove', onAccountsChange);
|
||||
// Listen to the settings collection for a change to sync frequency so that
|
||||
// we can update any alarms we've sent to the alarms api accordingly.
|
||||
debug('Will listen for syncFrequencyChange...');
|
||||
settings.on('syncFrequencyChange', exports);
|
||||
// Listen for sync event from alarms api.
|
||||
messageHandler.responder.on('sync', exports);
|
||||
return scheduleSync();
|
||||
});
|
||||
};
|
||||
|
||||
exports.unobserve = function() {
|
||||
syncAlarm = null;
|
||||
prevSyncFrequency = null;
|
||||
syncFrequency = null;
|
||||
syncing = null;
|
||||
scheduling = null;
|
||||
accounts.off('persist', onAccountsChange);
|
||||
accounts.off('remove', onAccountsChange);
|
||||
settings.off('syncFrequencyChange', exports);
|
||||
messageHandler.responder.off('sync', exports);
|
||||
};
|
||||
|
||||
exports.handleEvent = function(event) {
|
||||
switch (event.type) {
|
||||
case 'sync':
|
||||
// Gets triggered by mozSetMessageHandler alarm event.
|
||||
return onSync();
|
||||
case 'syncFrequencyChange':
|
||||
// Gets triggered by settings db change to sync frequency.
|
||||
debug('Received syncFrequencyChange!');
|
||||
return onSyncFrequencyChange(event.data[0]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 1. Wait until we're done with any previous work.
|
||||
* 2. Sync.
|
||||
* 3. Schedule the next periodic sync.
|
||||
*/
|
||||
function onSync() {
|
||||
return sync().then(scheduleSync);
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Wait until we're done with any previous work.
|
||||
* 2. Schedule a periodic sync at the new interval.
|
||||
*/
|
||||
function onSyncFrequencyChange(value) {
|
||||
debug('Sync frequency changed to', value);
|
||||
syncFrequency = value;
|
||||
return maybeScheduleSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* No syncable accounts => revoke any previously scheduled sync alarms.
|
||||
* Syncable accounts and no previously scheduled sync => schedule new sync.
|
||||
*/
|
||||
function onAccountsChange() {
|
||||
debug('Looking up syncable accounts...');
|
||||
return accounts.syncableAccounts().then(syncable => {
|
||||
if (!syncable || !syncable.length) {
|
||||
debug('There are no syncable accounts!');
|
||||
revokePreviousAlarm();
|
||||
events.emit('pause');
|
||||
return;
|
||||
}
|
||||
|
||||
debug('There are', syncable.length, 'syncable accounts');
|
||||
|
||||
if (!syncAlarmIssued()) {
|
||||
debug('The first syncable account was just added.');
|
||||
return scheduleSync();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sync() {
|
||||
if (!syncing) {
|
||||
syncing = new Promise((resolve, reject) => {
|
||||
debug('Will request cpu and wifi wake locks...');
|
||||
var cpuLock = navigator.requestWakeLock('cpu');
|
||||
var wifiLock = navigator.requestWakeLock('wifi');
|
||||
debug('Will start periodic sync...');
|
||||
core.syncController.all(() => {
|
||||
debug('Sync complete! Will release cpu and wifi wake locks...');
|
||||
cpuLock.unlock();
|
||||
wifiLock.unlock();
|
||||
events.emit('sync');
|
||||
syncing = null;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return syncing;
|
||||
}
|
||||
|
||||
function scheduleSync() {
|
||||
if (scheduling) {
|
||||
return scheduling;
|
||||
}
|
||||
|
||||
scheduling = accounts.syncableAccounts()
|
||||
.then(syncable => {
|
||||
if (!syncable || !syncable.length) {
|
||||
debug('There seem to be no syncable accounts, will defer scheduling...');
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
debug('Will schedule periodic sync in:', syncFrequency);
|
||||
// Cache the sync interval which we're sending to the alarms api.
|
||||
prevSyncFrequency = syncFrequency;
|
||||
revokePreviousAlarm();
|
||||
|
||||
return issueSyncAlarm().then(cacheSyncAlarm).then(maybeScheduleSync);
|
||||
})
|
||||
.then(() => {
|
||||
events.emit('schedule');
|
||||
scheduling = null;
|
||||
})
|
||||
.catch(error => {
|
||||
debug('Error scheduling sync:', error);
|
||||
console.error(error.toString());
|
||||
scheduling = null;
|
||||
});
|
||||
|
||||
return scheduling;
|
||||
}
|
||||
|
||||
// TODO: When navigator.mozAlarms.remove (one day) returns a DOMRequest,
|
||||
// we should make this async...
|
||||
function revokePreviousAlarm() {
|
||||
if (!syncAlarmIssued()) {
|
||||
debug('No sync alarms issued, nothing to revoke...');
|
||||
return;
|
||||
}
|
||||
|
||||
debug('Will revoke alarm', syncAlarm.alarmId);
|
||||
var alarms = navigator.mozAlarms;
|
||||
alarms.remove(syncAlarm.alarmId);
|
||||
}
|
||||
|
||||
function issueSyncAlarm() {
|
||||
if (!prevSyncFrequency) {
|
||||
debug('Periodic sync disabled!');
|
||||
return Promise.resolve({ alarmId: null, start: null, end: null });
|
||||
}
|
||||
|
||||
var start = new Date();
|
||||
var end = new Date(
|
||||
start.getTime() +
|
||||
prevSyncFrequency * 60 * 1000 // minutes to ms
|
||||
);
|
||||
|
||||
var alarms = navigator.mozAlarms;
|
||||
var request = alarms.add(end, 'ignoreTimezone', { type: 'sync' });
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request.onsuccess = function() {
|
||||
resolve({ alarmId: this.result, start: start, end: end });
|
||||
};
|
||||
|
||||
request.onerror = function() {
|
||||
reject(this.error);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function cacheSyncAlarm(alarm) {
|
||||
debug('Will save alarm:', alarm);
|
||||
syncAlarm = alarm;
|
||||
return settings.set('syncAlarm', syncAlarm);
|
||||
}
|
||||
|
||||
function maybeScheduleSync() {
|
||||
if (syncFrequency === prevSyncFrequency) {
|
||||
// Nothing to do!
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (scheduling) {
|
||||
return scheduling.then(scheduleSync);
|
||||
}
|
||||
|
||||
return scheduleSync();
|
||||
}
|
||||
|
||||
function syncAlarmIssued() {
|
||||
return syncAlarm && !!syncAlarm.alarmId;
|
||||
}
|
||||
|
||||
});
|
||||
Loading…
Reference in a new issue