mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 858005 - Part 3: Alarm implementation. r=gene, r=jshih
This commit is contained in:
parent
6bcfb56ea7
commit
81f12bdf6e
@ -62,6 +62,9 @@ this.SystemMessagePermissionsTable = {
|
||||
"settings": ["read", "write"]
|
||||
},
|
||||
"media-button": { },
|
||||
"networkstats-alarm": {
|
||||
"networkstats-manage": []
|
||||
},
|
||||
"notification": {
|
||||
"desktop-notification": []
|
||||
},
|
||||
|
@ -16,8 +16,9 @@ Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
|
||||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
|
||||
const DB_NAME = "net_stats";
|
||||
const DB_VERSION = 4;
|
||||
const STORE_NAME = "net_stats";
|
||||
const DB_VERSION = 5;
|
||||
const STATS_STORE_NAME = "net_stats";
|
||||
const ALARMS_STORE_NAME = "net_alarm";
|
||||
|
||||
// Constant defining the maximum values allowed per interface. If more, older
|
||||
// will be erased.
|
||||
@ -30,20 +31,20 @@ this.NetworkStatsDB = function NetworkStatsDB() {
|
||||
if (DEBUG) {
|
||||
debug("Constructor");
|
||||
}
|
||||
this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME]);
|
||||
this.initDBHelper(DB_NAME, DB_VERSION, [STATS_STORE_NAME, ALARMS_STORE_NAME]);
|
||||
}
|
||||
|
||||
NetworkStatsDB.prototype = {
|
||||
__proto__: IndexedDBHelper.prototype,
|
||||
|
||||
dbNewTxn: function dbNewTxn(txn_type, callback, txnCb) {
|
||||
dbNewTxn: function dbNewTxn(store_name, txn_type, callback, txnCb) {
|
||||
function successCb(result) {
|
||||
txnCb(null, result);
|
||||
}
|
||||
function errorCb(error) {
|
||||
txnCb(error, null);
|
||||
}
|
||||
return this.newTxn(txn_type, STORE_NAME, callback, successCb, errorCb);
|
||||
return this.newTxn(txn_type, store_name, callback, successCb, errorCb);
|
||||
},
|
||||
|
||||
upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
|
||||
@ -58,7 +59,7 @@ NetworkStatsDB.prototype = {
|
||||
* Create the initial database schema.
|
||||
*/
|
||||
|
||||
objectStore = db.createObjectStore(STORE_NAME, { keyPath: ["connectionType", "timestamp"] });
|
||||
objectStore = db.createObjectStore(STATS_STORE_NAME, { keyPath: ["connectionType", "timestamp"] });
|
||||
objectStore.createIndex("connectionType", "connectionType", { unique: false });
|
||||
objectStore.createIndex("timestamp", "timestamp", { unique: false });
|
||||
objectStore.createIndex("rxBytes", "rxBytes", { unique: false });
|
||||
@ -77,9 +78,9 @@ NetworkStatsDB.prototype = {
|
||||
// to modify the keyPath is mandatory to delete the object store
|
||||
// and create it again. Old data is going to be deleted because the
|
||||
// networkId for each sample can not be set.
|
||||
db.deleteObjectStore(STORE_NAME);
|
||||
db.deleteObjectStore(STATS_STORE_NAME);
|
||||
|
||||
objectStore = db.createObjectStore(STORE_NAME, { keyPath: ["appId", "network", "timestamp"] });
|
||||
objectStore = db.createObjectStore(STATS_STORE_NAME, { keyPath: ["appId", "network", "timestamp"] });
|
||||
objectStore.createIndex("appId", "appId", { unique: false });
|
||||
objectStore.createIndex("network", "network", { unique: false });
|
||||
objectStore.createIndex("networkType", "networkType", { unique: false });
|
||||
@ -94,7 +95,7 @@ NetworkStatsDB.prototype = {
|
||||
}
|
||||
} else if (currVersion == 3) {
|
||||
// Delete redundent indexes (leave "network" only).
|
||||
objectStore = aTransaction.objectStore(STORE_NAME);
|
||||
objectStore = aTransaction.objectStore(STATS_STORE_NAME);
|
||||
if (objectStore.indexNames.contains("appId")) {
|
||||
objectStore.deleteIndex("appId");
|
||||
}
|
||||
@ -120,18 +121,82 @@ NetworkStatsDB.prototype = {
|
||||
if (DEBUG) {
|
||||
debug("Deleted redundent indexes for version 4");
|
||||
}
|
||||
} else if (currVersion == 4) {
|
||||
// In order to manage alarms, it is necessary to use a global counter
|
||||
// (totalBytes) that will increase regardless of the system reboot.
|
||||
objectStore = aTransaction.objectStore(STATS_STORE_NAME);
|
||||
|
||||
// Now, systemBytes will hold the old totalBytes and totalBytes will
|
||||
// keep the increasing counter. |counters| will keep the track of
|
||||
// accumulated values.
|
||||
let counters = {};
|
||||
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor){
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.value.rxSystemBytes = cursor.value.rxTotalBytes;
|
||||
cursor.value.txSystemBytes = cursor.value.txTotalBytes;
|
||||
|
||||
if (cursor.value.appId == 0) {
|
||||
let netId = cursor.value.network[0] + '' + cursor.value.network[1];
|
||||
if (!counters[netId]) {
|
||||
counters[netId] = {
|
||||
rxCounter: 0,
|
||||
txCounter: 0,
|
||||
lastRx: 0,
|
||||
lastTx: 0
|
||||
};
|
||||
}
|
||||
|
||||
let rxDiff = cursor.value.rxSystemBytes - counters[netId].lastRx;
|
||||
let txDiff = cursor.value.txSystemBytes - counters[netId].lastTx;
|
||||
if (rxDiff < 0 || txDiff < 0) {
|
||||
// System reboot between samples, so take the current one.
|
||||
rxDiff = cursor.value.rxSystemBytes;
|
||||
txDiff = cursor.value.txSystemBytes;
|
||||
}
|
||||
|
||||
counters[netId].rxCounter += rxDiff;
|
||||
counters[netId].txCounter += txDiff;
|
||||
cursor.value.rxTotalBytes = counters[netId].rxCounter;
|
||||
cursor.value.txTotalBytes = counters[netId].txCounter;
|
||||
|
||||
counters[netId].lastRx = cursor.value.rxSystemBytes;
|
||||
counters[netId].lastTx = cursor.value.txSystemBytes;
|
||||
} else {
|
||||
cursor.value.rxTotalBytes = cursor.value.rxSystemBytes;
|
||||
cursor.value.txTotalBytes = cursor.value.txSystemBytes;
|
||||
}
|
||||
|
||||
cursor.update(cursor.value);
|
||||
cursor.continue();
|
||||
};
|
||||
|
||||
// Create object store for alarms.
|
||||
objectStore = db.createObjectStore(ALARMS_STORE_NAME, { keyPath: "id", autoIncrement: true });
|
||||
objectStore.createIndex("alarm", ['networkId','threshold'], { unique: false });
|
||||
objectStore.createIndex("manifestURL", "manifestURL", { unique: false });
|
||||
|
||||
if (DEBUG) {
|
||||
debug("Created alarms store for version 5");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
importData: function importData(aStats) {
|
||||
let stats = { appId: aStats.appId,
|
||||
network: [aStats.networkId, aStats.networkType],
|
||||
timestamp: aStats.timestamp,
|
||||
rxBytes: aStats.rxBytes,
|
||||
txBytes: aStats.txBytes,
|
||||
rxTotalBytes: aStats.rxTotalBytes,
|
||||
txTotalBytes: aStats.txTotalBytes };
|
||||
let stats = { appId: aStats.appId,
|
||||
network: [aStats.networkId, aStats.networkType],
|
||||
timestamp: aStats.timestamp,
|
||||
rxBytes: aStats.rxBytes,
|
||||
txBytes: aStats.txBytes,
|
||||
rxSystemBytes: aStats.rxSystemBytes,
|
||||
txSystemBytes: aStats.txSystemBytes,
|
||||
rxTotalBytes: aStats.rxTotalBytes,
|
||||
txTotalBytes: aStats.txTotalBytes };
|
||||
|
||||
return stats;
|
||||
},
|
||||
@ -160,18 +225,20 @@ NetworkStatsDB.prototype = {
|
||||
saveStats: function saveStats(aStats, aResultCb) {
|
||||
let timestamp = this.normalizeDate(aStats.date);
|
||||
|
||||
let stats = { appId: aStats.appId,
|
||||
networkId: aStats.networkId,
|
||||
networkType: aStats.networkType,
|
||||
timestamp: timestamp,
|
||||
rxBytes: (aStats.appId == 0) ? 0 : aStats.rxBytes,
|
||||
txBytes: (aStats.appId == 0) ? 0 : aStats.txBytes,
|
||||
rxTotalBytes: (aStats.appId == 0) ? aStats.rxBytes : 0,
|
||||
txTotalBytes: (aStats.appId == 0) ? aStats.txBytes : 0 };
|
||||
let stats = { appId: aStats.appId,
|
||||
networkId: aStats.networkId,
|
||||
networkType: aStats.networkType,
|
||||
timestamp: timestamp,
|
||||
rxBytes: (aStats.appId == 0) ? 0 : aStats.rxBytes,
|
||||
txBytes: (aStats.appId == 0) ? 0 : aStats.txBytes,
|
||||
rxSystemBytes: (aStats.appId == 0) ? aStats.rxBytes : 0,
|
||||
txSystemBytes: (aStats.appId == 0) ? aStats.txBytes : 0,
|
||||
rxTotalBytes: (aStats.appId == 0) ? aStats.rxBytes : 0,
|
||||
txTotalBytes: (aStats.appId == 0) ? aStats.txBytes : 0 };
|
||||
|
||||
stats = this.importData(stats);
|
||||
|
||||
this.dbNewTxn("readwrite", function(aTxn, aStore) {
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readwrite", function(aTxn, aStore) {
|
||||
if (DEBUG) {
|
||||
debug("Filtered time: " + new Date(timestamp));
|
||||
debug("New stats: " + JSON.stringify(stats));
|
||||
@ -241,21 +308,29 @@ NetworkStatsDB.prototype = {
|
||||
// |txTotalBytes|/|rxTotalBytes| and the last |txTotalBytes|/|rxTotalBytes|.
|
||||
// Else, the incoming data is per-app data (|newSample.appId| is not 0),
|
||||
// the |txBytes|/|rxBytes| is directly the new |txBytes|/|rxBytes|.
|
||||
let rxDiff = 0;
|
||||
let txDiff = 0;
|
||||
if (aNewSample.appId == 0) {
|
||||
let rxDiff = aNewSample.rxTotalBytes - lastSample.rxTotalBytes;
|
||||
let txDiff = aNewSample.txTotalBytes - lastSample.txTotalBytes;
|
||||
rxDiff = aNewSample.rxSystemBytes - lastSample.rxSystemBytes;
|
||||
txDiff = aNewSample.txSystemBytes - lastSample.txSystemBytes;
|
||||
if (rxDiff < 0 || txDiff < 0) {
|
||||
rxDiff = aNewSample.rxTotalBytes;
|
||||
txDiff = aNewSample.txTotalBytes;
|
||||
rxDiff = aNewSample.rxSystemBytes;
|
||||
txDiff = aNewSample.txSystemBytes;
|
||||
}
|
||||
aNewSample.rxBytes = rxDiff;
|
||||
aNewSample.txBytes = txDiff;
|
||||
|
||||
aNewSample.rxTotalBytes = lastSample.rxTotalBytes + rxDiff;
|
||||
aNewSample.txTotalBytes = lastSample.txTotalBytes + txDiff;
|
||||
} else {
|
||||
rxDiff = aNewSample.rxBytes;
|
||||
txDiff = aNewSample.txBytes;
|
||||
}
|
||||
|
||||
if (diff == 1) {
|
||||
// New element.
|
||||
|
||||
// If the incoming data is per-data data, new |rxTotalBytes|/|txTotalBytes|
|
||||
// If the incoming data is per-app data, new |rxTotalBytes|/|txTotalBytes|
|
||||
// needs to be obtained by adding new |rxBytes|/|txBytes| to last
|
||||
// |rxTotalBytes|/|txTotalBytes|.
|
||||
if (aNewSample.appId != 0) {
|
||||
@ -277,13 +352,15 @@ NetworkStatsDB.prototype = {
|
||||
let data = [];
|
||||
for (let i = diff - 2; i >= 0; i--) {
|
||||
let time = aNewSample.timestamp - SAMPLE_RATE * (i + 1);
|
||||
let sample = { appId: aNewSample.appId,
|
||||
network: aNewSample.network,
|
||||
timestamp: time,
|
||||
rxBytes: 0,
|
||||
txBytes: 0,
|
||||
rxTotalBytes: lastSample.rxTotalBytes,
|
||||
txTotalBytes: lastSample.txTotalBytes };
|
||||
let sample = { appId: aNewSample.appId,
|
||||
network: aNewSample.network,
|
||||
timestamp: time,
|
||||
rxBytes: 0,
|
||||
txBytes: 0,
|
||||
rxSystemBytes: lastSample.rxSystemBytes,
|
||||
txSystemBytes: lastSample.txSystemBytes,
|
||||
rxTotalBytes: lastSample.rxTotalBytes,
|
||||
txTotalBytes: lastSample.txTotalBytes };
|
||||
|
||||
data.push(sample);
|
||||
}
|
||||
@ -293,27 +370,20 @@ NetworkStatsDB.prototype = {
|
||||
return;
|
||||
}
|
||||
if (diff == 0 || diff < 0) {
|
||||
// New element received before samplerate period.
|
||||
// It means that device has been restarted (or clock / timezone change).
|
||||
// Update element.
|
||||
// New element received before samplerate period. It means that device has
|
||||
// been restarted (or clock / timezone change).
|
||||
// Update element. If diff < 0, clock or timezone changed back. Place data
|
||||
// in the last sample.
|
||||
|
||||
// If diff < 0, clock or timezone changed back. Place data in the last sample.
|
||||
// Old |rxTotalBytes|/|txTotalBytes| needs to get updated by adding the
|
||||
// last |rxTotalBytes|/|txTotalBytes|.
|
||||
lastSample.rxBytes += rxDiff;
|
||||
lastSample.txBytes += txDiff;
|
||||
lastSample.rxSystemBytes = aNewSample.rxSystemBytes;
|
||||
lastSample.txSystemBytes = aNewSample.txSystemBytes;
|
||||
lastSample.rxTotalBytes += rxDiff;
|
||||
lastSample.txTotalBytes += txDiff;
|
||||
|
||||
lastSample.rxBytes += aNewSample.rxBytes;
|
||||
lastSample.txBytes += aNewSample.txBytes;
|
||||
|
||||
// If incoming data is obtained from netd, last |rxTotalBytes|/|txTotalBytes|
|
||||
// needs to get updated by replacing the new |rxTotalBytes|/|txTotalBytes|.
|
||||
if (aNewSample.appId == 0) {
|
||||
lastSample.rxTotalBytes = aNewSample.rxTotalBytes;
|
||||
lastSample.txTotalBytes = aNewSample.txTotalBytes;
|
||||
} else {
|
||||
// Else, the incoming data is per-app data, old |rxTotalBytes|/
|
||||
// |txTotalBytes| needs to get updated by adding the new
|
||||
// |rxBytes|/|txBytes| to last |rxTotalBytes|/|txTotalBytes|.
|
||||
lastSample.rxTotalBytes += aNewSample.rxBytes;
|
||||
lastSample.txTotalBytes += aNewSample.txBytes;
|
||||
}
|
||||
if (DEBUG) {
|
||||
debug("Update: " + JSON.stringify(lastSample));
|
||||
}
|
||||
@ -379,7 +449,7 @@ NetworkStatsDB.prototype = {
|
||||
let self = this;
|
||||
|
||||
// Clear and save an empty sample to keep sync with system counters
|
||||
this.dbNewTxn("readwrite", function(aTxn, aStore) {
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readwrite", function(aTxn, aStore) {
|
||||
let sample = null;
|
||||
let request = aStore.index("network").openCursor(network, "prev");
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
@ -431,6 +501,33 @@ NetworkStatsDB.prototype = {
|
||||
this.clearInterfaceStats(aNetworks[index], callback);
|
||||
},
|
||||
|
||||
getCurrentStats: function getCurrentStats(aNetwork, aDate, aResultCb) {
|
||||
if (DEBUG) {
|
||||
debug("Get current stats for " + JSON.stringify(aNetwork) + " since " + aDate);
|
||||
}
|
||||
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(txn, store) {
|
||||
let request = null;
|
||||
let network = [aNetwork.id, aNetwork.type];
|
||||
if (aDate) {
|
||||
let start = this.normalizeDate(aDate);
|
||||
let lowerFilter = [0, network, start];
|
||||
let range = this.dbGlobal.IDBKeyRange.lowerBound(lowerFilter, false);
|
||||
request = store.openCursor(range);
|
||||
} else {
|
||||
request = store.index("network").openCursor(network, "prev");
|
||||
}
|
||||
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
txn.result = null;
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
txn.result = cursor.value;
|
||||
}
|
||||
};
|
||||
}.bind(this), aResultCb);
|
||||
},
|
||||
|
||||
find: function find(aResultCb, aNetwork, aStart, aEnd, aAppId, aManifestURL) {
|
||||
let offset = (new Date()).getTimezoneOffset() * 60 * 1000;
|
||||
let start = this.normalizeDate(aStart);
|
||||
@ -443,7 +540,7 @@ NetworkStatsDB.prototype = {
|
||||
debug("End time: " + new Date(end));
|
||||
}
|
||||
|
||||
this.dbNewTxn("readonly", function(aTxn, aStore) {
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) {
|
||||
let network = [aNetwork.id, aNetwork.type];
|
||||
let lowerFilter = [aAppId, network, start];
|
||||
let upperFilter = [aAppId, network, end];
|
||||
@ -503,7 +600,7 @@ NetworkStatsDB.prototype = {
|
||||
},
|
||||
|
||||
getAvailableNetworks: function getAvailableNetworks(aResultCb) {
|
||||
this.dbNewTxn("readonly", function(aTxn, aStore) {
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) {
|
||||
if (!aTxn.result) {
|
||||
aTxn.result = [];
|
||||
}
|
||||
@ -522,7 +619,7 @@ NetworkStatsDB.prototype = {
|
||||
},
|
||||
|
||||
isNetworkAvailable: function isNetworkAvailable(aNetwork, aResultCb) {
|
||||
this.dbNewTxn("readonly", function(aTxn, aStore) {
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) {
|
||||
if (!aTxn.result) {
|
||||
aTxn.result = false;
|
||||
}
|
||||
@ -546,10 +643,159 @@ NetworkStatsDB.prototype = {
|
||||
},
|
||||
|
||||
logAllRecords: function logAllRecords(aResultCb) {
|
||||
this.dbNewTxn("readonly", function(aTxn, aStore) {
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) {
|
||||
aStore.mozGetAll().onsuccess = function onsuccess(event) {
|
||||
aTxn.result = event.target.result;
|
||||
};
|
||||
}, aResultCb);
|
||||
},
|
||||
|
||||
alarmToRecord: function alarmToRecord(aAlarm) {
|
||||
let record = { networkId: aAlarm.networkId,
|
||||
threshold: aAlarm.threshold,
|
||||
data: aAlarm.data,
|
||||
manifestURL: aAlarm.manifestURL,
|
||||
pageURL: aAlarm.pageURL };
|
||||
|
||||
if (aAlarm.id) {
|
||||
record.id = aAlarm.id;
|
||||
}
|
||||
|
||||
return record;
|
||||
},
|
||||
|
||||
recordToAlarm: function recordToalarm(aRecord) {
|
||||
let alarm = { networkId: aRecord.networkId,
|
||||
threshold: aRecord.threshold,
|
||||
data: aRecord.data,
|
||||
manifestURL: aRecord.manifestURL,
|
||||
pageURL: aRecord.pageURL };
|
||||
|
||||
if (aRecord.id) {
|
||||
alarm.id = aRecord.id;
|
||||
}
|
||||
|
||||
return alarm;
|
||||
},
|
||||
|
||||
addAlarm: function addAlarm(aAlarm, aResultCb) {
|
||||
this.dbNewTxn(ALARMS_STORE_NAME, "readwrite", function(txn, store) {
|
||||
if (DEBUG) {
|
||||
debug("Going to add " + JSON.stringify(aAlarm));
|
||||
}
|
||||
|
||||
let record = this.alarmToRecord(aAlarm);
|
||||
store.put(record).onsuccess = function setResult(aEvent) {
|
||||
txn.result = aEvent.target.result;
|
||||
if (DEBUG) {
|
||||
debug("Request successful. New record ID: " + txn.result);
|
||||
}
|
||||
};
|
||||
}.bind(this), aResultCb);
|
||||
},
|
||||
|
||||
getFirstAlarm: function getFirstAlarm(aNetworkId, aResultCb) {
|
||||
let self = this;
|
||||
|
||||
this.dbNewTxn(ALARMS_STORE_NAME, "readonly", function(txn, store) {
|
||||
if (DEBUG) {
|
||||
debug("Get first alarm for network " + aNetworkId);
|
||||
}
|
||||
|
||||
let lowerFilter = [aNetworkId, 0];
|
||||
let upperFilter = [aNetworkId, ""];
|
||||
let range = IDBKeyRange.bound(lowerFilter, upperFilter);
|
||||
|
||||
store.index("alarm").openCursor(range).onsuccess = function onsuccess(event) {
|
||||
let cursor = event.target.result;
|
||||
txn.result = null;
|
||||
if (cursor) {
|
||||
txn.result = self.recordToAlarm(cursor.value);
|
||||
}
|
||||
};
|
||||
}, aResultCb);
|
||||
},
|
||||
|
||||
removeAlarm: function removeAlarm(aAlarmId, aManifestURL, aResultCb) {
|
||||
this.dbNewTxn(ALARMS_STORE_NAME, "readwrite", function(txn, store) {
|
||||
if (DEBUG) {
|
||||
debug("Remove alarm " + aAlarmId);
|
||||
}
|
||||
|
||||
store.get(aAlarmId).onsuccess = function onsuccess(event) {
|
||||
let record = event.target.result;
|
||||
txn.result = false;
|
||||
if (!record || (aManifestURL && record.manifestURL != aManifestURL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
store.delete(aAlarmId);
|
||||
txn.result = true;
|
||||
}
|
||||
}, aResultCb);
|
||||
},
|
||||
|
||||
removeAlarms: function removeAlarms(aManifestURL, aResultCb) {
|
||||
this.dbNewTxn(ALARMS_STORE_NAME, "readwrite", function(txn, store) {
|
||||
if (DEBUG) {
|
||||
debug("Remove alarms of " + aManifestURL);
|
||||
}
|
||||
|
||||
store.index("manifestURL").openCursor(aManifestURL)
|
||||
.onsuccess = function onsuccess(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
cursor.delete();
|
||||
cursor.continue();
|
||||
}
|
||||
}
|
||||
}, aResultCb);
|
||||
},
|
||||
|
||||
updateAlarm: function updateAlarm(aAlarm, aResultCb) {
|
||||
let self = this;
|
||||
this.dbNewTxn(ALARMS_STORE_NAME, "readwrite", function(txn, store) {
|
||||
if (DEBUG) {
|
||||
debug("Update alarm " + aAlarm.id);
|
||||
}
|
||||
|
||||
let record = self.alarmToRecord(aAlarm);
|
||||
store.openCursor(record.id).onsuccess = function onsuccess(event) {
|
||||
let cursor = event.target.result;
|
||||
txn.result = false;
|
||||
if (cursor) {
|
||||
cursor.update(record);
|
||||
txn.result = true;
|
||||
}
|
||||
}
|
||||
}, aResultCb);
|
||||
},
|
||||
|
||||
getAlarms: function getAlarms(aNetworkId, aManifestURL, aResultCb) {
|
||||
this.dbNewTxn(ALARMS_STORE_NAME, "readonly", function(txn, store) {
|
||||
if (DEBUG) {
|
||||
debug("Get alarms for " + aManifestURL);
|
||||
}
|
||||
|
||||
txn.result = [];
|
||||
store.index("manifestURL").openCursor(aManifestURL)
|
||||
.onsuccess = function onsuccess(event) {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aNetworkId || cursor.value.networkId == aNetworkId) {
|
||||
let alarm = { id: cursor.value.id,
|
||||
networkId: cursor.value.networkId,
|
||||
threshold: cursor.value.threshold,
|
||||
data: cursor.value.data };
|
||||
|
||||
txn.result.push(alarm);
|
||||
}
|
||||
|
||||
cursor.continue();
|
||||
}
|
||||
}, aResultCb);
|
||||
}
|
||||
};
|
||||
|
@ -30,7 +30,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
// NetworkStatsData
|
||||
const nsIClassInfo = Ci.nsIClassInfo;
|
||||
const NETWORKSTATSDATA_CID = Components.ID("{3b16fe17-5583-483a-b486-b64a3243221c}");
|
||||
const nsIDOMMozNetworkStatsData = Components.interfaces.nsIDOMMozNetworkStatsData;
|
||||
const nsIDOMMozNetworkStatsData = Ci.nsIDOMMozNetworkStatsData;
|
||||
|
||||
function NetworkStatsData(aData) {
|
||||
this.rxBytes = aData.rxBytes;
|
||||
@ -40,10 +40,10 @@ function NetworkStatsData(aData) {
|
||||
|
||||
NetworkStatsData.prototype = {
|
||||
__exposedProps__: {
|
||||
rxBytes: 'r',
|
||||
txBytes: 'r',
|
||||
date: 'r',
|
||||
},
|
||||
rxBytes: 'r',
|
||||
txBytes: 'r',
|
||||
date: 'r',
|
||||
},
|
||||
|
||||
classID : NETWORKSTATSDATA_CID,
|
||||
classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSDATA_CID,
|
||||
@ -58,7 +58,7 @@ NetworkStatsData.prototype = {
|
||||
// NetworkStatsInterface
|
||||
const NETWORKSTATSINTERFACE_CONTRACTID = "@mozilla.org/networkstatsinterface;1";
|
||||
const NETWORKSTATSINTERFACE_CID = Components.ID("{f540615b-d803-43ff-8200-2a9d145a5645}");
|
||||
const nsIDOMMozNetworkStatsInterface = Components.interfaces.nsIDOMMozNetworkStatsInterface;
|
||||
const nsIDOMMozNetworkStatsInterface = Ci.nsIDOMMozNetworkStatsInterface;
|
||||
|
||||
function NetworkStatsInterface(aNetwork) {
|
||||
if (DEBUG) {
|
||||
@ -70,9 +70,9 @@ function NetworkStatsInterface(aNetwork) {
|
||||
|
||||
NetworkStatsInterface.prototype = {
|
||||
__exposedProps__: {
|
||||
id: 'r',
|
||||
type: 'r',
|
||||
},
|
||||
id: 'r',
|
||||
type: 'r',
|
||||
},
|
||||
|
||||
classID : NETWORKSTATSINTERFACE_CID,
|
||||
classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSINTERFACE_CID,
|
||||
@ -87,7 +87,7 @@ NetworkStatsInterface.prototype = {
|
||||
// NetworkStats
|
||||
const NETWORKSTATS_CONTRACTID = "@mozilla.org/networkstats;1";
|
||||
const NETWORKSTATS_CID = Components.ID("{b6fc4b14-628d-4c99-bf4e-e4ed56916cbe}");
|
||||
const nsIDOMMozNetworkStats = Components.interfaces.nsIDOMMozNetworkStats;
|
||||
const nsIDOMMozNetworkStats = Ci.nsIDOMMozNetworkStats;
|
||||
|
||||
function NetworkStats(aWindow, aStats) {
|
||||
if (DEBUG) {
|
||||
@ -106,12 +106,12 @@ function NetworkStats(aWindow, aStats) {
|
||||
|
||||
NetworkStats.prototype = {
|
||||
__exposedProps__: {
|
||||
manifestURL: 'r',
|
||||
network: 'r',
|
||||
start: 'r',
|
||||
end: 'r',
|
||||
data: 'r',
|
||||
},
|
||||
manifestURL: 'r',
|
||||
network: 'r',
|
||||
start: 'r',
|
||||
end: 'r',
|
||||
data: 'r',
|
||||
},
|
||||
|
||||
classID : NETWORKSTATS_CID,
|
||||
classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATS_CID,
|
||||
@ -125,11 +125,40 @@ NetworkStats.prototype = {
|
||||
nsIDOMMozNetworkStatsInterface])
|
||||
}
|
||||
|
||||
// NetworkStatsAlarm
|
||||
const NETWORKSTATSALARM_CID = Components.ID("{063ebeb2-5c6e-47ae-bdcd-5e6ebdc7a68c}");
|
||||
const nsIDOMMozNetworkStatsAlarm = Ci.nsIDOMMozNetworkStatsAlarm;
|
||||
|
||||
function NetworkStatsAlarm(aAlarm) {
|
||||
this.alarmId = aAlarm.id;
|
||||
this.network = new NetworkStatsInterface(aAlarm.network);
|
||||
this.threshold = aAlarm.threshold;
|
||||
this.data = aAlarm.data;
|
||||
}
|
||||
|
||||
NetworkStatsAlarm.prototype = {
|
||||
__exposedProps__: {
|
||||
alarmId: 'r',
|
||||
network: 'r',
|
||||
threshold: 'r',
|
||||
data: 'r',
|
||||
},
|
||||
|
||||
classID : NETWORKSTATSALARM_CID,
|
||||
classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSALARM_CID,
|
||||
contractID:"@mozilla.org/networkstatsalarm;1",
|
||||
classDescription: "NetworkStatsAlarm",
|
||||
interfaces: [nsIDOMMozNetworkStatsAlarm],
|
||||
flags: nsIClassInfo.DOM_OBJECT}),
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsAlarm])
|
||||
};
|
||||
|
||||
// NetworkStatsManager
|
||||
|
||||
const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1";
|
||||
const NETWORKSTATSMANAGER_CID = Components.ID("{5f033d31-c9a2-4e2d-83aa-6a807f1e0c11}");
|
||||
const nsIDOMMozNetworkStatsManager = Components.interfaces.nsIDOMMozNetworkStatsManager;
|
||||
const NETWORKSTATSMANAGER_CID = Components.ID("{50d109b8-0d7f-4208-81fe-5f07a759f159}");
|
||||
const nsIDOMMozNetworkStatsManager = Ci.nsIDOMMozNetworkStatsManager;
|
||||
|
||||
function NetworkStatsManager() {
|
||||
if (DEBUG) {
|
||||
@ -189,6 +218,52 @@ NetworkStatsManager.prototype = {
|
||||
return request;
|
||||
},
|
||||
|
||||
addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) {
|
||||
this.checkPrivileges();
|
||||
|
||||
if (!aOptions) {
|
||||
aOptions = Object.create(null);
|
||||
}
|
||||
|
||||
let request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
|
||||
{id: this.getRequestId(request),
|
||||
data: {network: aNetwork,
|
||||
threshold: aThreshold,
|
||||
startTime: aOptions.startTime,
|
||||
data: aOptions.data,
|
||||
manifestURL: this.manifestURL,
|
||||
pageURL: this.pageURL}});
|
||||
return request;
|
||||
},
|
||||
|
||||
getAllAlarms: function getAllAlarms(aNetwork) {
|
||||
this.checkPrivileges();
|
||||
|
||||
let request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("NetworkStats:GetAlarms",
|
||||
{id: this.getRequestId(request),
|
||||
data: {network: aNetwork,
|
||||
manifestURL: this.manifestURL}});
|
||||
return request;
|
||||
},
|
||||
|
||||
removeAlarms: function removeAlarms(aAlarmId) {
|
||||
this.checkPrivileges();
|
||||
|
||||
if (aAlarmId == 0) {
|
||||
aAlarmId = -1;
|
||||
}
|
||||
|
||||
let request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("NetworkStats:RemoveAlarms",
|
||||
{id: this.getRequestId(request),
|
||||
data: {alarmId: aAlarmId,
|
||||
manifestURL: this.manifestURL}});
|
||||
|
||||
return request;
|
||||
},
|
||||
|
||||
getAvailableNetworks: function getAvailableNetworks() {
|
||||
this.checkPrivileges();
|
||||
|
||||
@ -212,8 +287,8 @@ NetworkStatsManager.prototype = {
|
||||
if (DEBUG) {
|
||||
debug("NetworkStatsmanager::receiveMessage: " + aMessage.name);
|
||||
}
|
||||
let msg = aMessage.json;
|
||||
|
||||
let msg = aMessage.json;
|
||||
let req = this.takeRequest(msg.id);
|
||||
if (!req) {
|
||||
if (DEBUG) {
|
||||
@ -260,6 +335,30 @@ NetworkStatsManager.prototype = {
|
||||
Services.DOMRequest.fireSuccess(req, true);
|
||||
break;
|
||||
|
||||
case "NetworkStats:SetAlarm:Return":
|
||||
case "NetworkStats:RemoveAlarms:Return":
|
||||
if (msg.error) {
|
||||
Services.DOMRequest.fireError(req, msg.error);
|
||||
return;
|
||||
}
|
||||
|
||||
Services.DOMRequest.fireSuccess(req, msg.result);
|
||||
break;
|
||||
|
||||
case "NetworkStats:GetAlarms:Return":
|
||||
if (msg.error) {
|
||||
Services.DOMRequest.fireError(req, msg.error);
|
||||
return;
|
||||
}
|
||||
|
||||
let alarms = Cu.createArrayIn(this._window);
|
||||
for (let i = 0; i < msg.result.length; i++) {
|
||||
alarms.push(new NetworkStatsAlarm(msg.result[i]));
|
||||
}
|
||||
|
||||
Services.DOMRequest.fireSuccess(req, alarms);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (DEBUG) {
|
||||
debug("Wrong message: " + aMessage.name);
|
||||
@ -293,7 +392,21 @@ NetworkStatsManager.prototype = {
|
||||
this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return",
|
||||
"NetworkStats:GetAvailableNetworks:Return",
|
||||
"NetworkStats:Clear:Return",
|
||||
"NetworkStats:ClearAll:Return"]);
|
||||
"NetworkStats:ClearAll:Return",
|
||||
"NetworkStats:SetAlarm:Return",
|
||||
"NetworkStats:GetAlarms:Return",
|
||||
"NetworkStats:RemoveAlarms:Return"]);
|
||||
|
||||
// Init app properties.
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
|
||||
this.manifestURL = appsService.getManifestURLByLocalId(principal.appId);
|
||||
|
||||
let isApp = !!this.manifestURL.length;
|
||||
if (isApp) {
|
||||
this.pageURL = principal.URI.spec;
|
||||
}
|
||||
},
|
||||
|
||||
// Called from DOMRequestIpcHelper
|
||||
@ -316,7 +429,8 @@ NetworkStatsManager.prototype = {
|
||||
flags: nsIClassInfo.DOM_OBJECT})
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsData,
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm,
|
||||
NetworkStatsData,
|
||||
NetworkStatsInterface,
|
||||
NetworkStats,
|
||||
NetworkStatsManager]);
|
||||
|
@ -7,6 +7,9 @@ contract @mozilla.org/networkStats;1 {b6fc4b14-628d-4c99-bf4e-e4ed56916cbe}
|
||||
component {f540615b-d803-43ff-8200-2a9d145a5645} NetworkStatsManager.js
|
||||
contract @mozilla.org/networkstatsinterface;1 {f540615b-d803-43ff-8200-2a9d145a5645}
|
||||
|
||||
component {5f033d31-c9a2-4e2d-83aa-6a807f1e0c11} NetworkStatsManager.js
|
||||
contract @mozilla.org/networkStatsManager;1 {5f033d31-c9a2-4e2d-83aa-6a807f1e0c11}
|
||||
component {063ebeb2-5c6e-47ae-bdcd-5e6ebdc7a68c} NetworkStatsManager.js
|
||||
contract @mozilla.org/networkstatsalarm;1 {063ebeb2-5c6e-47ae-bdcd-5e6ebdc7a68c}
|
||||
|
||||
component {50d109b8-0d7f-4208-81fe-5f07a759f159} NetworkStatsManager.js
|
||||
contract @mozilla.org/networkStatsManager;1 {50d109b8-0d7f-4208-81fe-5f07a759f159}
|
||||
category JavaScript-navigator-property mozNetworkStats @mozilla.org/networkStatsManager;1
|
||||
|
@ -22,6 +22,8 @@ Cu.import("resource://gre/modules/NetworkStatsDB.jsm");
|
||||
const NET_NETWORKSTATSSERVICE_CONTRACTID = "@mozilla.org/network/netstatsservice;1";
|
||||
const NET_NETWORKSTATSSERVICE_CID = Components.ID("{18725604-e9ac-488a-8aa0-2471e7f6c0a4}");
|
||||
|
||||
const TOPIC_BANDWIDTH_CONTROL = "netd-bandwidth-control"
|
||||
|
||||
const TOPIC_INTERFACE_REGISTERED = "network-interface-registered";
|
||||
const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
|
||||
const NET_TYPE_WIFI = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
|
||||
@ -50,6 +52,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
||||
"@mozilla.org/settingsService;1",
|
||||
"nsISettingsService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "messenger",
|
||||
"@mozilla.org/system-message-internal;1",
|
||||
"nsISystemMessagesInternal");
|
||||
|
||||
this.NetworkStatsService = {
|
||||
init: function() {
|
||||
debug("Service started");
|
||||
@ -57,6 +63,7 @@ this.NetworkStatsService = {
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
Services.obs.addObserver(this, TOPIC_INTERFACE_REGISTERED, false);
|
||||
Services.obs.addObserver(this, TOPIC_INTERFACE_UNREGISTERED, false);
|
||||
Services.obs.addObserver(this, TOPIC_BANDWIDTH_CONTROL, false);
|
||||
Services.obs.addObserver(this, "profile-after-change", false);
|
||||
|
||||
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
@ -87,6 +94,9 @@ this.NetworkStatsService = {
|
||||
this.messages = ["NetworkStats:Get",
|
||||
"NetworkStats:Clear",
|
||||
"NetworkStats:ClearAll",
|
||||
"NetworkStats:SetAlarm",
|
||||
"NetworkStats:GetAlarms",
|
||||
"NetworkStats:RemoveAlarms",
|
||||
"NetworkStats:GetAvailableNetworks",
|
||||
"NetworkStats:SampleRate",
|
||||
"NetworkStats:MaxStorageAge"];
|
||||
@ -107,6 +117,9 @@ this.NetworkStatsService = {
|
||||
|
||||
this.updateQueue = [];
|
||||
this.isQueueRunning = false;
|
||||
|
||||
this._currentAlarms = {};
|
||||
this.initAlarms();
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
@ -129,6 +142,15 @@ this.NetworkStatsService = {
|
||||
case "NetworkStats:ClearAll":
|
||||
this.clearDB(mm, msg);
|
||||
break;
|
||||
case "NetworkStats:SetAlarm":
|
||||
this.setAlarm(mm, msg);
|
||||
break;
|
||||
case "NetworkStats:GetAlarms":
|
||||
this.getAlarms(mm, msg);
|
||||
break;
|
||||
case "NetworkStats:RemoveAlarms":
|
||||
this.removeAlarms(mm, msg);
|
||||
break;
|
||||
case "NetworkStats:GetAvailableNetworks":
|
||||
this.getAvailableNetworks(mm, msg);
|
||||
break;
|
||||
@ -146,7 +168,7 @@ this.NetworkStatsService = {
|
||||
case TOPIC_INTERFACE_REGISTERED:
|
||||
case TOPIC_INTERFACE_UNREGISTERED:
|
||||
|
||||
// If new interface is registered (notified from NetworkManager),
|
||||
// If new interface is registered (notified from NetworkService),
|
||||
// the stats are updated for the new interface without waiting to
|
||||
// complete the updating period.
|
||||
|
||||
@ -158,9 +180,27 @@ this.NetworkStatsService = {
|
||||
break;
|
||||
}
|
||||
|
||||
this._updateCurrentAlarm(netId);
|
||||
|
||||
debug("NetId: " + netId);
|
||||
this.updateStats(netId);
|
||||
break;
|
||||
|
||||
case TOPIC_BANDWIDTH_CONTROL:
|
||||
debug("Bandwidth message from netd: " + JSON.stringify(aData));
|
||||
|
||||
let interfaceName = aData.substring(aData.lastIndexOf(" ") + 1);
|
||||
for (let networkId in this._networks) {
|
||||
if (interfaceName == this._networks[networkId].interfaceName) {
|
||||
let currentAlarm = this._currentAlarms[networkId];
|
||||
if (Object.getOwnPropertyNames(currentAlarm).length !== 0) {
|
||||
this._fireAlarm(currentAlarm.alarm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "xpcom-shutdown":
|
||||
debug("Service shutdown");
|
||||
|
||||
@ -172,6 +212,7 @@ this.NetworkStatsService = {
|
||||
Services.obs.removeObserver(this, "profile-after-change");
|
||||
Services.obs.removeObserver(this, TOPIC_INTERFACE_REGISTERED);
|
||||
Services.obs.removeObserver(this, TOPIC_INTERFACE_UNREGISTERED);
|
||||
Services.obs.removeObserver(this, TOPIC_BANDWIDTH_CONTROL);
|
||||
|
||||
this.timer.cancel();
|
||||
this.timer = null;
|
||||
@ -266,6 +307,25 @@ this.NetworkStatsService = {
|
||||
});
|
||||
},
|
||||
|
||||
initAlarms: function initAlarms() {
|
||||
debug("Init usage alarms");
|
||||
let self = this;
|
||||
|
||||
for (let netId in this._networks) {
|
||||
this._currentAlarms[netId] = Object.create(null);
|
||||
|
||||
this._db.getFirstAlarm(netId, function getResult(error, result) {
|
||||
if (!error && result) {
|
||||
self._setAlarm(result, function onSet(error, success) {
|
||||
if (error == "InvalidStateError") {
|
||||
self._fireAlarm(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Function called from manager to get stats from database.
|
||||
* In order to return updated stats, first is performed a call to
|
||||
@ -482,8 +542,8 @@ this.NetworkStatsService = {
|
||||
}
|
||||
} else {
|
||||
// The caller is a function that has pushed new elements to the queue,
|
||||
// if isQueueRunning is false it means there is no processing currently being
|
||||
// done, so start.
|
||||
// if isQueueRunning is false it means there is no processing currently
|
||||
// being done, so start.
|
||||
if (this.isQueueRunning) {
|
||||
if(this.updateQueue.length > 1) {
|
||||
return;
|
||||
@ -515,7 +575,7 @@ this.NetworkStatsService = {
|
||||
let interfaceName = this._networks[aNetId].interfaceName;
|
||||
debug("Update stats for " + interfaceName);
|
||||
|
||||
// Request stats to NetworkManager, which will get stats from netd, passing
|
||||
// Request stats to NetworkService, which will get stats from netd, passing
|
||||
// 'networkStatsAvailable' as a callback.
|
||||
if (interfaceName) {
|
||||
networkService.getNetworkInterfaceStats(interfaceName,
|
||||
@ -706,6 +766,262 @@ this.NetworkStatsService = {
|
||||
debug(JSON.stringify(aResult));
|
||||
});
|
||||
},
|
||||
|
||||
getAlarms: function getAlarms(mm, msg) {
|
||||
let network = msg.data.network;
|
||||
let manifestURL = msg.data.manifestURL;
|
||||
|
||||
let netId = null;
|
||||
if (network) {
|
||||
netId = this.getNetworkId(network.id, network.type);
|
||||
if (!this._networks[netId]) {
|
||||
mm.sendAsyncMessage("NetworkStats:GetAlarms:Return",
|
||||
{ id: msg.id, error: "InvalidInterface", result: null });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let self = this;
|
||||
this._db.getAlarms(netId, manifestURL, function onCompleted(error, result) {
|
||||
if (error) {
|
||||
mm.sendAsyncMessage("NetworkStats:GetAlarms:Return",
|
||||
{ id: msg.id, error: error, result: result });
|
||||
return;
|
||||
}
|
||||
|
||||
let alarms = []
|
||||
// NetworkStatsManager must return the network instead of the networkId.
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
let alarm = result[i];
|
||||
alarms.push({ id: alarm.id,
|
||||
network: self._networks[alarm.networkId].network,
|
||||
threshold: alarm.threshold,
|
||||
data: alarm.data });
|
||||
}
|
||||
|
||||
mm.sendAsyncMessage("NetworkStats:GetAlarms:Return",
|
||||
{ id: msg.id, error: null, result: alarms });
|
||||
});
|
||||
},
|
||||
|
||||
removeAlarms: function removeAlarms(mm, msg) {
|
||||
let alarmId = msg.data.alarmId;
|
||||
let manifestURL = msg.data.manifestURL;
|
||||
|
||||
let self = this;
|
||||
let callback = function onRemove(error, result) {
|
||||
if (error) {
|
||||
mm.sendAsyncMessage("NetworkStats:RemoveAlarms:Return",
|
||||
{ id: msg.id, error: error, result: result });
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i in self._currentAlarms) {
|
||||
let currentAlarm = self._currentAlarms[i].alarm;
|
||||
if (currentAlarm && ((alarmId == currentAlarm.id) ||
|
||||
(alarmId == -1 && currentAlarm.manifestURL == manifestURL))) {
|
||||
|
||||
self._updateCurrentAlarm(currentAlarm.networkId);
|
||||
}
|
||||
}
|
||||
|
||||
mm.sendAsyncMessage("NetworkStats:RemoveAlarms:Return",
|
||||
{ id: msg.id, error: error, result: true });
|
||||
};
|
||||
|
||||
if (alarmId == -1) {
|
||||
this._db.removeAlarms(manifestURL, callback);
|
||||
} else {
|
||||
this._db.removeAlarm(alarmId, manifestURL, callback);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Function called from manager to set an alarm.
|
||||
*/
|
||||
setAlarm: function setAlarm(mm, msg) {
|
||||
let options = msg.data;
|
||||
let network = options.network;
|
||||
let threshold = options.threshold;
|
||||
|
||||
debug("Set alarm at " + threshold + " for " + JSON.stringify(network));
|
||||
|
||||
if (threshold < 0) {
|
||||
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
|
||||
{ id: msg.id, error: "InvalidThresholdValue", result: null });
|
||||
return;
|
||||
}
|
||||
|
||||
let netId = this.getNetworkId(network.id, network.type);
|
||||
if (!this._networks[netId]) {
|
||||
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
|
||||
{ id: msg.id, error: "InvalidiConnectionType", result: null });
|
||||
return;
|
||||
}
|
||||
|
||||
let newAlarm = {
|
||||
id: null,
|
||||
networkId: netId,
|
||||
threshold: threshold,
|
||||
absoluteThreshold: null,
|
||||
startTime: options.startTime,
|
||||
data: options.data,
|
||||
pageURL: options.pageURL,
|
||||
manifestURL: options.manifestURL
|
||||
};
|
||||
|
||||
let self = this;
|
||||
this._updateThreshold(newAlarm, function onUpdate(error, _threshold) {
|
||||
if (error) {
|
||||
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
|
||||
{ id: msg.id, error: error, result: null });
|
||||
return;
|
||||
}
|
||||
|
||||
newAlarm.absoluteThreshold = _threshold.absoluteThreshold;
|
||||
self._db.addAlarm(newAlarm, function addSuccessCb(error, newId) {
|
||||
if (error) {
|
||||
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
|
||||
{ id: msg.id, error: error, result: null });
|
||||
return;
|
||||
}
|
||||
|
||||
newAlarm.id = newId;
|
||||
self._setAlarm(newAlarm, function onSet(error, success) {
|
||||
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
|
||||
{ id: msg.id, error: error, result: newId });
|
||||
|
||||
if (error == "InvalidStateError") {
|
||||
self._fireAlarm(newAlarm);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_setAlarm: function _setAlarm(aAlarm, aCallback) {
|
||||
let currentAlarm = this._currentAlarms[aAlarm.networkId];
|
||||
if (Object.getOwnPropertyNames(currentAlarm).length !== 0 &&
|
||||
aAlarm.absoluteThreshold > currentAlarm.alarm.absoluteThreshold) {
|
||||
aCallback(null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
this._updateThreshold(aAlarm, function onUpdate(aError, aThreshold) {
|
||||
if (aError) {
|
||||
aCallback(aError, null);
|
||||
return;
|
||||
}
|
||||
|
||||
let callback = function onAlarmSet(aError) {
|
||||
if (aError) {
|
||||
debug("Set alarm error: " + aError);
|
||||
aCallback("netdError", null);
|
||||
return;
|
||||
}
|
||||
|
||||
self._currentAlarms[aAlarm.networkId].alarm = aAlarm;
|
||||
|
||||
aCallback(null, true);
|
||||
};
|
||||
|
||||
debug("Set alarm " + JSON.stringify(aAlarm));
|
||||
let interfaceName = self._networks[aAlarm.networkId].interfaceName;
|
||||
if (interfaceName) {
|
||||
networkService.setNetworkInterfaceAlarm(interfaceName,
|
||||
aThreshold.systemThreshold,
|
||||
callback);
|
||||
return;
|
||||
}
|
||||
|
||||
aCallback(null, true);
|
||||
});
|
||||
},
|
||||
|
||||
_updateThreshold: function _updateThreshold(aAlarm, aCallback) {
|
||||
let self = this;
|
||||
this.updateStats(aAlarm.networkId, function onStatsUpdated(aResult, aMessage) {
|
||||
self._db.getCurrentStats(self._networks[aAlarm.networkId].network,
|
||||
aAlarm.startTime,
|
||||
function onStatsFound(error, result) {
|
||||
if (error) {
|
||||
debug("Error getting stats for " +
|
||||
JSON.stringify(self._networks[aAlarm.networkId]) + ": " + error);
|
||||
aCallback(error, result);
|
||||
return;
|
||||
}
|
||||
|
||||
let offset = aAlarm.threshold - result.rxTotalBytes - result.txTotalBytes;
|
||||
|
||||
// Alarm set to a threshold lower than current rx/tx bytes.
|
||||
if (offset <= 0) {
|
||||
aCallback("InvalidStateError", null);
|
||||
return;
|
||||
}
|
||||
|
||||
let threshold = {
|
||||
systemThreshold: result.rxSystemBytes + result.txSystemBytes + offset,
|
||||
absoluteThreshold: result.rxTotalBytes + result.txTotalBytes + offset
|
||||
};
|
||||
|
||||
aCallback(null, threshold);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_fireAlarm: function _fireAlarm(aAlarm) {
|
||||
debug("Fire alarm");
|
||||
|
||||
let self = this;
|
||||
this._db.removeAlarm(aAlarm.id, null, function onRemove(aError, aResult){
|
||||
if (!aError && !aResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
self._fireSystemMessage(aAlarm);
|
||||
self._updateCurrentAlarm(aAlarm.networkId);
|
||||
});
|
||||
},
|
||||
|
||||
_updateCurrentAlarm: function _updateCurrentAlarm(aNetworkId) {
|
||||
this._currentAlarms[aNetworkId] = Object.create(null);
|
||||
|
||||
let self = this;
|
||||
this._db.getFirstAlarm(aNetworkId, function onGet(error, result){
|
||||
if (error) {
|
||||
debug("Error getting the first alarm");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
let interfaceName = self._networks[aNetworkId].interfaceName;
|
||||
networkService.setNetworkInterfaceAlarm(interfaceName, -1,
|
||||
function onComplete(){});
|
||||
return;
|
||||
}
|
||||
|
||||
self._setAlarm(result, function onSet(error, success){
|
||||
if (error == "InvalidStateError") {
|
||||
self._fireAlarm(result);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_fireSystemMessage: function _fireSystemMessage(aAlarm) {
|
||||
debug("Fire system message: " + JSON.stringify(aAlarm));
|
||||
|
||||
let manifestURI = Services.io.newURI(aAlarm.manifestURL, null, null);
|
||||
let pageURI = Services.io.newURI(aAlarm.pageURL, null, null);
|
||||
|
||||
let alarm = { "id": aAlarm.id,
|
||||
"threshold": aAlarm.threshold,
|
||||
"data": aAlarm.data };
|
||||
messenger.sendMessage("networkstats-alarm", alarm, pageURI, manifestURI);
|
||||
}
|
||||
};
|
||||
|
||||
NetworkStatsService.init();
|
||||
|
Loading…
Reference in New Issue
Block a user