summary refs log tree commit diff
path: root/webclient/components
diff options
context:
space:
mode:
Diffstat (limited to 'webclient/components')
-rw-r--r--webclient/components/matrix/event-handler-service.js98
-rw-r--r--webclient/components/matrix/event-stream-service.js13
2 files changed, 86 insertions, 25 deletions
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);        
             },