diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js
index 94ac91db5e..277faa6f77 100644
--- a/webclient/components/matrix/event-handler-service.js
+++ b/webclient/components/matrix/event-handler-service.js
@@ -55,6 +55,11 @@ angular.module('eventHandlerService', [])
$rootScope.events.rooms[room_id] = {};
$rootScope.events.rooms[room_id].messages = [];
$rootScope.events.rooms[room_id].members = {};
+
+ // Pagination information
+ $rootScope.events.rooms[room_id].pagination = {
+ earliest_token: "END" // how far back we've paginated
+ }
}
};
@@ -81,8 +86,15 @@ angular.module('eventHandlerService', [])
if (isLiveEvent) {
if (event.user_id === matrixService.config().user_id &&
(event.content.msgtype === "m.text" || event.content.msgtype === "m.emote") ) {
- // assume we've already echoed it
- // FIXME: track events by ID and ungrey the right message to show it's been delivered
+ // Assume we've already echoed it. So, there is a fake event in the messages list of the room
+ // Replace this fake event by the true one
+ var index = getRoomEventIndex(event.room_id, event.event_id);
+ if (index) {
+ $rootScope.events.rooms[event.room_id].messages[index] = event;
+ }
+ else {
+ $rootScope.events.rooms[event.room_id].messages.push(event);
+ }
}
else {
$rootScope.events.rooms[event.room_id].messages.push(event);
@@ -100,7 +112,7 @@ angular.module('eventHandlerService', [])
$rootScope.$broadcast(MSG_EVENT, event, isLiveEvent);
};
- var handleRoomMember = function(event, isLiveEvent) {
+ var handleRoomMember = function(event, isLiveEvent, isStateEvent) {
initRoom(event.room_id);
// if the server is stupidly re-relaying a no-op join, discard it.
@@ -112,7 +124,10 @@ angular.module('eventHandlerService', [])
}
// add membership changes as if they were a room message if something interesting changed
- if (event.content.prev !== event.content.membership) {
+ // Exception: Do not do this if the event is a room state event because such events already come
+ // as room messages events. Moreover, when they come as room messages events, they are relatively ordered
+ // with other other room messages
+ if (event.content.prev !== event.content.membership && !isStateEvent) {
if (isLiveEvent) {
$rootScope.events.rooms[event.room_id].messages.push(event);
}
@@ -121,8 +136,13 @@ angular.module('eventHandlerService', [])
}
}
- $rootScope.events.rooms[event.room_id].members[event.state_key] = event;
- $rootScope.$broadcast(MEMBER_EVENT, event, isLiveEvent);
+ // Use data from state event or the latest data from the stream.
+ // Do not care of events that come when paginating back
+ if (isStateEvent || isLiveEvent) {
+ $rootScope.events.rooms[event.room_id].members[event.state_key] = event;
+ }
+
+ $rootScope.$broadcast(MEMBER_EVENT, event, isLiveEvent, isStateEvent);
};
var handlePresence = function(event, isLiveEvent) {
@@ -177,6 +197,29 @@ angular.module('eventHandlerService', [])
}
};
+ /**
+ * Get the index of the event in $rootScope.events.rooms[room_id].messages
+ * @param {type} room_id the room id
+ * @param {type} event_id the event id to look for
+ * @returns {Number | undefined} the index. undefined if not found.
+ */
+ var getRoomEventIndex = function(room_id, event_id) {
+ var index;
+
+ var room = $rootScope.events.rooms[room_id];
+ if (room) {
+ for (var i = 0; i < room.messages.length; i++) {
+ var message = room.messages[i];
+ console.log(message.event_id);
+ if (event_id === message.event_id) {
+ index = i;
+ break;
+ }
+ }
+ }
+ return index;
+ }
+
return {
ROOM_CREATE_EVENT: ROOM_CREATE_EVENT,
MSG_EVENT: MSG_EVENT,
@@ -186,18 +229,24 @@ angular.module('eventHandlerService', [])
CALL_EVENT: CALL_EVENT,
NAME_EVENT: NAME_EVENT,
- handleEvent: function(event, isLiveEvent) {
- // FIXME: event duplication suppression is all broken as the code currently expect to handles
- // events multiple times to get their side-effects...
-/*
- if (eventMap[event.event_id]) {
- console.log("discarding duplicate event: " + JSON.stringify(event));
- return;
- }
- else {
- eventMap[event.event_id] = 1;
+ handleEvent: function(event, isLiveEvent, isStateEvent) {
+ // Avoid duplicated events
+ // Needed for rooms where initialSync has not been done.
+ // In this case, we do not know where to start pagination. So, it starts from the END
+ // and we can have the same event (ex: joined, invitation) coming from the pagination
+ // AND from the event stream.
+ // FIXME: This workaround should be no more required when /initialSync on a particular room
+ // will be available (as opposite to the global /initialSync done at startup)
+ if (!isStateEvent) { // Do not consider state events
+ if (event.event_id && eventMap[event.event_id]) {
+ console.log("discarding duplicate event: " + JSON.stringify(event, undefined, 4));
+ return;
+ }
+ else {
+ eventMap[event.event_id] = 1;
+ }
}
-*/
+
if (event.type.indexOf('m.call.') === 0) {
handleCallEvent(event, isLiveEvent);
}
@@ -213,7 +262,7 @@ angular.module('eventHandlerService', [])
handleMessage(event, isLiveEvent);
break;
case "m.room.member":
- handleRoomMember(event, isLiveEvent);
+ handleRoomMember(event, isLiveEvent, isStateEvent);
break;
case "m.presence":
handlePresence(event, isLiveEvent);
@@ -241,12 +290,21 @@ angular.module('eventHandlerService', [])
// isLiveEvents determines whether notifications should be shown, whether
// messages get appended to the start/end of lists, etc.
- handleEvents: function(events, isLiveEvents) {
+ handleEvents: function(events, isLiveEvents, isStateEvents) {
for (var i=0; i<events.length; i++) {
- this.handleEvent(events[i], isLiveEvents);
+ this.handleEvent(events[i], isLiveEvents, isStateEvents);
}
},
+ // Handle messages from /initialSync or /messages
+ handleRoomMessages: function(room_id, messages, isLiveEvents) {
+ this.handleEvents(messages.chunk, isLiveEvents);
+
+ // Store how far back we've paginated
+ // This assumes the paginations requests are contiguous and in reverse chronological order
+ $rootScope.events.rooms[room_id].pagination.earliest_token = messages.end;
+ },
+
handleInitialSyncDone: function(initialSyncData) {
console.log("# handleInitialSyncDone");
initialSyncDeferred.resolve(initialSyncData);
diff --git a/webclient/components/matrix/event-stream-service.js b/webclient/components/matrix/event-stream-service.js
index 1bc850a8fa..03b805213d 100644
--- a/webclient/components/matrix/event-stream-service.js
+++ b/webclient/components/matrix/event-stream-service.js
@@ -104,17 +104,19 @@ angular.module('eventStreamService', [])
settings.isActive = true;
var deferred = $q.defer();
- // FIXME: We are discarding all the messages.
- // XXX FIXME TODO : The discard works because we are doing this all over
- // again on EVERY INSTANTIATION of the recents controller.
+ // Initial sync: get all information and the last message of all rooms of the user
matrixService.initialSync(1, false).then(
function(response) {
var rooms = response.data.rooms;
for (var i = 0; i < rooms.length; ++i) {
var room = rooms[i];
- // console.log("got room: " + room.room_id);
+
+ if ("messages" in room) {
+ eventHandlerService.handleRoomMessages(room.room_id, room.messages, false);
+ }
+
if ("state" in room) {
- eventHandlerService.handleEvents(room.state, false);
+ eventHandlerService.handleEvents(room.state, false, true);
}
}
@@ -124,6 +126,7 @@ angular.module('eventStreamService', [])
// Initial sync is done
eventHandlerService.handleInitialSyncDone(response);
+ // Start event streaming from that point
settings.from = response.data.end;
doEventStream(deferred);
},
|