diff options
Diffstat (limited to 'webclient/components')
-rw-r--r-- | webclient/components/matrix/event-handler-service.js | 98 | ||||
-rw-r--r-- | webclient/components/matrix/event-stream-service.js | 13 |
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); }, |