diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js
index 98003e97bf..e990d42d05 100644
--- a/webclient/components/matrix/event-handler-service.js
+++ b/webclient/components/matrix/event-handler-service.js
@@ -101,7 +101,7 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
var initRoom = function(room_id, room) {
if (!(room_id in $rootScope.events.rooms)) {
- console.log("Creating new handler entry for " + room_id);
+ console.log("Creating new rooms entry for " + room_id);
$rootScope.events.rooms[room_id] = {
room_id: room_id,
messages: [],
@@ -113,10 +113,12 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
};
}
- if (room) {
+ if (room) { // we got an existing room object from initialsync, seemingly.
// Report all other metadata of the room object (membership, inviter, visibility, ...)
for (var field in room) {
- if (-1 === ["room_id", "messages", "state"].indexOf(field)) {
+ if (!room.hasOwnProperty(field)) continue;
+
+ if (-1 === ["room_id", "messages", "state"].indexOf(field)) { // why indexOf - why not ===? --Matthew
$rootScope.events.rooms[room_id][field] = room[field];
}
}
@@ -211,11 +213,8 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
if (shouldBing && isIdle) {
console.log("Displaying notification for "+JSON.stringify(event));
- var member = $rootScope.events.rooms[event.room_id].members[event.user_id];
- var displayname = undefined;
- if (member) {
- displayname = member.displayname;
- }
+ var member = getMember(event.room_id, event.user_id);
+ var displayname = getUserDisplayName(event.room_id, event.user_id);
var message = event.content.body;
if (event.content.msgtype === "m.emote") {
@@ -223,7 +222,7 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
}
var notification = new window.Notification(
- (displayname || event.user_id) +
+ displayname +
" (" + (matrixService.getRoomIdToAliasMapping(event.room_id) || event.room_id) + ")", // FIXME: don't leak room_ids here
{
"body": message,
@@ -253,12 +252,29 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
// 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);
+ if (!isStateEvent) {
+ // could be a membership change, display name change, etc.
+ // Find out which one.
+ var memberChanges = undefined;
+ if (event.content.prev !== event.content.membership) {
+ memberChanges = "membership";
}
- else {
- $rootScope.events.rooms[event.room_id].messages.unshift(event);
+ else if (event.prev_content && (event.prev_content.displayname !== event.content.displayname)) {
+ memberChanges = "displayname";
+ }
+
+ // mark the key which changed
+ event.changedKey = memberChanges;
+
+ // If there was a change we want to display, dump it in the message
+ // list.
+ if (memberChanges) {
+ if (isLiveEvent) {
+ $rootScope.events.rooms[event.room_id].messages.push(event);
+ }
+ else {
+ $rootScope.events.rooms[event.room_id].messages.unshift(event);
+ }
}
}
@@ -328,6 +344,65 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
return index;
};
+ /**
+ * Get the member object of a room member
+ * @param {String} room_id the room id
+ * @param {String} user_id the id of the user
+ * @returns {undefined | Object} the member object of this user in this room if he is part of the room
+ */
+ var getMember = function(room_id, user_id) {
+ var member;
+
+ var room = $rootScope.events.rooms[room_id];
+ if (room) {
+ member = room.members[user_id];
+ }
+ return member;
+ };
+
+ /**
+ * Return the display name of an user acccording to data already downloaded
+ * @param {String} room_id the room id
+ * @param {String} user_id the id of the user
+ * @returns {String} the user displayname or user_id if not available
+ */
+ var getUserDisplayName = function(room_id, user_id) {
+ var displayName;
+
+ // Get the user display name from the member list of the room
+ var member = getMember(room_id, user_id);
+ if (member && member.content.displayname) { // Do not consider null displayname
+ displayName = member.content.displayname;
+
+ // Disambiguate users who have the same displayname in the room
+ if (user_id !== matrixService.config().user_id) {
+ var room = $rootScope.events.rooms[room_id];
+
+ for (var member_id in room.members) {
+ if (room.members.hasOwnProperty(member_id) && member_id !== user_id) {
+ var member2 = room.members[member_id];
+ if (member2.content.displayname && member2.content.displayname === displayName) {
+ displayName = displayName + " (" + user_id + ")";
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // The user may not have joined the room yet. So try to resolve display name from presence data
+ // Note: This data may not be available
+ if (undefined === displayName && user_id in $rootScope.presence) {
+ displayName = $rootScope.presence[user_id].content.displayname;
+ }
+
+ if (undefined === displayName) {
+ // By default, use the user ID
+ displayName = user_id;
+ }
+ return displayName;
+ };
+
return {
ROOM_CREATE_EVENT: ROOM_CREATE_EVENT,
MSG_EVENT: MSG_EVENT,
@@ -499,6 +574,8 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
memberCount = 0;
for (var i in room.members) {
+ if (!room.members.hasOwnProperty(i)) continue;
+
var member = room.members[i];
if ("join" === member.membership) {
@@ -517,15 +594,19 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
* @returns {undefined | Object} the member object of this user in this room if he is part of the room
*/
getMember: function(room_id, user_id) {
- var member;
-
- var room = $rootScope.events.rooms[room_id];
- if (room) {
- member = room.members[user_id];
- }
- return member;
+ return getMember(room_id, user_id);
},
+ /**
+ * Return the display name of an user acccording to data already downloaded
+ * @param {String} room_id the room id
+ * @param {String} user_id the id of the user
+ * @returns {String} the user displayname or user_id if not available
+ */
+ getUserDisplayName: function(room_id, user_id) {
+ return getUserDisplayName(room_id, user_id);
+ },
+
setRoomVisibility: function(room_id, visible) {
if (!visible) {
return;
diff --git a/webclient/components/matrix/matrix-call.js b/webclient/components/matrix/matrix-call.js
index 7b5d9cffef..3e8811e5fc 100644
--- a/webclient/components/matrix/matrix-call.js
+++ b/webclient/components/matrix/matrix-call.js
@@ -66,15 +66,67 @@ angular.module('MatrixCall', [])
}
+ MatrixCall.getTurnServer = function() {
+ matrixService.getTurnServer().then(function(response) {
+ if (response.data.uris) {
+ console.log("Got TURN URIs: "+response.data.uris);
+ MatrixCall.turnServer = response.data;
+ $rootScope.haveTurn = true;
+ // re-fetch when we're about to reach the TTL
+ $timeout(MatrixCall.getTurnServer, MatrixCall.turnServer.ttl * 1000 * 0.9);
+ } else {
+ console.log("Got no TURN URIs from HS");
+ $rootScope.haveTurn = false;
+ }
+ }, function(error) {
+ console.log("Failed to get TURN URIs");
+ MatrixCall.turnServer = {};
+ $timeout(MatrixCall.getTurnServer, 60000);
+ });
+ }
+
+ // FIXME: we should prevent any class from being placed or accepted before this has finished
+ MatrixCall.getTurnServer();
+
MatrixCall.CALL_TIMEOUT = 60000;
+ MatrixCall.FALLBACK_STUN_SERVER = 'stun:stun.l.google.com:19302';
MatrixCall.prototype.createPeerConnection = function() {
- var stunServer = 'stun:stun.l.google.com:19302';
var pc;
if (window.mozRTCPeerConnection) {
- pc = new window.mozRTCPeerConnection({'url': stunServer});
+ var iceServers = [];
+ if (MatrixCall.turnServer) {
+ if (MatrixCall.turnServer.uris) {
+ for (var i = 0; i < MatrixCall.turnServer.uris.length; i++) {
+ iceServers.push({
+ 'url': MatrixCall.turnServer.uris[i],
+ 'username': MatrixCall.turnServer.username,
+ 'credential': MatrixCall.turnServer.password,
+ });
+ }
+ } else {
+ console.log("No TURN server: using fallback STUN server");
+ iceServers.push({ 'url' : MatrixCall.FALLBACK_STUN_SERVER });
+ }
+ }
+
+ pc = new window.mozRTCPeerConnection({"iceServers":iceServers});
} else {
- pc = new window.RTCPeerConnection({"iceServers":[{"urls":"stun:stun.l.google.com:19302"}]});
+ var iceServers = [];
+ if (MatrixCall.turnServer) {
+ if (MatrixCall.turnServer.uris) {
+ iceServers.push({
+ 'urls': MatrixCall.turnServer.uris,
+ 'username': MatrixCall.turnServer.username,
+ 'credential': MatrixCall.turnServer.password,
+ });
+ } else {
+ console.log("No TURN server: using fallback STUN server");
+ iceServers.push({ 'urls' : MatrixCall.FALLBACK_STUN_SERVER });
+ }
+ }
+
+ pc = new window.RTCPeerConnection({"iceServers":iceServers});
}
var self = this;
pc.oniceconnectionstatechange = function() { self.onIceConnectionStateChanged(); };
diff --git a/webclient/components/matrix/matrix-filter.js b/webclient/components/matrix/matrix-filter.js
index 328e3a7086..e6f2acc5fd 100644
--- a/webclient/components/matrix/matrix-filter.js
+++ b/webclient/components/matrix/matrix-filter.js
@@ -19,7 +19,7 @@
angular.module('matrixFilter', [])
// Compute the room name according to information we have
-.filter('mRoomName', ['$rootScope', 'matrixService', function($rootScope, matrixService) {
+.filter('mRoomName', ['$rootScope', 'matrixService', 'eventHandlerService', function($rootScope, matrixService, eventHandlerService) {
return function(room_id) {
var roomName;
@@ -31,49 +31,57 @@ angular.module('matrixFilter', [])
if (room) {
// Get name from room state date
var room_name_event = room["m.room.name"];
+
+ // Determine if it is a public room
+ var isPublicRoom = false;
+ if (room["m.room.join_rules"] && room["m.room.join_rules"].content) {
+ isPublicRoom = ("public" === room["m.room.join_rules"].content.join_rule);
+ }
+
if (room_name_event) {
roomName = room_name_event.content.name;
}
else if (alias) {
roomName = alias;
}
- else if (room.members) {
-
+ else if (room.members && !isPublicRoom) { // Do not rename public room
+
var user_id = matrixService.config().user_id;
// Else, build the name from its users
// Limit the room renaming to 1:1 room
if (2 === Object.keys(room.members).length) {
for (var i in room.members) {
+ if (!room.members.hasOwnProperty(i)) continue;
+
var member = room.members[i];
if (member.state_key !== user_id) {
-
- if (member.state_key in $rootScope.presence) {
- // If the user is available in presence, use the displayname there
- // as it is the most uptodate
- roomName = $rootScope.presence[member.state_key].content.displayname;
- }
- else if (member.content.displayname) {
- roomName = member.content.displayname;
- }
- else {
- roomName = member.state_key;
- }
+ roomName = eventHandlerService.getUserDisplayName(room_id, member.state_key);
+ break;
}
}
}
- else if (1 === Object.keys(room.members).length) {
+ else if (Object.keys(room.members).length <= 1) {
+
var otherUserId;
- if (Object.keys(room.members)[0] !== user_id) {
+ if (Object.keys(room.members)[0] && Object.keys(room.members)[0] !== user_id) {
otherUserId = Object.keys(room.members)[0];
}
else {
+ // it's got to be an invite, or failing that a self-chat;
+ otherUserId = room.inviter || user_id;
+/*
+ // XXX: This should all be unnecessary now thanks to using the /rooms/<room>/roomid API
+
// The other member may be in the invite list, get all invited users
var invitedUserIDs = [];
+
+ // XXX: *SURELY* we shouldn't have to trawl through the whole messages list to
+ // find invite - surely the other user should be in room.members with state invited? :/ --Matthew
for (var i in room.messages) {
var message = room.messages[i];
- if ("m.room.member" === message.type && "invite" === message.membership) {
+ if ("m.room.member" === message.type && "invite" === message.content.membership) {
// Filter out the current user
var member_id = message.state_key;
if (member_id === user_id) {
@@ -92,15 +100,11 @@ angular.module('matrixFilter', [])
if (1 === invitedUserIDs.length) {
otherUserId = invitedUserIDs[0];
}
+*/
}
-
- // Try to resolve his displayname in presence global data
- if (otherUserId in $rootScope.presence) {
- roomName = $rootScope.presence[otherUserId].content.displayname;
- }
- else {
- roomName = otherUserId;
- }
+
+ // Get the user display name
+ roomName = eventHandlerService.getUserDisplayName(room_id, otherUserId);
}
}
}
@@ -127,37 +131,9 @@ angular.module('matrixFilter', [])
};
}])
-// Compute the user display name in a room according to the data already downloaded
-.filter('mUserDisplayName', ['$rootScope', function($rootScope) {
+// Return the user display name
+.filter('mUserDisplayName', ['eventHandlerService', function(eventHandlerService) {
return function(user_id, room_id) {
- var displayName;
-
- // Try to find the user name among presence data
- // Warning: that means we have received before a presence event for this
- // user which cannot be guaranted.
- // However, if we get the info by this way, we are sure this is the latest user display name
- // See FIXME comment below
- if (user_id in $rootScope.presence) {
- displayName = $rootScope.presence[user_id].content.displayname;
- }
-
- // FIXME: Would like to use the display name as defined in room members of the room.
- // But this information is the display name of the user when he has joined the room.
- // It does not take into account user display name update
- if (room_id) {
- var room = $rootScope.events.rooms[room_id];
- if (room && (user_id in room.members)) {
- var member = room.members[user_id];
- if (member.content.displayname) {
- displayName = member.content.displayname;
- }
- }
- }
-
- if (undefined === displayName) {
- // By default, use the user ID
- displayName = user_id;
- }
- return displayName;
+ return eventHandlerService.getUserDisplayName(room_id, user_id);
};
}]);
diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js
index 069e02e939..a4f0568bce 100644
--- a/webclient/components/matrix/matrix-service.js
+++ b/webclient/components/matrix/matrix-service.js
@@ -264,7 +264,13 @@ angular.module('matrixService', [])
return doRequest("GET", path, params);
},
-
+
+ // get room state for a specific room
+ roomState: function(room_id) {
+ var path = "/rooms/" + room_id + "/state";
+ return doRequest("GET", path);
+ },
+
// Joins a room
join: function(room_id) {
return this.membershipChange(room_id, undefined, "join");
@@ -697,11 +703,10 @@ angular.module('matrixService', [])
createRoomIdToAliasMapping: function(roomId, alias) {
roomIdToAlias[roomId] = alias;
aliasToRoomId[alias] = roomId;
- // localStorage.setItem(MAPPING_PREFIX+roomId, alias);
},
getRoomIdToAliasMapping: function(roomId) {
- var alias = roomIdToAlias[roomId]; // was localStorage.getItem(MAPPING_PREFIX+roomId)
+ var alias = roomIdToAlias[roomId];
//console.log("looking for alias for " + roomId + "; found: " + alias);
return alias;
},
@@ -762,6 +767,10 @@ angular.module('matrixService', [])
var deferred = $q.defer();
deferred.reject({data:{error: "Invalid room: " + room_id}});
return deferred.promise;
+ },
+
+ getTurnServer: function() {
+ return doRequest("GET", "/voip/turnServer");
}
};
|