mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 813978 - [SMS API] getMessages cursor is slow when SMS database contains large number of messages [r=ferjm]
This commit is contained in:
parent
82df292271
commit
320bd9dafe
@ -13,9 +13,9 @@ Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
|
||||
const RIL_SMSDATABASESERVICE_CONTRACTID = "@mozilla.org/sms/rilsmsdatabaseservice;1";
|
||||
const RIL_SMSDATABASESERVICE_CID = Components.ID("{a1fa610c-eb6c-4ac2-878f-b005d5e89249}");
|
||||
|
||||
const DEBUG = false;
|
||||
const DEBUG = true;
|
||||
const DB_NAME = "sms";
|
||||
const DB_VERSION = 6;
|
||||
const DB_VERSION = 7;
|
||||
const STORE_NAME = "sms";
|
||||
const MOST_RECENT_STORE_NAME = "most-recent";
|
||||
|
||||
@ -97,6 +97,13 @@ function SmsDatabaseService() {
|
||||
});
|
||||
|
||||
this.messageLists = {};
|
||||
|
||||
// cursorReqs are where we keep "live" cursor based queries.
|
||||
// Each item is an object with the following properties:
|
||||
// ids[] : the message IDs already retrieved.
|
||||
// done : a boolean indicating wether we retrieved all the ids.
|
||||
// cursor : the indexedDB cursor itself.
|
||||
this.cursorReqs = {};
|
||||
}
|
||||
SmsDatabaseService.prototype = {
|
||||
|
||||
@ -114,8 +121,10 @@ SmsDatabaseService.prototype = {
|
||||
* message list is stored as an array of primary keys.
|
||||
*/
|
||||
messageLists: null,
|
||||
cursorReqs: null,
|
||||
|
||||
lastMessageListId: 0,
|
||||
lastCursorReqId: 0,
|
||||
|
||||
/**
|
||||
* Last key value stored in the database.
|
||||
@ -178,22 +187,27 @@ SmsDatabaseService.prototype = {
|
||||
self.upgradeSchema(objectStore);
|
||||
break;
|
||||
case 2:
|
||||
if (DEBUG) debug("Upgrade to version 3. Fix existing entries.")
|
||||
if (DEBUG) debug("Upgrade to version 3. Fix existing entries.");
|
||||
objectStore = event.target.transaction.objectStore(STORE_NAME);
|
||||
self.upgradeSchema2(objectStore);
|
||||
break;
|
||||
case 3:
|
||||
if (DEBUG) debug("Upgrade to version 4. Add quick threads view.")
|
||||
if (DEBUG) debug("Upgrade to version 4. Add quick threads view.");
|
||||
self.upgradeSchema3(db, event.target.transaction);
|
||||
break;
|
||||
case 4:
|
||||
if (DEBUG) debug("Upgrade to version 5. Populate quick threads view.")
|
||||
if (DEBUG) debug("Upgrade to version 5. Populate quick threads view.");
|
||||
self.upgradeSchema4(event.target.transaction);
|
||||
break;
|
||||
case 5:
|
||||
if (DEBUG) debug("Upgrade to version 6. Use PhonenumberJS.")
|
||||
self.upgradeSchema5(event.target.transaction);
|
||||
break;
|
||||
case 6:
|
||||
if (DEBUG) debug("Upgrade to version 7. Add a `senderOrReceiver` field.");
|
||||
objectStore = event.target.transaction.objectStore(STORE_NAME);
|
||||
self.upgradeSchema6(objectStore);
|
||||
break;
|
||||
default:
|
||||
event.target.transaction.abort();
|
||||
callback("Old database version: " + event.oldVersion, null);
|
||||
@ -366,6 +380,27 @@ SmsDatabaseService.prototype = {
|
||||
// Don't perform any upgrade. See Bug 819560.
|
||||
},
|
||||
|
||||
upgradeSchema6: function upgradeSchema6(objectStore) {
|
||||
objectStore.createIndex("senderOrReceiver", "senderOrReceiver",
|
||||
{ unique: false });
|
||||
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
if (DEBUG) debug("updgradeSchema6 done");
|
||||
return;
|
||||
}
|
||||
|
||||
let message = cursor.value;
|
||||
message.senderOrReceiver =
|
||||
message.delivery == DELIVERY_SENT ? message.receiver
|
||||
: message.sender;
|
||||
|
||||
cursor.update(message);
|
||||
cursor.continue();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function to make the intersection of the partial result arrays
|
||||
* obtained within createMessageList.
|
||||
@ -379,10 +414,12 @@ SmsDatabaseService.prototype = {
|
||||
* return Array of keys containing the final result of createMessageList.
|
||||
*/
|
||||
keyIntersection: function keyIntersection(keys, filter) {
|
||||
// Always use keys[FILTER_TIMESTAMP] as base result set to be filtered.
|
||||
// This ensures the result set is always sorted by timestamp.
|
||||
// Use the FILTER_TIMESTAMP as a base filter if available, or the
|
||||
// FILTER_NUMBERS filter otherwise.
|
||||
let result = keys[FILTER_TIMESTAMP];
|
||||
if (keys[FILTER_NUMBERS].length || filter.numbers) {
|
||||
if (!result) {
|
||||
result = keys[FILTER_NUMBERS];
|
||||
} else if (keys[FILTER_NUMBERS].length || filter.numbers) {
|
||||
result = result.filter(function(i) {
|
||||
return keys[FILTER_NUMBERS].indexOf(i) != -1;
|
||||
});
|
||||
@ -454,6 +491,8 @@ SmsDatabaseService.prototype = {
|
||||
saveMessage: function saveMessage(message) {
|
||||
this.lastKey += 1;
|
||||
message.id = this.lastKey;
|
||||
message.senderOrReceiver = message.sender || message.receiver;
|
||||
|
||||
if (DEBUG) debug("Going to store " + JSON.stringify(message));
|
||||
this.newTxn(READ_WRITE, function(error, txn, stores) {
|
||||
if (error) {
|
||||
@ -503,21 +542,6 @@ SmsDatabaseService.prototype = {
|
||||
*/
|
||||
|
||||
saveReceivedMessage: function saveReceivedMessage(aSender, aBody, aMessageClass, aDate) {
|
||||
let receiver = this.mRIL.rilContext.icc ? this.mRIL.rilContext.icc.msisdn : null;
|
||||
|
||||
// Workaround an xpconnect issue with undefined string objects.
|
||||
// See bug 808220
|
||||
if (receiver === undefined || receiver === "undefined") {
|
||||
receiver = null;
|
||||
}
|
||||
|
||||
if (receiver) {
|
||||
let parsedNumber = PhoneNumberUtils.parse(receiver);
|
||||
receiver = (parsedNumber && parsedNumber.internationalNumber)
|
||||
? parsedNumber.internationalNumber
|
||||
: receiver;
|
||||
}
|
||||
|
||||
let sender = aSender;
|
||||
if (sender) {
|
||||
let parsedNumber = PhoneNumberUtils.parse(sender);
|
||||
@ -529,7 +553,7 @@ SmsDatabaseService.prototype = {
|
||||
let message = {delivery: DELIVERY_RECEIVED,
|
||||
deliveryStatus: DELIVERY_STATUS_SUCCESS,
|
||||
sender: sender,
|
||||
receiver: receiver,
|
||||
receiver: null,
|
||||
body: aBody,
|
||||
messageClass: aMessageClass,
|
||||
timestamp: aDate,
|
||||
@ -538,14 +562,6 @@ SmsDatabaseService.prototype = {
|
||||
},
|
||||
|
||||
saveSentMessage: function saveSentMessage(aReceiver, aBody, aDate) {
|
||||
let sender = this.mRIL.rilContext.icc ? this.mRIL.rilContext.icc.msisdn : null;
|
||||
|
||||
// Workaround an xpconnect issue with undefined string objects.
|
||||
// See bug 808220
|
||||
if (sender === undefined || sender === "undefined") {
|
||||
sender = null;
|
||||
}
|
||||
|
||||
let receiver = aReceiver
|
||||
if (receiver) {
|
||||
let parsedNumber = PhoneNumberUtils.parse(receiver.toString());
|
||||
@ -554,16 +570,9 @@ SmsDatabaseService.prototype = {
|
||||
: receiver;
|
||||
}
|
||||
|
||||
if (sender) {
|
||||
let parsedNumber = PhoneNumberUtils.parse(sender.toString());
|
||||
sender = (parsedNumber && parsedNumber.internationalNumber)
|
||||
? parsedNumber.internationalNumber
|
||||
: sender;
|
||||
}
|
||||
|
||||
let message = {delivery: DELIVERY_SENT,
|
||||
deliveryStatus: DELIVERY_STATUS_PENDING,
|
||||
sender: sender,
|
||||
sender: null,
|
||||
receiver: receiver,
|
||||
body: aBody,
|
||||
messageClass: MESSAGE_CLASS_NORMAL,
|
||||
@ -620,12 +629,14 @@ SmsDatabaseService.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
getMessage: function getMessage(messageId, aRequest) {
|
||||
if (DEBUG) debug("Retrieving message with ID " + messageId);
|
||||
// Internal helper to get a message.
|
||||
// Returns the sms object in aSuccess,
|
||||
// or an nsISmsRequest error code in aError
|
||||
_getMessageInternal: function getMessageInternal(messageId, aSuccess, aError) {
|
||||
this.newTxn(READ_ONLY, function (error, txn, store) {
|
||||
if (error) {
|
||||
if (DEBUG) debug(error);
|
||||
aRequest.notifyGetMessageFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
|
||||
aError(Ci.nsISmsRequest.INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
let request = store.mozGetAll(messageId);
|
||||
@ -634,13 +645,13 @@ SmsDatabaseService.prototype = {
|
||||
if (DEBUG) debug("Transaction " + txn + " completed.");
|
||||
if (request.result.length > 1) {
|
||||
if (DEBUG) debug("Got too many results for id " + messageId);
|
||||
aRequest.notifyGetMessageFailed(Ci.nsISmsRequest.UNKNOWN_ERROR);
|
||||
aError(Ci.nsISmsRequest.UNKNOWN_ERROR);
|
||||
return;
|
||||
}
|
||||
let data = request.result[0];
|
||||
if (!data) {
|
||||
if (DEBUG) debug("Message ID " + messageId + " not found");
|
||||
aRequest.notifyGetMessageFailed(Ci.nsISmsRequest.NOT_FOUND_ERROR);
|
||||
aError(Ci.nsISmsRequest.NOT_FOUND_ERROR);
|
||||
return;
|
||||
}
|
||||
if (data.id != messageId) {
|
||||
@ -648,7 +659,7 @@ SmsDatabaseService.prototype = {
|
||||
debug("Requested message ID (" + messageId + ") is " +
|
||||
"different from the one we got");
|
||||
}
|
||||
aRequest.notifyGetMessageFailed(Ci.nsISmsRequest.UNKNOWN_ERROR);
|
||||
aError(Ci.nsISmsRequest.UNKNOWN_ERROR);
|
||||
return;
|
||||
}
|
||||
let message = gSmsService.createSmsMessage(data.id,
|
||||
@ -660,7 +671,7 @@ SmsDatabaseService.prototype = {
|
||||
data.messageClass,
|
||||
data.timestamp,
|
||||
data.read);
|
||||
aRequest.notifyMessageGot(message);
|
||||
aSuccess(message);
|
||||
};
|
||||
|
||||
txn.onerror = function onerror(event) {
|
||||
@ -669,11 +680,21 @@ SmsDatabaseService.prototype = {
|
||||
debug("Caught error on transaction", event.target.errorCode);
|
||||
}
|
||||
//TODO look at event.target.errorCode, pick appropriate error constant
|
||||
aRequest.notifyGetMessageFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
|
||||
};
|
||||
aError(Ci.nsISmsRequest.INTERNAL_ERROR);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getMessage: function getMessage(messageId, aRequest) {
|
||||
this._getMessageInternal(messageId,
|
||||
function(aMessage) {
|
||||
aRequest.notifyMessageGot(aMessage);
|
||||
},
|
||||
function(aError) {
|
||||
aRequest.notifyGetMessageFailed(aError);
|
||||
});
|
||||
},
|
||||
|
||||
deleteMessage: function deleteMessage(messageId, aRequest) {
|
||||
let deleted = false;
|
||||
let self = this;
|
||||
@ -776,6 +797,65 @@ SmsDatabaseService.prototype = {
|
||||
}, [STORE_NAME, MOST_RECENT_STORE_NAME]);
|
||||
},
|
||||
|
||||
startCursorRequest: function startCurReq(aIndex, aKey, aDirection, aRequest) {
|
||||
if (DEBUG) debug("Starting cursor request on " + aIndex + " " + aDirection);
|
||||
|
||||
let self = this;
|
||||
let id = self.lastCursorReqId += 1;
|
||||
let firstMessage = true;
|
||||
|
||||
this.newTxn(READ_ONLY, function (error, txn, store) {
|
||||
if (error) {
|
||||
if (DEBUG) debug("Error creating transaction: " + error);
|
||||
aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
let cursor = store.index(aIndex).openKeyCursor(aKey, aDirection);
|
||||
self.cursorReqs[id] = { done: false,
|
||||
cursor: cursor,
|
||||
ids: [] }
|
||||
|
||||
cursor.onsuccess = function(aEvent) {
|
||||
let result = aEvent.target.result;
|
||||
let cursor = self.cursorReqs[id];
|
||||
|
||||
if (!result) {
|
||||
cursor.done = true;
|
||||
return;
|
||||
}
|
||||
|
||||
let messageId = result.primaryKey;
|
||||
if (firstMessage) {
|
||||
self._getMessageInternal(messageId,
|
||||
function(aMessage) {
|
||||
aRequest.notifyMessageListCreated(id, aMessage);
|
||||
},
|
||||
function(aError) {
|
||||
aRequest.notifyReadMessageListFailed(aError);
|
||||
}
|
||||
);
|
||||
firstMessage = false;
|
||||
} else {
|
||||
cursor.ids.push(messageId);
|
||||
}
|
||||
result.continue();
|
||||
}
|
||||
|
||||
cursor.onerror = function() {
|
||||
aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
txn.oncomplete = function oncomplete(event) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
txn.onerror = function onerror(event) {
|
||||
aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
createMessageList: function createMessageList(filter, reverse, aRequest) {
|
||||
if (DEBUG) {
|
||||
debug("Creating a message list. Filters:" +
|
||||
@ -786,12 +866,65 @@ SmsDatabaseService.prototype = {
|
||||
" read: " + filter.read +
|
||||
" reverse: " + reverse);
|
||||
}
|
||||
|
||||
// Fast paths for some common situations:
|
||||
// 1. If only one constraint is set, filter based on this one, and
|
||||
// avoid the full scan due to unrestricted date range.
|
||||
// 2. If no filters are applied, use a cursor on all messages with
|
||||
// the right direction.
|
||||
// In any other case, fallback to the slow path.
|
||||
|
||||
let constraintCount = (filter.delivery ? 1 : 0) +
|
||||
(filter.numbers ? filter.numbers.length : 0) +
|
||||
(filter.read ? 1 : 0) +
|
||||
(filter.startDate ? 1 : 0) +
|
||||
(filter.endDate ? 1 : 0);
|
||||
if (DEBUG) debug("Constraints found: " + constraintCount);
|
||||
|
||||
let direction = reverse ? PREV : NEXT;
|
||||
|
||||
if (constraintCount == 1) {
|
||||
// 1.
|
||||
let indexName;
|
||||
let keyRange;
|
||||
if (filter.delivery) {
|
||||
indexName = "delivery";
|
||||
keyRange = IDBKeyRange.only(filter.delivery);
|
||||
} else if (filter.numbers) {
|
||||
indexName = "senderOrReceiver";
|
||||
keyRange = IDBKeyRange.only(filter.numbers[0]);
|
||||
} else if (filter.read) {
|
||||
indexName = "read";
|
||||
let keyRange = IDBKeyRange.only(filter.read ? FILTER_READ_READ
|
||||
: FILTER_READ_UNREAD);
|
||||
} else {
|
||||
indexName = "timestamp";
|
||||
if (filter.startDate != null && filter.endDate != null) {
|
||||
keyRange = IDBKeyRange.bound(filter.startDate.getTime(),
|
||||
filter.endDate.getTime());
|
||||
} else if (filter.startDate != null) {
|
||||
keyRange = IDBKeyRange.lowerBound(filter.startDate.getTime());
|
||||
} else if (filter.endDate != null) {
|
||||
keyRange = IDBKeyRange.upperBound(filter.endDate.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
if (indexName && keyRange) {
|
||||
this.startCursorRequest(indexName, keyRange, direction, aRequest);
|
||||
return;
|
||||
}
|
||||
} else if (constraintCount == 0) {
|
||||
// 2.
|
||||
this.startCursorRequest("timestamp", null, direction, aRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
// This object keeps the lists of keys retrieved by the search specific to
|
||||
// each nsIMozSmsFilter. Once all the keys have been retrieved from the
|
||||
// store, the final intersection of this arrays will contain all the
|
||||
// keys for the message list that we are creating.
|
||||
let filteredKeys = {};
|
||||
filteredKeys[FILTER_TIMESTAMP] = [];
|
||||
filteredKeys[FILTER_TIMESTAMP] = null;
|
||||
filteredKeys[FILTER_NUMBERS] = [];
|
||||
filteredKeys[FILTER_DELIVERY] = [];
|
||||
filteredKeys[FILTER_READ] = [];
|
||||
@ -828,29 +961,12 @@ SmsDatabaseService.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// In first place, we retrieve the keys that match the filter.startDate
|
||||
// and filter.endDate search criteria.
|
||||
let timeKeyRange = null;
|
||||
if (filter.startDate != null && filter.endDate != null) {
|
||||
timeKeyRange = IDBKeyRange.bound(filter.startDate.getTime(),
|
||||
filter.endDate.getTime());
|
||||
} else if (filter.startDate != null) {
|
||||
timeKeyRange = IDBKeyRange.lowerBound(filter.startDate.getTime());
|
||||
} else if (filter.endDate != null) {
|
||||
timeKeyRange = IDBKeyRange.upperBound(filter.endDate.getTime());
|
||||
}
|
||||
let direction = reverse ? PREV : NEXT;
|
||||
let timeRequest = store.index("timestamp").openKeyCursor(timeKeyRange,
|
||||
direction);
|
||||
|
||||
timeRequest.onsuccess = function onsuccess(event) {
|
||||
successCb(event.target.result, FILTER_TIMESTAMP);
|
||||
};
|
||||
timeRequest.onerror = errorCb;
|
||||
let filtered = false;
|
||||
|
||||
// Retrieve the keys from the 'delivery' index that matches the
|
||||
// value of filter.delivery.
|
||||
if (filter.delivery) {
|
||||
filtered = true;
|
||||
let deliveryKeyRange = IDBKeyRange.only(filter.delivery);
|
||||
let deliveryRequest = store.index("delivery")
|
||||
.openKeyCursor(deliveryKeyRange);
|
||||
@ -860,26 +976,26 @@ SmsDatabaseService.prototype = {
|
||||
deliveryRequest.onerror = errorCb;
|
||||
}
|
||||
|
||||
// Retrieve the keys from the 'sender' and 'receiver' indexes that
|
||||
// Retrieve the keys from the 'senderOrReceiver' indexes that
|
||||
// match the values of filter.numbers
|
||||
if (filter.numbers) {
|
||||
for (let i = 0; i < filter.numbers.length; i++) {
|
||||
filtered = true;
|
||||
let numberKeyRange = IDBKeyRange.only(filter.numbers[i]);
|
||||
let senderRequest = store.index("sender")
|
||||
.openKeyCursor(numberKeyRange);
|
||||
let receiverRequest = store.index("receiver")
|
||||
.openKeyCursor(numberKeyRange);
|
||||
senderRequest.onsuccess = receiverRequest.onsuccess =
|
||||
let numberRequest = store.index("senderOrReceiver")
|
||||
.openKeyCursor(numberKeyRange, direction);
|
||||
numberRequest.onsuccess =
|
||||
function onsuccess(event){
|
||||
successCb(event.target.result, FILTER_NUMBERS);
|
||||
};
|
||||
senderRequest.onerror = receiverRequest.onerror = errorCb;
|
||||
numberRequest.onerror = errorCb;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the keys from the 'read' index that matches the value of
|
||||
// filter.read
|
||||
if (filter.read != undefined) {
|
||||
filtered = true;
|
||||
let read = filter.read ? FILTER_READ_READ : FILTER_READ_UNREAD;
|
||||
if (DEBUG) debug("filter.read " + read);
|
||||
let readKeyRange = IDBKeyRange.only(read);
|
||||
@ -891,6 +1007,34 @@ SmsDatabaseService.prototype = {
|
||||
readRequest.onerror = errorCb;
|
||||
}
|
||||
|
||||
// In last place, we retrieve the keys that match the filter.startDate
|
||||
// and filter.endDate search criteria.
|
||||
// If we already filtered and have no date filtering, bail out.
|
||||
let timeKeyRange = null;
|
||||
if (filter.startDate != null && filter.endDate != null) {
|
||||
timeKeyRange = IDBKeyRange.bound(filter.startDate.getTime(),
|
||||
filter.endDate.getTime());
|
||||
} else if (filter.startDate != null) {
|
||||
timeKeyRange = IDBKeyRange.lowerBound(filter.startDate.getTime());
|
||||
} else if (filter.endDate != null) {
|
||||
timeKeyRange = IDBKeyRange.upperBound(filter.endDate.getTime());
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
debug("timeKeyRange: " + timeKeyRange + " filtered: " + filtered);
|
||||
if (timeKeyRange || !filtered) {
|
||||
filteredKeys[FILTER_TIMESTAMP] = [];
|
||||
let timeRequest = store.index("timestamp").openKeyCursor(timeKeyRange,
|
||||
direction);
|
||||
|
||||
timeRequest.onsuccess = function onsuccess(event) {
|
||||
successCb(event.target.result, FILTER_TIMESTAMP);
|
||||
};
|
||||
timeRequest.onerror = errorCb;
|
||||
} else {
|
||||
if (DEBUG) debug("Ignoring useless date filtering");
|
||||
}
|
||||
|
||||
txn.oncomplete = function oncomplete(event) {
|
||||
if (DEBUG) debug("Transaction " + txn + " completed.");
|
||||
// We need to get the intersection of all the partial searches to
|
||||
@ -916,10 +1060,55 @@ SmsDatabaseService.prototype = {
|
||||
},
|
||||
|
||||
getNextMessageInList: function getNextMessageInList(listId, aRequest) {
|
||||
let getMessage = (function getMessage(messageId) {
|
||||
this._getMessageInternal(messageId,
|
||||
function(aMessage) {
|
||||
aRequest.notifyNextMessageInListGot(aMessage);
|
||||
},
|
||||
function(aError) {
|
||||
aRequest.notifyReadMessageListFailed(aError);
|
||||
}
|
||||
);
|
||||
}).bind(this);
|
||||
|
||||
if (DEBUG) debug("Getting next message in list " + listId);
|
||||
let messageId;
|
||||
let list = this.messageLists[listId];
|
||||
if (!list) {
|
||||
if (this.cursorReqs[listId]) {
|
||||
let cursor = this.cursorReqs[listId];
|
||||
if (cursor.done && cursor.ids.length == 0) {
|
||||
aRequest.notifyNoMessageInList();
|
||||
return;
|
||||
}
|
||||
|
||||
messageId = cursor.ids.shift();
|
||||
|
||||
// There is a message in the queue, retrieve it and provide it to
|
||||
// the caller.
|
||||
if (messageId) {
|
||||
getMessage(messageId);
|
||||
return;
|
||||
}
|
||||
|
||||
// We're not done, but have no message yet. Wait for the cursor
|
||||
// to provide something.
|
||||
cursor.cursor.addEventListener("success",
|
||||
function waitForResult(aEvent) {
|
||||
cursor.cursor.removeEventListener("success", waitForResult);
|
||||
// No more messages.
|
||||
if (cursor.done) {
|
||||
aRequest.notifyNoMessageInList();
|
||||
return;
|
||||
}
|
||||
|
||||
// We have a new message, grab it from the queue.
|
||||
messageId = cursor.ids.shift();
|
||||
getMessage(messageId);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
if (DEBUG) debug("Wrong list id");
|
||||
aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.NOT_FOUND_ERROR);
|
||||
return;
|
||||
@ -930,46 +1119,17 @@ SmsDatabaseService.prototype = {
|
||||
aRequest.notifyNoMessageInList();
|
||||
return;
|
||||
}
|
||||
this.newTxn(READ_ONLY, function (error, txn, store) {
|
||||
if (DEBUG) debug("Fetching message " + messageId);
|
||||
let request = store.get(messageId);
|
||||
let message;
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
message = request.result;
|
||||
};
|
||||
|
||||
txn.oncomplete = function oncomplete(event) {
|
||||
if (DEBUG) debug("Transaction " + txn + " completed.");
|
||||
if (!message) {
|
||||
if (DEBUG) debug("Could not get message id " + messageId);
|
||||
aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.NOT_FOUND_ERROR);
|
||||
}
|
||||
let sms = gSmsService.createSmsMessage(message.id,
|
||||
message.delivery,
|
||||
message.deliveryStatus,
|
||||
message.sender,
|
||||
message.receiver,
|
||||
message.body,
|
||||
message.messageClass,
|
||||
message.timestamp,
|
||||
message.read);
|
||||
aRequest.notifyNextMessageInListGot(sms);
|
||||
};
|
||||
|
||||
txn.onerror = function onerror(event) {
|
||||
//TODO check event.target.errorCode
|
||||
if (DEBUG) {
|
||||
debug("Error retrieving message id: " + messageId +
|
||||
". Error code: " + event.target.errorCode);
|
||||
}
|
||||
aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
|
||||
};
|
||||
});
|
||||
getMessage(messageId);
|
||||
},
|
||||
|
||||
clearMessageList: function clearMessageList(listId) {
|
||||
if (DEBUG) debug("Clearing message list: " + listId);
|
||||
delete this.messageLists[listId];
|
||||
if (this.messageLists[listId]) {
|
||||
delete this.messageLists[listId];
|
||||
} else if (this.cursorReqs[listId]) {
|
||||
delete this.cursorReqs[listId];
|
||||
}
|
||||
},
|
||||
|
||||
markMessageRead: function markMessageRead(messageId, value, aRequest) {
|
||||
@ -1035,6 +1195,7 @@ SmsDatabaseService.prototype = {
|
||||
};
|
||||
}, [STORE_NAME, MOST_RECENT_STORE_NAME]);
|
||||
},
|
||||
|
||||
getThreadList: function getThreadList(aRequest) {
|
||||
if (DEBUG) debug("Getting thread list");
|
||||
this.newTxn(READ_ONLY, function (error, txn, store) {
|
||||
|
Loading…
Reference in New Issue
Block a user