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.
parent
8bf3994c2e
commit
5dbceaf5a4
|
@ -21,7 +21,8 @@ var matrixWebClient = angular.module('matrixWebClient', [
|
||||||
'RoomController',
|
'RoomController',
|
||||||
'RoomsController',
|
'RoomsController',
|
||||||
'matrixService',
|
'matrixService',
|
||||||
'eventStreamService'
|
'eventStreamService',
|
||||||
|
'eventHandlerService'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',
|
matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -16,8 +16,17 @@ limitations under the License.
|
||||||
|
|
||||||
'use strict';
|
'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', [])
|
angular.module('eventStreamService', [])
|
||||||
.factory('eventStreamService', ['matrixService', function(matrixService) {
|
.factory('eventStreamService', ['matrixService', function(matrixService) {
|
||||||
|
var END = "END";
|
||||||
|
var START = "START";
|
||||||
|
var TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
var settings = {
|
var settings = {
|
||||||
from: "END",
|
from: "END",
|
||||||
to: undefined,
|
to: undefined,
|
||||||
|
@ -28,7 +37,7 @@ angular.module('eventStreamService', [])
|
||||||
// interrupts the stream. Only valid if there is a stream conneciton
|
// interrupts the stream. Only valid if there is a stream conneciton
|
||||||
// open.
|
// open.
|
||||||
var interrupt = function(shouldPoll) {
|
var interrupt = function(shouldPoll) {
|
||||||
console.log("[EventStream] interrupt("+shouldPoll+") "+
|
console.log("p[EventStream] interrupt("+shouldPoll+") "+
|
||||||
JSON.stringify(settings));
|
JSON.stringify(settings));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,7 +51,7 @@ angular.module('eventStreamService', [])
|
||||||
resume: function() {
|
resume: function() {
|
||||||
console.log("[EventStream] resume "+JSON.stringify(settings));
|
console.log("[EventStream] resume "+JSON.stringify(settings));
|
||||||
// run the stream from the latest token
|
// 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
|
// 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
|
// stop the stream and wipe the position in the stream. Typically used
|
||||||
// when logging out.
|
// when logging out / logged out.
|
||||||
stop: function() {
|
stop: function() {
|
||||||
console.log("[EventStream] stop "+JSON.stringify(settings));
|
console.log("[EventStream] stop "+JSON.stringify(settings));
|
||||||
// kill any running stream
|
// kill any running stream
|
||||||
interrupt(false);
|
interrupt(false);
|
||||||
// clear the latest token
|
// clear the latest token
|
||||||
settings.from = "END";
|
settings.from = END;
|
||||||
saveStreamSettings();
|
saveStreamSettings();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<script src="rooms/rooms-controller.js"></script>
|
<script src="rooms/rooms-controller.js"></script>
|
||||||
<script src="components/matrix/matrix-service.js"></script>
|
<script src="components/matrix/matrix-service.js"></script>
|
||||||
<script src="components/matrix/event-stream-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/fileInput/file-input-directive.js"></script>
|
||||||
<script src="components/fileUpload/file-upload-service.js"></script>
|
<script src="components/fileUpload/file-upload-service.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -15,8 +15,8 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
angular.module('RoomController', [])
|
angular.module('RoomController', [])
|
||||||
.controller('RoomController', ['$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) {
|
function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService, eventHandlerService) {
|
||||||
'use strict';
|
'use strict';
|
||||||
var MESSAGES_PER_PAGINATION = 10;
|
var MESSAGES_PER_PAGINATION = 10;
|
||||||
$scope.room_id = $routeParams.room_id;
|
$scope.room_id = $routeParams.room_id;
|
||||||
|
@ -42,34 +42,28 @@ angular.module('RoomController', [])
|
||||||
},0);
|
},0);
|
||||||
};
|
};
|
||||||
|
|
||||||
var parseChunk = function(chunks, appendToStart) {
|
$scope.$on(eventHandlerService.MSG_EVENT, function(ngEvent, event, isLive) {
|
||||||
for (var i = 0; i < chunks.length; i++) {
|
if (isLive) {
|
||||||
var chunk = chunks[i];
|
$scope.messages.push(event);
|
||||||
if (chunk.room_id == $scope.room_id && chunk.type == "m.room.message") {
|
scrollToBottom();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
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) {
|
var paginate = function(numItems) {
|
||||||
matrixService.paginateBackMessages($scope.room_id, $scope.state.earliest_token, numItems).then(
|
matrixService.paginateBackMessages($scope.room_id, $scope.state.earliest_token, numItems).then(
|
||||||
function(response) {
|
function(response) {
|
||||||
parseChunk(response.data.chunk, true);
|
eventHandlerService.handleEvents(response.data.chunk, false);
|
||||||
$scope.state.earliest_token = response.data.end;
|
$scope.state.earliest_token = response.data.end;
|
||||||
if (response.data.chunk.length < MESSAGES_PER_PAGINATION) {
|
if (response.data.chunk.length < MESSAGES_PER_PAGINATION) {
|
||||||
// no more messages to paginate :(
|
// no more messages to paginate :(
|
||||||
|
@ -90,7 +84,7 @@ angular.module('RoomController', [])
|
||||||
$scope.state.events_from = response.data.end;
|
$scope.state.events_from = response.data.end;
|
||||||
$scope.feedback = "";
|
$scope.feedback = "";
|
||||||
|
|
||||||
parseChunk(response.data.chunk, false);
|
eventHandlerService.handleEvents(response.data.chunk, true);
|
||||||
|
|
||||||
if ($scope.stopPoll) {
|
if ($scope.stopPoll) {
|
||||||
console.log("Stopping polling.");
|
console.log("Stopping polling.");
|
||||||
|
|
Loading…
Reference in New Issue