Merge branch 'master' of github.com:matrix-org/synapse into sql_refactor
Conflicts: synapse/storage/roommember.pypaul/schema_breaking_changes
commit
a17b371384
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
## CAUTION:
|
||||||
|
## This script will remove (hopefully) all trace of the given room ID from
|
||||||
|
## your homeserver.db
|
||||||
|
|
||||||
|
## Do not run it lightly.
|
||||||
|
|
||||||
|
ROOMID="$1"
|
||||||
|
|
||||||
|
sqlite3 homeserver.db <<EOF
|
||||||
|
DELETE FROM context_depth WHERE context = '$ROOMID';
|
||||||
|
DELETE FROM current_state WHERE context = '$ROOMID';
|
||||||
|
DELETE FROM feedback WHERE room_id = '$ROOMID';
|
||||||
|
DELETE FROM messages WHERE room_id = '$ROOMID';
|
||||||
|
DELETE FROM pdu_backward_extremities WHERE context = '$ROOMID';
|
||||||
|
DELETE FROM pdu_edges WHERE context = '$ROOMID';
|
||||||
|
DELETE FROM pdu_forward_extremities WHERE context = '$ROOMID';
|
||||||
|
DELETE FROM pdus WHERE context = '$ROOMID';
|
||||||
|
DELETE FROM room_data WHERE room_id = '$ROOMID';
|
||||||
|
DELETE FROM room_memberships WHERE room_id = '$ROOMID';
|
||||||
|
DELETE FROM rooms WHERE room_id = '$ROOMID';
|
||||||
|
DELETE FROM state_pdus WHERE context = '$ROOMID';
|
||||||
|
EOF
|
|
@ -21,8 +21,8 @@ limitations under the License.
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('MatrixWebClientController', ['matrixService'])
|
angular.module('MatrixWebClientController', ['matrixService'])
|
||||||
.controller('MatrixWebClientController', ['$scope', '$location', '$rootScope', 'matrixService',
|
.controller('MatrixWebClientController', ['$scope', '$location', '$rootScope', 'matrixService', 'eventStreamService',
|
||||||
function($scope, $location, $rootScope, matrixService) {
|
function($scope, $location, $rootScope, matrixService, eventStreamService) {
|
||||||
|
|
||||||
// Check current URL to avoid to display the logout button on the login page
|
// Check current URL to avoid to display the logout button on the login page
|
||||||
$scope.location = $location.path();
|
$scope.location = $location.path();
|
||||||
|
@ -46,9 +46,15 @@ angular.module('MatrixWebClientController', ['matrixService'])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (matrixService.config()) {
|
||||||
|
eventStreamService.resume();
|
||||||
|
}
|
||||||
|
|
||||||
// Logs the user out
|
// Logs the user out
|
||||||
$scope.logout = function() {
|
$scope.logout = function() {
|
||||||
|
// kill the event stream
|
||||||
|
eventStreamService.stop();
|
||||||
|
|
||||||
// Clean permanent data
|
// Clean permanent data
|
||||||
matrixService.setConfig({});
|
matrixService.setConfig({});
|
||||||
matrixService.saveConfig();
|
matrixService.saveConfig();
|
||||||
|
@ -57,7 +63,7 @@ angular.module('MatrixWebClientController', ['matrixService'])
|
||||||
$location.path("login");
|
$location.path("login");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Listen to the event indicating that the access token is no more valid.
|
// Listen to the event indicating that the access token is no longer valid.
|
||||||
// In this case, the user needs to log in again.
|
// In this case, the user needs to log in again.
|
||||||
$scope.$on("M_UNKNOWN_TOKEN", function() {
|
$scope.$on("M_UNKNOWN_TOKEN", function() {
|
||||||
console.log("Invalid access token -> log user out");
|
console.log("Invalid access token -> log user out");
|
||||||
|
|
|
@ -20,7 +20,9 @@ var matrixWebClient = angular.module('matrixWebClient', [
|
||||||
'LoginController',
|
'LoginController',
|
||||||
'RoomController',
|
'RoomController',
|
||||||
'RoomsController',
|
'RoomsController',
|
||||||
'matrixService'
|
'matrixService',
|
||||||
|
'eventStreamService',
|
||||||
|
'eventHandlerService'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',
|
matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',
|
||||||
|
@ -59,12 +61,16 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',
|
||||||
$httpProvider.interceptors.push('AccessTokenInterceptor');
|
$httpProvider.interceptors.push('AccessTokenInterceptor');
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
matrixWebClient.run(['$location', 'matrixService' , function($location, matrixService) {
|
matrixWebClient.run(['$location', 'matrixService', 'eventStreamService', function($location, matrixService, eventStreamService) {
|
||||||
// If we have no persistent login information, go to the login page
|
// If we have no persistent login information, go to the login page
|
||||||
var config = matrixService.config();
|
var config = matrixService.config();
|
||||||
if (!config || !config.access_token) {
|
if (!config || !config.access_token) {
|
||||||
|
eventStreamService.stop();
|
||||||
$location.path("login");
|
$location.path("login");
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
eventStreamService.resume();
|
||||||
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
matrixWebClient
|
matrixWebClient
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
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";
|
||||||
|
|
||||||
|
$rootScope.events = {
|
||||||
|
rooms: {}, // will contain roomId: { messages:[], members:[] }
|
||||||
|
};
|
||||||
|
|
||||||
|
var initRoom = function(room_id) {
|
||||||
|
console.log("Creating new handler entry for " + room_id);
|
||||||
|
$rootScope.events.rooms[room_id] = {};
|
||||||
|
$rootScope.events.rooms[room_id].messages = [];
|
||||||
|
$rootScope.events.rooms[room_id].members = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var handleMessage = function(event, isLiveEvent) {
|
||||||
|
if ("membership_target" in event.content) {
|
||||||
|
event.user_id = event.content.membership_target;
|
||||||
|
}
|
||||||
|
if (!(event.room_id in $rootScope.events.rooms)) {
|
||||||
|
initRoom(event.room_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLiveEvent) {
|
||||||
|
$rootScope.events.rooms[event.room_id].messages.push(event);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$rootScope.events.rooms[event.room_id].messages.unshift(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO send delivery receipt if isLiveEvent
|
||||||
|
|
||||||
|
// $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.
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
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 manages where in the event stream the web client currently is,
|
||||||
|
repolling the event stream, and provides methods to resume/pause/stop the event
|
||||||
|
stream. This service is not responsible for parsing event data. For that, see
|
||||||
|
the eventHandlerService.
|
||||||
|
*/
|
||||||
|
angular.module('eventStreamService', [])
|
||||||
|
.factory('eventStreamService', ['$q', '$timeout', 'matrixService', 'eventHandlerService', function($q, $timeout, matrixService, eventHandlerService) {
|
||||||
|
var END = "END";
|
||||||
|
var START = "START";
|
||||||
|
var TIMEOUT_MS = 5000;
|
||||||
|
var ERR_TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
|
var settings = {
|
||||||
|
from: "END",
|
||||||
|
to: undefined,
|
||||||
|
limit: undefined,
|
||||||
|
shouldPoll: true,
|
||||||
|
isActive: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// interrupts the stream. Only valid if there is a stream conneciton
|
||||||
|
// open.
|
||||||
|
var interrupt = function(shouldPoll) {
|
||||||
|
console.log("[EventStream] interrupt("+shouldPoll+") "+
|
||||||
|
JSON.stringify(settings));
|
||||||
|
settings.shouldPoll = shouldPoll;
|
||||||
|
settings.isActive = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var saveStreamSettings = function() {
|
||||||
|
localStorage.setItem("streamSettings", JSON.stringify(settings));
|
||||||
|
};
|
||||||
|
|
||||||
|
var startEventStream = function() {
|
||||||
|
settings.shouldPoll = true;
|
||||||
|
settings.isActive = true;
|
||||||
|
var deferred = $q.defer();
|
||||||
|
// run the stream from the latest token
|
||||||
|
matrixService.getEventStream(settings.from, TIMEOUT_MS).then(
|
||||||
|
function(response) {
|
||||||
|
if (!settings.isActive) {
|
||||||
|
console.log("[EventStream] Got response but now inactive. Dropping data.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.from = response.data.end;
|
||||||
|
|
||||||
|
console.log("[EventStream] Got response from "+settings.from+" to "+response.data.end);
|
||||||
|
eventHandlerService.handleEvents(response.data.chunk, true);
|
||||||
|
|
||||||
|
deferred.resolve(response);
|
||||||
|
|
||||||
|
if (settings.shouldPoll) {
|
||||||
|
$timeout(startEventStream, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("[EventStream] Stopping poll.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(error) {
|
||||||
|
if (error.status == 403) {
|
||||||
|
settings.shouldPoll = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
deferred.reject(error);
|
||||||
|
|
||||||
|
if (settings.shouldPoll) {
|
||||||
|
$timeout(startEventStream, ERR_TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("[EventStream] Stopping polling.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
// resume the stream from whereever it last got up to. Typically used
|
||||||
|
// when the page is opened.
|
||||||
|
resume: function() {
|
||||||
|
if (settings.isActive) {
|
||||||
|
console.log("[EventStream] Already active, ignoring resume()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("[EventStream] resume "+JSON.stringify(settings));
|
||||||
|
return startEventStream();
|
||||||
|
},
|
||||||
|
|
||||||
|
// pause the stream. Resuming it will continue from the current position
|
||||||
|
pause: function() {
|
||||||
|
console.log("[EventStream] pause "+JSON.stringify(settings));
|
||||||
|
// kill any running stream
|
||||||
|
interrupt(false);
|
||||||
|
// save the latest token
|
||||||
|
saveStreamSettings();
|
||||||
|
},
|
||||||
|
|
||||||
|
// stop the stream and wipe the position in the stream. Typically used
|
||||||
|
// 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;
|
||||||
|
saveStreamSettings();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}]);
|
|
@ -16,6 +16,12 @@ limitations under the License.
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
/*
|
||||||
|
This service wraps up Matrix API calls.
|
||||||
|
|
||||||
|
This serves to isolate the caller from changes to the underlying url paths, as
|
||||||
|
well as attach common params (e.g. access_token) to requests.
|
||||||
|
*/
|
||||||
angular.module('matrixService', [])
|
angular.module('matrixService', [])
|
||||||
.factory('matrixService', ['$http', '$q', '$rootScope', function($http, $q, $rootScope) {
|
.factory('matrixService', ['$http', '$q', '$rootScope', function($http, $q, $rootScope) {
|
||||||
|
|
||||||
|
@ -36,10 +42,16 @@ angular.module('matrixService', [])
|
||||||
var MAPPING_PREFIX = "alias_for_";
|
var MAPPING_PREFIX = "alias_for_";
|
||||||
|
|
||||||
var doRequest = function(method, path, params, data) {
|
var doRequest = function(method, path, params, data) {
|
||||||
|
if (!config) {
|
||||||
|
console.warn("No config exists. Cannot perform request to "+path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Inject the access token
|
// Inject the access token
|
||||||
if (!params) {
|
if (!params) {
|
||||||
params = {};
|
params = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
params.access_token = config.access_token;
|
params.access_token = config.access_token;
|
||||||
|
|
||||||
return doBaseRequest(config.homeserver, method, path, params, data, undefined);
|
return doBaseRequest(config.homeserver, method, path, params, data, undefined);
|
||||||
|
@ -297,6 +309,15 @@ angular.module('matrixService', [])
|
||||||
return doBaseRequest(config.identityServer, "POST", path, {}, data, headers);
|
return doBaseRequest(config.identityServer, "POST", path, {}, data, headers);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// start listening on /events
|
||||||
|
getEventStream: function(from, timeout) {
|
||||||
|
var path = "/events";
|
||||||
|
var params = {
|
||||||
|
from: from,
|
||||||
|
timeout: timeout
|
||||||
|
};
|
||||||
|
return doRequest("GET", path, params);
|
||||||
|
},
|
||||||
|
|
||||||
//
|
//
|
||||||
testLogin: function() {
|
testLogin: function() {
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
<script src="room/room-controller.js"></script>
|
<script src="room/room-controller.js"></script>
|
||||||
<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-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>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
angular.module('LoginController', ['matrixService'])
|
angular.module('LoginController', ['matrixService'])
|
||||||
.controller('LoginController', ['$scope', '$location', 'matrixService',
|
.controller('LoginController', ['$scope', '$location', 'matrixService', 'eventStreamService',
|
||||||
function($scope, $location, matrixService) {
|
function($scope, $location, matrixService, eventStreamService) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ angular.module('LoginController', ['matrixService'])
|
||||||
|
|
||||||
// And permanently save it
|
// And permanently save it
|
||||||
matrixService.saveConfig();
|
matrixService.saveConfig();
|
||||||
|
eventStreamService.resume();
|
||||||
// Go to the user's rooms list page
|
// Go to the user's rooms list page
|
||||||
$location.path("rooms");
|
$location.path("rooms");
|
||||||
},
|
},
|
||||||
|
@ -83,6 +83,7 @@ angular.module('LoginController', ['matrixService'])
|
||||||
access_token: response.data.access_token
|
access_token: response.data.access_token
|
||||||
});
|
});
|
||||||
matrixService.saveConfig();
|
matrixService.saveConfig();
|
||||||
|
eventStreamService.resume();
|
||||||
$location.path("rooms");
|
$location.path("rooms");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -15,8 +15,8 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
angular.module('RoomController', [])
|
angular.module('RoomController', [])
|
||||||
.controller('RoomController', ['$scope', '$http', '$timeout', '$routeParams', '$location', 'matrixService',
|
.controller('RoomController', ['$scope', '$http', '$timeout', '$routeParams', '$location', 'matrixService', 'eventStreamService', 'eventHandlerService',
|
||||||
function($scope, $http, $timeout, $routeParams, $location, matrixService) {
|
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;
|
||||||
|
@ -28,9 +28,7 @@ angular.module('RoomController', [])
|
||||||
can_paginate: true, // this is toggled off when we run out of items
|
can_paginate: true, // this is toggled off when we run out of items
|
||||||
stream_failure: undefined // the response when the stream fails
|
stream_failure: undefined // the response when the stream fails
|
||||||
};
|
};
|
||||||
$scope.messages = [];
|
|
||||||
$scope.members = {};
|
$scope.members = {};
|
||||||
$scope.stopPoll = false;
|
|
||||||
|
|
||||||
$scope.imageURLToSend = "";
|
$scope.imageURLToSend = "";
|
||||||
$scope.userIDToInvite = "";
|
$scope.userIDToInvite = "";
|
||||||
|
@ -42,34 +40,24 @@ 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 && event.room_id === $scope.room_id) {
|
||||||
var chunk = chunks[i];
|
scrollToBottom();
|
||||||
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.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 :(
|
||||||
|
@ -82,43 +70,6 @@ angular.module('RoomController', [])
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
var shortPoll = function() {
|
|
||||||
$http.get(matrixService.config().homeserver + matrixService.prefix + "/events", {
|
|
||||||
"params": {
|
|
||||||
"access_token": matrixService.config().access_token,
|
|
||||||
"from": $scope.state.events_from,
|
|
||||||
"timeout": 5000
|
|
||||||
}})
|
|
||||||
.then(function(response) {
|
|
||||||
$scope.state.stream_failure = undefined;
|
|
||||||
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);
|
|
||||||
|
|
||||||
if ($scope.stopPoll) {
|
|
||||||
console.log("Stopping polling.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$timeout(shortPoll, 0);
|
|
||||||
}
|
|
||||||
}, function(response) {
|
|
||||||
$scope.state.stream_failure = response;
|
|
||||||
|
|
||||||
if (response.status == 403) {
|
|
||||||
$scope.stopPoll = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($scope.stopPoll) {
|
|
||||||
console.log("Stopping polling.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$timeout(shortPoll, 5000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var updateMemberList = function(chunk) {
|
var updateMemberList = function(chunk) {
|
||||||
var isNewMember = !(chunk.target_user_id in $scope.members);
|
var isNewMember = !(chunk.target_user_id in $scope.members);
|
||||||
if (isNewMember) {
|
if (isNewMember) {
|
||||||
|
@ -133,7 +84,6 @@ angular.module('RoomController', [])
|
||||||
function(response) {
|
function(response) {
|
||||||
var member = $scope.members[chunk.target_user_id];
|
var member = $scope.members[chunk.target_user_id];
|
||||||
if (member !== undefined) {
|
if (member !== undefined) {
|
||||||
console.log("Updated displayname "+chunk.target_user_id+" to " + response.data.displayname);
|
|
||||||
member.displayname = response.data.displayname;
|
member.displayname = response.data.displayname;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +92,6 @@ angular.module('RoomController', [])
|
||||||
function(response) {
|
function(response) {
|
||||||
var member = $scope.members[chunk.target_user_id];
|
var member = $scope.members[chunk.target_user_id];
|
||||||
if (member !== undefined) {
|
if (member !== undefined) {
|
||||||
console.log("Updated image for "+chunk.target_user_id+" to " + response.data.avatar_url);
|
|
||||||
member.avatar_url = response.data.avatar_url;
|
member.avatar_url = response.data.avatar_url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,8 +167,6 @@ angular.module('RoomController', [])
|
||||||
matrixService.join($scope.room_id).then(
|
matrixService.join($scope.room_id).then(
|
||||||
function() {
|
function() {
|
||||||
console.log("Joined room "+$scope.room_id);
|
console.log("Joined room "+$scope.room_id);
|
||||||
// Now start reading from the stream
|
|
||||||
$timeout(shortPoll, 0);
|
|
||||||
|
|
||||||
// Get the current member list
|
// Get the current member list
|
||||||
matrixService.getMemberList($scope.room_id).then(
|
matrixService.getMemberList($scope.room_id).then(
|
||||||
|
@ -278,9 +225,4 @@ angular.module('RoomController', [])
|
||||||
$scope.loadMoreHistory = function() {
|
$scope.loadMoreHistory = function() {
|
||||||
paginate(MESSAGES_PER_PAGINATION);
|
paginate(MESSAGES_PER_PAGINATION);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.$on('$destroy', function(e) {
|
|
||||||
console.log("onDestroyed: Stopping poll.");
|
|
||||||
$scope.stopPoll = true;
|
|
||||||
});
|
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -22,14 +22,14 @@
|
||||||
|
|
||||||
<div class="messageTableWrapper">
|
<div class="messageTableWrapper">
|
||||||
<table class="messageTable">
|
<table class="messageTable">
|
||||||
<tr ng-repeat="msg in messages" ng-class="msg.user_id === state.user_id ? 'mine' : ''">
|
<tr ng-repeat="msg in events.rooms[room_id].messages" ng-class="msg.user_id === state.user_id ? 'mine' : ''">
|
||||||
<td class="leftBlock">
|
<td class="leftBlock">
|
||||||
<div class="sender" ng-hide="messages[$index - 1].user_id === msg.user_id">{{ members[msg.user_id].displayname || msg.user_id }}</div>
|
<div class="sender" ng-hide="events.rooms[room_id].messages[$index - 1].user_id === msg.user_id">{{ members[msg.user_id].displayname || msg.user_id }}</div>
|
||||||
<div class="timestamp">{{ msg.content.hsob_ts | date:'MMM d HH:mm:ss' }}</div>
|
<div class="timestamp">{{ msg.content.hsob_ts | date:'MMM d HH:mm:ss' }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="avatar">
|
<td class="avatar">
|
||||||
<img ng-src="{{ members[msg.user_id].avatar_url || 'img/default-profile.jpg' }}" width="32" height="32"
|
<img ng-src="{{ members[msg.user_id].avatar_url || 'img/default-profile.jpg' }}" width="32" height="32"
|
||||||
ng-hide="messages[$index - 1].user_id === msg.user_id || msg.user_id === state.user_id"/>
|
ng-hide="events.rooms[room_id].messages[$index - 1].user_id === msg.user_id || msg.user_id === state.user_id"/>
|
||||||
</td>
|
</td>
|
||||||
<td ng-class="!msg.content.membership_target ? (msg.content.msgtype === 'm.emote' ? 'emote text' : 'text') : ''">
|
<td ng-class="!msg.content.membership_target ? (msg.content.msgtype === 'm.emote' ? 'emote text' : 'text') : ''">
|
||||||
<div class="bubble">
|
<div class="bubble">
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="rightBlock">
|
<td class="rightBlock">
|
||||||
<img ng-src="{{ members[msg.user_id].avatar_url || 'img/default-profile.jpg' }}" width="32" height="32"
|
<img ng-src="{{ members[msg.user_id].avatar_url || 'img/default-profile.jpg' }}" width="32" height="32"
|
||||||
ng-hide="messages[$index - 1].user_id === msg.user_id || msg.user_id !== state.user_id"/>
|
ng-hide="events.rooms[room_id].messages[$index - 1].user_id === msg.user_id || msg.user_id !== state.user_id"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
Loading…
Reference in New Issue