Improved large getDiff perfomance
Now grouping most UI updates Closes #705
This commit is contained in:
parent
b4fdb48f87
commit
3f13351b1c
@ -631,24 +631,37 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$on('dialogs_update', function (e, dialog) {
|
||||
$scope.$on('dialogs_multiupdate', function (e, dialogsUpdated) {
|
||||
if ($scope.search.query !== undefined && $scope.search.query.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var pos = false;
|
||||
angular.forEach($scope.dialogs, function(curDialog, curPos) {
|
||||
if (curDialog.peerID == dialog.peerID) {
|
||||
pos = curPos;
|
||||
}
|
||||
var topMessages = [];
|
||||
var topToDialogs = {};
|
||||
angular.forEach(dialogsUpdated, function (dialog, peerID) {
|
||||
topToDialogs[dialog.top_message] = dialog;
|
||||
topMessages.push(dialog.top_message);
|
||||
});
|
||||
topMessages.sort();
|
||||
|
||||
var wrappedDialog = AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count);
|
||||
if (pos !== false) {
|
||||
var prev = $scope.dialogs.splice(pos, 1);
|
||||
safeReplaceObject(prev, wrappedDialog);
|
||||
var i, dialog;
|
||||
var len = $scope.dialogs.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
dialog = $scope.dialogs[i];
|
||||
if (dialogsUpdated[dialog.peerID]) {
|
||||
$scope.dialogs.splice(i, 1);
|
||||
i--;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
$scope.dialogs.unshift(wrappedDialog);
|
||||
len = topMessages.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
dialog = topToDialogs[topMessages[i]];
|
||||
$scope.dialogs.unshift(
|
||||
AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count)
|
||||
);
|
||||
}
|
||||
|
||||
delete $scope.isEmpty.dialogs;
|
||||
|
||||
if (!peersInDialogs[dialog.peerID]) {
|
||||
@ -1055,6 +1068,17 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
return false;
|
||||
}
|
||||
|
||||
function historiesQueuePop (peerID) {
|
||||
var i;
|
||||
for (i = 0; i < $scope.peerHistories.length; i++) {
|
||||
if ($scope.peerHistories[i].peerID == peerID) {
|
||||
$scope.peerHistories.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateHistoryPeer(preload) {
|
||||
var peerData = AppPeersManager.getPeer(peerID);
|
||||
// console.log('update', preload, peerData);
|
||||
@ -1460,15 +1484,29 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
$scope.$on('history_update', angular.noop);
|
||||
|
||||
var loadAfterSync = false;
|
||||
$scope.$on('stateSynchronized', function () {
|
||||
if (!loadAfterSync) {
|
||||
return;
|
||||
}
|
||||
if (loadAfterSync == $scope.curDialog.peerID) {
|
||||
loadHistory();
|
||||
}
|
||||
loadAfterSync = false;
|
||||
});
|
||||
|
||||
|
||||
var typingTimeouts = {};
|
||||
$scope.$on('history_append', function (e, addedMessage) {
|
||||
var history = historiesQueueFind(addedMessage.peerID);
|
||||
// var history = historiesQueuePush(addedMessage.peerID);
|
||||
if (!history) {
|
||||
return;
|
||||
}
|
||||
var curPeer = addedMessage.peerID == $scope.curDialog.peerID;
|
||||
if (curPeer) {
|
||||
if ($scope.historyFilter.mediaType || $scope.historyState.skipped) {
|
||||
if ($scope.historyFilter.mediaType ||
|
||||
$scope.historyState.skipped) {
|
||||
if (addedMessage.my) {
|
||||
returnToRecent();
|
||||
} else {
|
||||
@ -1518,6 +1556,101 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('history_multiappend', function (e, historyMultiAdded) {
|
||||
// console.log(dT(), 'multiappend', historyMultiAdded);
|
||||
var regroupped = false;
|
||||
var unreadAfterChanged = false;
|
||||
var isIDLE = $rootScope.idle.isIDLE;
|
||||
angular.forEach(historyMultiAdded, function (msgs, peerID) {
|
||||
var history = historiesQueueFind(peerID);
|
||||
// var history = historiesQueuePush(peerID);
|
||||
if (!history) {
|
||||
return;
|
||||
}
|
||||
var curPeer = peerID == $scope.curDialog.peerID;
|
||||
var len = msgs.length;
|
||||
|
||||
if (curPeer) {
|
||||
if ($scope.historyFilter.mediaType ||
|
||||
$scope.historyState.skipped) {
|
||||
$scope.historyState.missedCount += len;
|
||||
return;
|
||||
}
|
||||
delete $scope.state.empty;
|
||||
}
|
||||
if (len > 10) {
|
||||
if (curPeer) {
|
||||
var exlen = history.messages.length;
|
||||
if (exlen > 10) {
|
||||
minID = history.messages[exlen - 1].id;
|
||||
$scope.historyState.skipped = hasLess = minID > 0;
|
||||
if (hasLess) {
|
||||
loadAfterSync = peerID;
|
||||
$scope.$broadcast('ui_history_append');
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
historiesQueuePop(peerID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
var messageID, historyMessage, i;
|
||||
var hasOut = false;
|
||||
var unreadAfterNew = false;
|
||||
var lastIsRead = !(history.messages[history.messages.length - 1] || {}).unread;
|
||||
for (i = 0; i < len; i++) {
|
||||
messageID = msgs[i];
|
||||
historyMessage = AppMessagesManager.wrapForHistory(messageID);
|
||||
history.messages.push(historyMessage);
|
||||
if (!unreadAfterNew && isIDLE) {
|
||||
if (historyMessage.unread &&
|
||||
!historyMessage.out &&
|
||||
lastIsRead) {
|
||||
unreadAfterNew = messageID;
|
||||
} else {
|
||||
lastIsRead = !historyMessage.unread;
|
||||
}
|
||||
}
|
||||
if (!hasOut && historyMessage.out) {
|
||||
hasOut = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (AppMessagesManager.regroupWrappedHistory(history.messages, -len - 2)) {
|
||||
regroupped = true;
|
||||
}
|
||||
|
||||
if (curPeer) {
|
||||
if ($scope.historyState.typing.length) {
|
||||
$scope.historyState.typing.splice(0, $scope.historyState.typing.length);
|
||||
}
|
||||
$scope.$broadcast('ui_history_append_new', {
|
||||
idleScroll: unreadAfterIdle && !hasOut && unreadAfterNew
|
||||
});
|
||||
|
||||
if (isIDLE) {
|
||||
if (unreadAfterNew) {
|
||||
$scope.historyUnreadAfter = unreadAfterNew;
|
||||
unreadAfterIdle = true;
|
||||
unreadAfterChanged = true;
|
||||
}
|
||||
} else {
|
||||
$timeout(function () {
|
||||
AppMessagesManager.readHistory($scope.curDialog.inputPeer);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (regroupped) {
|
||||
$scope.$broadcast('messages_regroup');
|
||||
}
|
||||
if (unreadAfterChanged) {
|
||||
$scope.$broadcast('messages_unread_after');
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('history_delete', function (e, historyUpdate) {
|
||||
var history = historiesQueueFind(historyUpdate.peerID);
|
||||
if (!history) {
|
||||
|
@ -226,20 +226,22 @@ TLSerialization.prototype.storeMethod = function (methodName, params) {
|
||||
|
||||
this.storeInt(intToUint(methodData.id), methodName + '[id]');
|
||||
|
||||
var self = this;
|
||||
angular.forEach(methodData.params, function (param) {
|
||||
var type = param.type;
|
||||
var param, type, i, condType, fieldBit;
|
||||
var len = methodData.params.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
param = methodData.params[i];
|
||||
type = param.type;
|
||||
if (type.indexOf('?') !== -1) {
|
||||
var condType = type.split('?');
|
||||
var fieldBit = condType[0].split('.');
|
||||
condType = type.split('?');
|
||||
fieldBit = condType[0].split('.');
|
||||
if (!(params[fieldBit[0]] & (1 << fieldBit[1]))) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
type = condType[1];
|
||||
}
|
||||
|
||||
self.storeObject(params[param.name], type, methodName + '[' + param.name + ']');
|
||||
});
|
||||
this.storeObject(params[param.name], type, methodName + '[' + param.name + ']');
|
||||
}
|
||||
|
||||
return methodData.type;
|
||||
};
|
||||
@ -308,20 +310,22 @@ TLSerialization.prototype.storeObject = function (obj, type, field) {
|
||||
this.writeInt(intToUint(constructorData.id), field + '[' + predicate + '][id]');
|
||||
}
|
||||
|
||||
var self = this;
|
||||
angular.forEach(constructorData.params, function (param) {
|
||||
var type = param.type;
|
||||
var param, type, i, condType, fieldBit;
|
||||
var len = constructorData.params.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
param = constructorData.params[i];
|
||||
type = param.type;
|
||||
if (type.indexOf('?') !== -1) {
|
||||
var condType = type.split('?');
|
||||
var fieldBit = condType[0].split('.');
|
||||
condType = type.split('?');
|
||||
fieldBit = condType[0].split('.');
|
||||
if (!(obj[fieldBit[0]] & (1 << fieldBit[1]))) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
type = condType[1];
|
||||
}
|
||||
|
||||
self.storeObject(obj[param.name], type, field + '[' + predicate + '][' + param.name + ']');
|
||||
});
|
||||
this.storeObject(obj[param.name], type, field + '[' + predicate + '][' + param.name + ']');
|
||||
}
|
||||
|
||||
return constructorData.type;
|
||||
};
|
||||
@ -532,7 +536,7 @@ TLDeserialization.prototype.fetchObject = function (type, field) {
|
||||
|
||||
if (type.charAt(0) == '%') {
|
||||
var checkType = type.substr(1);
|
||||
for (i = 0; i < schema.constructors.length; i++) {
|
||||
for (var i = 0; i < schema.constructors.length; i++) {
|
||||
if (schema.constructors[i].type == checkType) {
|
||||
constructorData = schema.constructors[i];
|
||||
break
|
||||
@ -543,7 +547,7 @@ TLDeserialization.prototype.fetchObject = function (type, field) {
|
||||
}
|
||||
}
|
||||
else if (type.charAt(0) >= 97 && type.charAt(0) <= 122) {
|
||||
for (i = 0; i < schema.constructors.length; i++) {
|
||||
for (var i = 0; i < schema.constructors.length; i++) {
|
||||
if (schema.constructors[i].predicate == type) {
|
||||
constructorData = schema.constructors[i];
|
||||
break
|
||||
@ -566,12 +570,17 @@ TLDeserialization.prototype.fetchObject = function (type, field) {
|
||||
return newDeserializer.fetchObject(type, field);
|
||||
}
|
||||
|
||||
for (i = 0; i < schema.constructors.length; i++) {
|
||||
if (schema.constructors[i].id == constructorCmp) {
|
||||
constructorData = schema.constructors[i];
|
||||
break;
|
||||
var index = schema.constructorsIndex;
|
||||
if (!index) {
|
||||
schema.constructorsIndex = index = {};
|
||||
for (var i = 0; i < schema.constructors.length; i++) {
|
||||
index[schema.constructors[i].id] = i;
|
||||
}
|
||||
}
|
||||
var i = index[constructorCmp];
|
||||
if (i) {
|
||||
constructorData = schema.constructors[i];
|
||||
}
|
||||
|
||||
var fallback = false;
|
||||
if (!constructorData && this.mtproto) {
|
||||
@ -601,19 +610,22 @@ TLDeserialization.prototype.fetchObject = function (type, field) {
|
||||
if (this.override[overrideKey]) {
|
||||
this.override[overrideKey].apply(this, [result, field + '[' + predicate + ']']);
|
||||
} else {
|
||||
angular.forEach(constructorData.params, function (param) {
|
||||
var type = param.type;
|
||||
var i, param, type, condType, fieldBit;
|
||||
var len = constructorData.params.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
param = constructorData.params[i];
|
||||
type = param.type;
|
||||
if (type.indexOf('?') !== -1) {
|
||||
var condType = type.split('?');
|
||||
var fieldBit = condType[0].split('.');
|
||||
condType = type.split('?');
|
||||
fieldBit = condType[0].split('.');
|
||||
if (!(result[fieldBit[0]] & (1 << fieldBit[1]))) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
type = condType[1];
|
||||
}
|
||||
|
||||
result[param.name] = self.fetchObject(type, field + '[' + predicate + '][' + param.name + ']');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (fallback) {
|
||||
|
@ -792,7 +792,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
}
|
||||
})
|
||||
|
||||
.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, AppWebPagesManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, PeersSelectService, Storage, FileManager, TelegramMeWebService, StatusManager, _) {
|
||||
.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, $timeout, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, AppWebPagesManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, PeersSelectService, Storage, FileManager, TelegramMeWebService, StatusManager, _) {
|
||||
|
||||
var messagesStorage = {};
|
||||
var messagesForHistory = {};
|
||||
@ -895,6 +895,12 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
|
||||
AppUsersManager.saveApiUsers(dialogsResult.users);
|
||||
AppChatsManager.saveApiChats(dialogsResult.chats);
|
||||
|
||||
// return {
|
||||
// count: 0,
|
||||
// dialogs: []
|
||||
// };
|
||||
|
||||
saveMessages(dialogsResult.messages);
|
||||
|
||||
if (maxID > 0) {
|
||||
@ -2270,6 +2276,25 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
});
|
||||
}
|
||||
|
||||
var newMessagesHandlePromise = false;
|
||||
var newMessagesToHandle = {};
|
||||
var newDialogsHandlePromise = false;
|
||||
var newDialogsToHandle = {};
|
||||
|
||||
function handleNewMessages () {
|
||||
$timeout.cancel(newMessagesHandlePromise);
|
||||
newMessagesHandlePromise = false;
|
||||
$rootScope.$broadcast('history_multiappend', newMessagesToHandle);
|
||||
newMessagesToHandle = {};
|
||||
}
|
||||
|
||||
function handleNewDialogs () {
|
||||
$timeout.cancel(newDialogsHandlePromise);
|
||||
newDialogsHandlePromise = false;
|
||||
$rootScope.$broadcast('dialogs_multiupdate', newDialogsToHandle);
|
||||
newDialogsToHandle = {};
|
||||
}
|
||||
|
||||
$rootScope.$on('apiUpdate', function (e, update) {
|
||||
// if (update._ != 'updateUserStatus') {
|
||||
// console.log('on apiUpdate', update);
|
||||
@ -2320,34 +2345,45 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
}
|
||||
|
||||
if (!pendingMessage) {
|
||||
$rootScope.$broadcast('history_append', {peerID: peerID, messageID: message.id});
|
||||
if (newMessagesToHandle[peerID] === undefined) {
|
||||
newMessagesToHandle[peerID] = [];
|
||||
}
|
||||
newMessagesToHandle[peerID].push(message.id);
|
||||
if (!newMessagesHandlePromise) {
|
||||
newMessagesHandlePromise = $timeout(handleNewMessages, 0);
|
||||
}
|
||||
}
|
||||
|
||||
var foundDialog = getDialogByPeerID(peerID),
|
||||
dialog;
|
||||
var foundDialog = getDialogByPeerID(peerID);
|
||||
var dialog;
|
||||
var inboxUnread = !message.out && message.unread;
|
||||
|
||||
if (foundDialog.length) {
|
||||
dialog = foundDialog[0];
|
||||
dialogsStorage.dialogs.splice(foundDialog[1], 1);
|
||||
if (foundDialog[1] > 0) {
|
||||
dialogsStorage.dialogs.splice(foundDialog[1], 1);
|
||||
dialogsStorage.dialogs.unshift(dialog);
|
||||
}
|
||||
dialog.top_message = message.id;
|
||||
if (inboxUnread) {
|
||||
dialog.unread_count++;
|
||||
}
|
||||
} else {
|
||||
dialog = {peerID: peerID, unread_count: 0, top_message: false}
|
||||
SearchIndexManager.indexObject(peerID, AppPeersManager.getPeerSearchText(peerID), dialogsIndex);
|
||||
|
||||
dialog = {
|
||||
peerID: peerID,
|
||||
unread_count: inboxUnread ? 1 : 0,
|
||||
top_message: message.id
|
||||
};
|
||||
dialogsStorage.dialogs.unshift(dialog);
|
||||
}
|
||||
if (!message.out && message.unread) {
|
||||
// console.log('inc unread count', dialog.unread_count);
|
||||
dialog.unread_count++;
|
||||
newDialogsToHandle[peerID] = dialog;
|
||||
if (!newDialogsHandlePromise) {
|
||||
newDialogsHandlePromise = $timeout(handleNewDialogs, 0);
|
||||
}
|
||||
dialog.top_message = message.id;
|
||||
|
||||
// console.log('new message', message, peerID, historyStorage, foundDialog, dialog);
|
||||
|
||||
SearchIndexManager.indexObject(peerID, AppPeersManager.getPeerSearchText(peerID), dialogsIndex);
|
||||
|
||||
dialogsStorage.dialogs.unshift(dialog);
|
||||
$rootScope.$broadcast('dialogs_update', dialog);
|
||||
|
||||
if (($rootScope.selectedPeerID != peerID || $rootScope.idle.isIDLE) &&
|
||||
!message.out &&
|
||||
message.unread) {
|
||||
if (inboxUnread && ($rootScope.selectedPeerID != peerID || $rootScope.idle.isIDLE)) {
|
||||
|
||||
var notifyPeer = message.flags & 16 ? message.from_id : peerID;
|
||||
var isMutedPromise = NotificationsManager.getPeerMuted(notifyPeer);
|
||||
@ -3716,12 +3752,13 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
syncPending = false;
|
||||
}
|
||||
|
||||
MtpApiManager.invokeApi('updates.getDifference', {pts: curState.pts, date: curState.date, qts: 0}).then(function (differenceResult) {
|
||||
MtpApiManager.invokeApi('updates.getDifference', {pts: curState.pts, date: curState.date, qts: -1}).then(function (differenceResult) {
|
||||
if (differenceResult._ == 'updates.differenceEmpty') {
|
||||
console.log(dT(), 'apply empty diff', differenceResult.seq);
|
||||
curState.date = differenceResult.date;
|
||||
curState.seq = differenceResult.seq;
|
||||
syncLoading = false;
|
||||
$rootScope.$broadcast('stateSynchronized');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3729,10 +3766,12 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
AppChatsManager.saveApiChats(differenceResult.chats);
|
||||
|
||||
// Should be first because of updateMessageID
|
||||
// console.log(dT(), 'applying', differenceResult.other_updates.length, 'other updates');
|
||||
angular.forEach(differenceResult.other_updates, function(update){
|
||||
saveUpdate(update);
|
||||
});
|
||||
|
||||
// console.log(dT(), 'applying', differenceResult.new_messages.length, 'new messages');
|
||||
angular.forEach(differenceResult.new_messages, function (apiMessage) {
|
||||
saveUpdate({
|
||||
_: 'updateNewMessage',
|
||||
@ -3752,6 +3791,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
if (differenceResult._ == 'updates.differenceSlice') {
|
||||
getDifference();
|
||||
} else {
|
||||
// console.log(dT(), 'finished get diff');
|
||||
$rootScope.$broadcast('stateSynchronized');
|
||||
syncLoading = false;
|
||||
}
|
||||
});
|
||||
@ -3855,6 +3896,11 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
setTimeout(function () {
|
||||
syncLoading = false;
|
||||
}, 1000);
|
||||
|
||||
// curState.seq = 1;
|
||||
// curState.pts = stateResult.pts - 5000;
|
||||
// curState.date = 1;
|
||||
// getDifference();
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user