diff options
author | Kegan Dougal <kegan@matrix.org> | 2014-08-15 11:31:13 +0100 |
---|---|---|
committer | Kegan Dougal <kegan@matrix.org> | 2014-08-15 14:06:56 +0100 |
commit | 5dbceaf5a40a7e90a4aca1a1612fa9ea13290a02 (patch) | |
tree | afe6432266ad80f95b31390370df5278c931bf76 | |
parent | Added event stream service which neatly blobs together requests / state for t... (diff) | |
download | synapse-5dbceaf5a40a7e90a4aca1a1612fa9ea13290a02.tar.xz |
Added event handler service which.. handles events. More specifically, it $broadcasts events depending on their type, and does processing on events (shuffling keys, adding events to $rootScope so displays will automatically update, sending delivery receipts, and so on). Some of this logic was previously contained in the RoomController, which fails the moment you add >1 room into the mix, hence requiring a Service to handle events, rather than having each individual controller maintain their part of the world.
-rw-r--r-- | webclient/app.js | 3 | ||||
-rw-r--r-- | webclient/components/matrix/event-handler-service.js | 87 | ||||
-rw-r--r-- | webclient/components/matrix/event-stream-service.js | 17 | ||||
-rw-r--r-- | webclient/index.html | 1 | ||||
-rw-r--r-- | webclient/room/room-controller.js | 48 |
5 files changed, 124 insertions, 32 deletions
diff --git a/webclient/app.js b/webclient/app.js index 547431d9b2..bc78eb9d17 100644 --- a/webclient/app.js +++ b/webclient/app.js @@ -21,7 +21,8 @@ var matrixWebClient = angular.module('matrixWebClient', [ 'RoomController', 'RoomsController', 'matrixService', - 'eventStreamService' + 'eventStreamService', + 'eventHandlerService' ]); matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider', diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js new file mode 100644 index 0000000000..30d7ab35ca --- /dev/null +++ b/webclient/components/matrix/event-handler-service.js @@ -0,0 +1,87 @@ +/* +Copyright 2014 matrix.org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +/* +This service handles what should happen when you get an event. This service does +not care where the event came from, it only needs enough context to be able to +process them. Events may be coming from the event stream, the REST API (via +direct GETs or via a pagination stream API), etc. + +Typically, this service will store events or broadcast them to any listeners +(e.g. controllers) via $broadcast. Alternatively, it may update the $rootScope +if typically all the $on method would do is update its own $scope. +*/ +angular.module('eventHandlerService', []) +.factory('eventHandlerService', ['matrixService', '$rootScope', function(matrixService, $rootScope) { + var MSG_EVENT = "MSG_EVENT"; + var MEMBER_EVENT = "MEMBER_EVENT"; + var PRESENCE_EVENT = "PRESENCE_EVENT"; + + var handleMessage = function(event, isLiveEvent) { + if ("membership_target" in event.content) { + // event.user_id = event.content.membership_target; + } + + // $broadcast this, as controllers may want to do funky things such as + // scroll to the bottom, etc which cannot be expressed via simple $scope + // updates. + console.log("Bcast " + JSON.stringify(event)); + $rootScope.$broadcast(MSG_EVENT, event, isLiveEvent); + }; + + var handleRoomMember = function(event, isLiveEvent) { + $rootScope.$broadcast(MEMBER_EVENT, event, isLiveEvent); + }; + + var handlePresence = function(event, isLiveEvent) { + $rootScope.$broadcast(PRESENCE_EVENT, event, isLiveEvent); + }; + + + return { + MSG_EVENT: MSG_EVENT, + MEMBER_EVENT: MEMBER_EVENT, + PRESENCE_EVENT: PRESENCE_EVENT, + + + handleEvent: function(event, isLiveEvent) { + switch(event.type) { + case "m.room.message": + handleMessage(event, isLiveEvent); + break; + case "m.room.member": + handleRoomMember(event, isLiveEvent); + break; + case "m.presence": + handlePresence(event, isLiveEvent); + break; + default: + console.log("Unable to handle event type " + event.type); + break; + } + }, + + // isLiveEvents determines whether notifications should be shown, whether + // messages get appended to the start/end of lists, etc. + handleEvents: function(events, isLiveEvents) { + for (var i=0; i<events.length; i++) { + this.handleEvent(events[i], isLiveEvents); + } + } + }; +}]); diff --git a/webclient/components/matrix/event-stream-service.js b/webclient/components/matrix/event-stream-service.js index 0a3a12192b..1cb9960b9a 100644 --- a/webclient/components/matrix/event-stream-service.js +++ b/webclient/components/matrix/event-stream-service.js @@ -16,8 +16,17 @@ limitations under the License. 'use strict'; +/* +This service manages where in the event stream the web client currently is and +provides methods to resume/pause/stop the event stream. This service is not +responsible for parsing event data. For that, see the eventDataHandler. +*/ angular.module('eventStreamService', []) .factory('eventStreamService', ['matrixService', function(matrixService) { + var END = "END"; + var START = "START"; + var TIMEOUT_MS = 5000; + var settings = { from: "END", to: undefined, @@ -28,7 +37,7 @@ angular.module('eventStreamService', []) // interrupts the stream. Only valid if there is a stream conneciton // open. var interrupt = function(shouldPoll) { - console.log("[EventStream] interrupt("+shouldPoll+") "+ + console.log("p[EventStream] interrupt("+shouldPoll+") "+ JSON.stringify(settings)); }; @@ -42,7 +51,7 @@ angular.module('eventStreamService', []) resume: function() { console.log("[EventStream] resume "+JSON.stringify(settings)); // run the stream from the latest token - return matrixService.getEventStream(settings.from, 5000); + return matrixService.getEventStream(settings.from, TIMEOUT_MS); }, // pause the stream. Resuming it will continue from the current position @@ -55,13 +64,13 @@ angular.module('eventStreamService', []) }, // stop the stream and wipe the position in the stream. Typically used - // when logging out. + // when logging out / logged out. stop: function() { console.log("[EventStream] stop "+JSON.stringify(settings)); // kill any running stream interrupt(false); // clear the latest token - settings.from = "END"; + settings.from = END; saveStreamSettings(); } }; diff --git a/webclient/index.html b/webclient/index.html index 793b03d108..31b62efaa8 100644 --- a/webclient/index.html +++ b/webclient/index.html @@ -15,6 +15,7 @@ <script src="rooms/rooms-controller.js"></script> <script src="components/matrix/matrix-service.js"></script> <script src="components/matrix/event-stream-service.js"></script> + <script src="components/matrix/event-handler-service.js"></script> <script src="components/fileInput/file-input-directive.js"></script> <script src="components/fileUpload/file-upload-service.js"></script> </head> diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 3f69a12c23..301d3d6447 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -15,8 +15,8 @@ limitations under the License. */ angular.module('RoomController', []) -.controller('RoomController', ['$scope', '$http', '$timeout', '$routeParams', '$location', 'matrixService', 'eventStreamService', - function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService) { +.controller('RoomController', ['$scope', '$http', '$timeout', '$routeParams', '$location', 'matrixService', 'eventStreamService', 'eventHandlerService', + function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService, eventHandlerService) { 'use strict'; var MESSAGES_PER_PAGINATION = 10; $scope.room_id = $routeParams.room_id; @@ -42,34 +42,28 @@ angular.module('RoomController', []) },0); }; - var parseChunk = function(chunks, appendToStart) { - for (var i = 0; i < chunks.length; i++) { - var chunk = chunks[i]; - if (chunk.room_id == $scope.room_id && chunk.type == "m.room.message") { - if ("membership_target" in chunk.content) { - chunk.user_id = chunk.content.membership_target; - } - if (appendToStart) { - $scope.messages.unshift(chunk); - } - else { - $scope.messages.push(chunk); - scrollToBottom(); - } - } - else if (chunk.room_id == $scope.room_id && chunk.type == "m.room.member") { - updateMemberList(chunk); - } - else if (chunk.type === "m.presence") { - updatePresence(chunk); - } + $scope.$on(eventHandlerService.MSG_EVENT, function(ngEvent, event, isLive) { + if (isLive) { + $scope.messages.push(event); + scrollToBottom(); } - }; + else { + $scope.messages.unshift(event); + } + }); + + $scope.$on(eventHandlerService.MEMBER_EVENT, function(ngEvent, event, isLive) { + updateMemberList(event); + }); + + $scope.$on(eventHandlerService.PRESENCE_EVENT, function(ngEvent, event, isLive) { + updatePresence(event); + }); var paginate = function(numItems) { matrixService.paginateBackMessages($scope.room_id, $scope.state.earliest_token, numItems).then( function(response) { - parseChunk(response.data.chunk, true); + eventHandlerService.handleEvents(response.data.chunk, false); $scope.state.earliest_token = response.data.end; if (response.data.chunk.length < MESSAGES_PER_PAGINATION) { // no more messages to paginate :( @@ -89,8 +83,8 @@ angular.module('RoomController', []) console.log("Got response from "+$scope.state.events_from+" to "+response.data.end); $scope.state.events_from = response.data.end; $scope.feedback = ""; - - parseChunk(response.data.chunk, false); + + eventHandlerService.handleEvents(response.data.chunk, true); if ($scope.stopPoll) { console.log("Stopping polling."); |